]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Localisation updates from https://translatewiki.net.
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2
3         var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
4
5         function createCommonjsModule(fn, basedir, module) {
6                 return module = {
7                         path: basedir,
8                         exports: {},
9                         require: function (path, base) {
10                                 return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
11                         }
12                 }, fn(module, module.exports), module.exports;
13         }
14
15         function commonjsRequire () {
16                 throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
17         }
18
19         var check = function (it) {
20           return it && it.Math == Math && it;
21         };
22
23         // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
24         var global_1 =
25           /* global globalThis -- safe */
26           check(typeof globalThis == 'object' && globalThis) ||
27           check(typeof window == 'object' && window) ||
28           check(typeof self == 'object' && self) ||
29           check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
30           // eslint-disable-next-line no-new-func -- fallback
31           (function () { return this; })() || Function('return this')();
32
33         var fails = function (exec) {
34           try {
35             return !!exec();
36           } catch (error) {
37             return true;
38           }
39         };
40
41         // Detect IE8's incomplete defineProperty implementation
42         var descriptors = !fails(function () {
43           return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
44         });
45
46         var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
47         var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
48
49         // Nashorn ~ JDK8 bug
50         var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1);
51
52         // `Object.prototype.propertyIsEnumerable` method implementation
53         // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
54         var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
55           var descriptor = getOwnPropertyDescriptor(this, V);
56           return !!descriptor && descriptor.enumerable;
57         } : nativePropertyIsEnumerable;
58
59         var objectPropertyIsEnumerable = {
60                 f: f
61         };
62
63         var createPropertyDescriptor = function (bitmap, value) {
64           return {
65             enumerable: !(bitmap & 1),
66             configurable: !(bitmap & 2),
67             writable: !(bitmap & 4),
68             value: value
69           };
70         };
71
72         var toString = {}.toString;
73
74         var classofRaw = function (it) {
75           return toString.call(it).slice(8, -1);
76         };
77
78         var split = ''.split;
79
80         // fallback for non-array-like ES3 and non-enumerable old V8 strings
81         var indexedObject = fails(function () {
82           // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
83           // eslint-disable-next-line no-prototype-builtins -- safe
84           return !Object('z').propertyIsEnumerable(0);
85         }) ? function (it) {
86           return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
87         } : Object;
88
89         // `RequireObjectCoercible` abstract operation
90         // https://tc39.es/ecma262/#sec-requireobjectcoercible
91         var requireObjectCoercible = function (it) {
92           if (it == undefined) throw TypeError("Can't call method on " + it);
93           return it;
94         };
95
96         // toObject with fallback for non-array-like ES3 strings
97
98
99
100         var toIndexedObject = function (it) {
101           return indexedObject(requireObjectCoercible(it));
102         };
103
104         var isObject = function (it) {
105           return typeof it === 'object' ? it !== null : typeof it === 'function';
106         };
107
108         // `ToPrimitive` abstract operation
109         // https://tc39.es/ecma262/#sec-toprimitive
110         // instead of the ES6 spec version, we didn't implement @@toPrimitive case
111         // and the second argument - flag - preferred type is a string
112         var toPrimitive = function (input, PREFERRED_STRING) {
113           if (!isObject(input)) return input;
114           var fn, val;
115           if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
116           if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
117           if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
118           throw TypeError("Can't convert object to primitive value");
119         };
120
121         var hasOwnProperty = {}.hasOwnProperty;
122
123         var has = function (it, key) {
124           return hasOwnProperty.call(it, key);
125         };
126
127         var document$1 = global_1.document;
128         // typeof document.createElement is 'object' in old IE
129         var EXISTS = isObject(document$1) && isObject(document$1.createElement);
130
131         var documentCreateElement = function (it) {
132           return EXISTS ? document$1.createElement(it) : {};
133         };
134
135         // Thank's IE8 for his funny defineProperty
136         var ie8DomDefine = !descriptors && !fails(function () {
137           return Object.defineProperty(documentCreateElement('div'), 'a', {
138             get: function () { return 7; }
139           }).a != 7;
140         });
141
142         var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
143
144         // `Object.getOwnPropertyDescriptor` method
145         // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
146         var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
147           O = toIndexedObject(O);
148           P = toPrimitive(P, true);
149           if (ie8DomDefine) try {
150             return nativeGetOwnPropertyDescriptor(O, P);
151           } catch (error) { /* empty */ }
152           if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
153         };
154
155         var objectGetOwnPropertyDescriptor = {
156                 f: f$1
157         };
158
159         var anObject = function (it) {
160           if (!isObject(it)) {
161             throw TypeError(String(it) + ' is not an object');
162           } return it;
163         };
164
165         var nativeDefineProperty = Object.defineProperty;
166
167         // `Object.defineProperty` method
168         // https://tc39.es/ecma262/#sec-object.defineproperty
169         var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
170           anObject(O);
171           P = toPrimitive(P, true);
172           anObject(Attributes);
173           if (ie8DomDefine) try {
174             return nativeDefineProperty(O, P, Attributes);
175           } catch (error) { /* empty */ }
176           if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
177           if ('value' in Attributes) O[P] = Attributes.value;
178           return O;
179         };
180
181         var objectDefineProperty = {
182                 f: f$2
183         };
184
185         var createNonEnumerableProperty = descriptors ? function (object, key, value) {
186           return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
187         } : function (object, key, value) {
188           object[key] = value;
189           return object;
190         };
191
192         var setGlobal = function (key, value) {
193           try {
194             createNonEnumerableProperty(global_1, key, value);
195           } catch (error) {
196             global_1[key] = value;
197           } return value;
198         };
199
200         var SHARED = '__core-js_shared__';
201         var store = global_1[SHARED] || setGlobal(SHARED, {});
202
203         var sharedStore = store;
204
205         var functionToString = Function.toString;
206
207         // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper
208         if (typeof sharedStore.inspectSource != 'function') {
209           sharedStore.inspectSource = function (it) {
210             return functionToString.call(it);
211           };
212         }
213
214         var inspectSource = sharedStore.inspectSource;
215
216         var WeakMap = global_1.WeakMap;
217
218         var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap));
219
220         var isPure = false;
221
222         var shared = createCommonjsModule(function (module) {
223         (module.exports = function (key, value) {
224           return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
225         })('versions', []).push({
226           version: '3.9.1',
227           mode:  'global',
228           copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
229         });
230         });
231
232         var id = 0;
233         var postfix = Math.random();
234
235         var uid = function (key) {
236           return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
237         };
238
239         var keys = shared('keys');
240
241         var sharedKey = function (key) {
242           return keys[key] || (keys[key] = uid(key));
243         };
244
245         var hiddenKeys = {};
246
247         var WeakMap$1 = global_1.WeakMap;
248         var set, get, has$1;
249
250         var enforce = function (it) {
251           return has$1(it) ? get(it) : set(it, {});
252         };
253
254         var getterFor = function (TYPE) {
255           return function (it) {
256             var state;
257             if (!isObject(it) || (state = get(it)).type !== TYPE) {
258               throw TypeError('Incompatible receiver, ' + TYPE + ' required');
259             } return state;
260           };
261         };
262
263         if (nativeWeakMap) {
264           var store$1 = sharedStore.state || (sharedStore.state = new WeakMap$1());
265           var wmget = store$1.get;
266           var wmhas = store$1.has;
267           var wmset = store$1.set;
268           set = function (it, metadata) {
269             metadata.facade = it;
270             wmset.call(store$1, it, metadata);
271             return metadata;
272           };
273           get = function (it) {
274             return wmget.call(store$1, it) || {};
275           };
276           has$1 = function (it) {
277             return wmhas.call(store$1, it);
278           };
279         } else {
280           var STATE = sharedKey('state');
281           hiddenKeys[STATE] = true;
282           set = function (it, metadata) {
283             metadata.facade = it;
284             createNonEnumerableProperty(it, STATE, metadata);
285             return metadata;
286           };
287           get = function (it) {
288             return has(it, STATE) ? it[STATE] : {};
289           };
290           has$1 = function (it) {
291             return has(it, STATE);
292           };
293         }
294
295         var internalState = {
296           set: set,
297           get: get,
298           has: has$1,
299           enforce: enforce,
300           getterFor: getterFor
301         };
302
303         var redefine = createCommonjsModule(function (module) {
304         var getInternalState = internalState.get;
305         var enforceInternalState = internalState.enforce;
306         var TEMPLATE = String(String).split('String');
307
308         (module.exports = function (O, key, value, options) {
309           var unsafe = options ? !!options.unsafe : false;
310           var simple = options ? !!options.enumerable : false;
311           var noTargetGet = options ? !!options.noTargetGet : false;
312           var state;
313           if (typeof value == 'function') {
314             if (typeof key == 'string' && !has(value, 'name')) {
315               createNonEnumerableProperty(value, 'name', key);
316             }
317             state = enforceInternalState(value);
318             if (!state.source) {
319               state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
320             }
321           }
322           if (O === global_1) {
323             if (simple) O[key] = value;
324             else setGlobal(key, value);
325             return;
326           } else if (!unsafe) {
327             delete O[key];
328           } else if (!noTargetGet && O[key]) {
329             simple = true;
330           }
331           if (simple) O[key] = value;
332           else createNonEnumerableProperty(O, key, value);
333         // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
334         })(Function.prototype, 'toString', function toString() {
335           return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
336         });
337         });
338
339         var path = global_1;
340
341         var aFunction = function (variable) {
342           return typeof variable == 'function' ? variable : undefined;
343         };
344
345         var getBuiltIn = function (namespace, method) {
346           return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace])
347             : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
348         };
349
350         var ceil = Math.ceil;
351         var floor = Math.floor;
352
353         // `ToInteger` abstract operation
354         // https://tc39.es/ecma262/#sec-tointeger
355         var toInteger = function (argument) {
356           return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
357         };
358
359         var min = Math.min;
360
361         // `ToLength` abstract operation
362         // https://tc39.es/ecma262/#sec-tolength
363         var toLength = function (argument) {
364           return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
365         };
366
367         var max = Math.max;
368         var min$1 = Math.min;
369
370         // Helper for a popular repeating case of the spec:
371         // Let integer be ? ToInteger(index).
372         // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
373         var toAbsoluteIndex = function (index, length) {
374           var integer = toInteger(index);
375           return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
376         };
377
378         // `Array.prototype.{ indexOf, includes }` methods implementation
379         var createMethod = function (IS_INCLUDES) {
380           return function ($this, el, fromIndex) {
381             var O = toIndexedObject($this);
382             var length = toLength(O.length);
383             var index = toAbsoluteIndex(fromIndex, length);
384             var value;
385             // Array#includes uses SameValueZero equality algorithm
386             // eslint-disable-next-line no-self-compare -- NaN check
387             if (IS_INCLUDES && el != el) while (length > index) {
388               value = O[index++];
389               // eslint-disable-next-line no-self-compare -- NaN check
390               if (value != value) return true;
391             // Array#indexOf ignores holes, Array#includes - not
392             } else for (;length > index; index++) {
393               if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
394             } return !IS_INCLUDES && -1;
395           };
396         };
397
398         var arrayIncludes = {
399           // `Array.prototype.includes` method
400           // https://tc39.es/ecma262/#sec-array.prototype.includes
401           includes: createMethod(true),
402           // `Array.prototype.indexOf` method
403           // https://tc39.es/ecma262/#sec-array.prototype.indexof
404           indexOf: createMethod(false)
405         };
406
407         var indexOf = arrayIncludes.indexOf;
408
409
410         var objectKeysInternal = function (object, names) {
411           var O = toIndexedObject(object);
412           var i = 0;
413           var result = [];
414           var key;
415           for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key);
416           // Don't enum bug & hidden keys
417           while (names.length > i) if (has(O, key = names[i++])) {
418             ~indexOf(result, key) || result.push(key);
419           }
420           return result;
421         };
422
423         // IE8- don't enum bug keys
424         var enumBugKeys = [
425           'constructor',
426           'hasOwnProperty',
427           'isPrototypeOf',
428           'propertyIsEnumerable',
429           'toLocaleString',
430           'toString',
431           'valueOf'
432         ];
433
434         var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype');
435
436         // `Object.getOwnPropertyNames` method
437         // https://tc39.es/ecma262/#sec-object.getownpropertynames
438         var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
439           return objectKeysInternal(O, hiddenKeys$1);
440         };
441
442         var objectGetOwnPropertyNames = {
443                 f: f$3
444         };
445
446         var f$4 = Object.getOwnPropertySymbols;
447
448         var objectGetOwnPropertySymbols = {
449                 f: f$4
450         };
451
452         // all object keys, includes non-enumerable and symbols
453         var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
454           var keys = objectGetOwnPropertyNames.f(anObject(it));
455           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
456           return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
457         };
458
459         var copyConstructorProperties = function (target, source) {
460           var keys = ownKeys(source);
461           var defineProperty = objectDefineProperty.f;
462           var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
463           for (var i = 0; i < keys.length; i++) {
464             var key = keys[i];
465             if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
466           }
467         };
468
469         var replacement = /#|\.prototype\./;
470
471         var isForced = function (feature, detection) {
472           var value = data[normalize(feature)];
473           return value == POLYFILL ? true
474             : value == NATIVE ? false
475             : typeof detection == 'function' ? fails(detection)
476             : !!detection;
477         };
478
479         var normalize = isForced.normalize = function (string) {
480           return String(string).replace(replacement, '.').toLowerCase();
481         };
482
483         var data = isForced.data = {};
484         var NATIVE = isForced.NATIVE = 'N';
485         var POLYFILL = isForced.POLYFILL = 'P';
486
487         var isForced_1 = isForced;
488
489         var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
490
491
492
493
494
495
496         /*
497           options.target      - name of the target object
498           options.global      - target is the global object
499           options.stat        - export as static methods of target
500           options.proto       - export as prototype methods of target
501           options.real        - real prototype method for the `pure` version
502           options.forced      - export even if the native feature is available
503           options.bind        - bind methods to the target, required for the `pure` version
504           options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
505           options.unsafe      - use the simple assignment of property instead of delete + defineProperty
506           options.sham        - add a flag to not completely full polyfills
507           options.enumerable  - export as enumerable property
508           options.noTargetGet - prevent calling a getter on target
509         */
510         var _export = function (options, source) {
511           var TARGET = options.target;
512           var GLOBAL = options.global;
513           var STATIC = options.stat;
514           var FORCED, target, key, targetProperty, sourceProperty, descriptor;
515           if (GLOBAL) {
516             target = global_1;
517           } else if (STATIC) {
518             target = global_1[TARGET] || setGlobal(TARGET, {});
519           } else {
520             target = (global_1[TARGET] || {}).prototype;
521           }
522           if (target) for (key in source) {
523             sourceProperty = source[key];
524             if (options.noTargetGet) {
525               descriptor = getOwnPropertyDescriptor$1(target, key);
526               targetProperty = descriptor && descriptor.value;
527             } else targetProperty = target[key];
528             FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
529             // contained in target
530             if (!FORCED && targetProperty !== undefined) {
531               if (typeof sourceProperty === typeof targetProperty) continue;
532               copyConstructorProperties(sourceProperty, targetProperty);
533             }
534             // add a flag to not completely full polyfills
535             if (options.sham || (targetProperty && targetProperty.sham)) {
536               createNonEnumerableProperty(sourceProperty, 'sham', true);
537             }
538             // extend global
539             redefine(target, key, sourceProperty, options);
540           }
541         };
542
543         // `Date.now` method
544         // https://tc39.es/ecma262/#sec-date.now
545         _export({ target: 'Date', stat: true }, {
546           now: function now() {
547             return new Date().getTime();
548           }
549         });
550
551         var DatePrototype = Date.prototype;
552         var INVALID_DATE = 'Invalid Date';
553         var TO_STRING = 'toString';
554         var nativeDateToString = DatePrototype[TO_STRING];
555         var getTime = DatePrototype.getTime;
556
557         // `Date.prototype.toString` method
558         // https://tc39.es/ecma262/#sec-date.prototype.tostring
559         if (new Date(NaN) + '' != INVALID_DATE) {
560           redefine(DatePrototype, TO_STRING, function toString() {
561             var value = getTime.call(this);
562             // eslint-disable-next-line no-self-compare -- NaN check
563             return value === value ? nativeDateToString.call(this) : INVALID_DATE;
564           });
565         }
566
567         function _typeof(obj) {
568           "@babel/helpers - typeof";
569
570           if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
571             _typeof = function (obj) {
572               return typeof obj;
573             };
574           } else {
575             _typeof = function (obj) {
576               return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
577             };
578           }
579
580           return _typeof(obj);
581         }
582
583         function _classCallCheck(instance, Constructor) {
584           if (!(instance instanceof Constructor)) {
585             throw new TypeError("Cannot call a class as a function");
586           }
587         }
588
589         function _defineProperties(target, props) {
590           for (var i = 0; i < props.length; i++) {
591             var descriptor = props[i];
592             descriptor.enumerable = descriptor.enumerable || false;
593             descriptor.configurable = true;
594             if ("value" in descriptor) descriptor.writable = true;
595             Object.defineProperty(target, descriptor.key, descriptor);
596           }
597         }
598
599         function _createClass(Constructor, protoProps, staticProps) {
600           if (protoProps) _defineProperties(Constructor.prototype, protoProps);
601           if (staticProps) _defineProperties(Constructor, staticProps);
602           return Constructor;
603         }
604
605         function _defineProperty(obj, key, value) {
606           if (key in obj) {
607             Object.defineProperty(obj, key, {
608               value: value,
609               enumerable: true,
610               configurable: true,
611               writable: true
612             });
613           } else {
614             obj[key] = value;
615           }
616
617           return obj;
618         }
619
620         function _slicedToArray(arr, i) {
621           return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
622         }
623
624         function _toConsumableArray(arr) {
625           return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
626         }
627
628         function _arrayWithoutHoles(arr) {
629           if (Array.isArray(arr)) return _arrayLikeToArray(arr);
630         }
631
632         function _arrayWithHoles(arr) {
633           if (Array.isArray(arr)) return arr;
634         }
635
636         function _iterableToArray(iter) {
637           if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
638         }
639
640         function _iterableToArrayLimit(arr, i) {
641           if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
642           var _arr = [];
643           var _n = true;
644           var _d = false;
645           var _e = undefined;
646
647           try {
648             for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
649               _arr.push(_s.value);
650
651               if (i && _arr.length === i) break;
652             }
653           } catch (err) {
654             _d = true;
655             _e = err;
656           } finally {
657             try {
658               if (!_n && _i["return"] != null) _i["return"]();
659             } finally {
660               if (_d) throw _e;
661             }
662           }
663
664           return _arr;
665         }
666
667         function _unsupportedIterableToArray(o, minLen) {
668           if (!o) return;
669           if (typeof o === "string") return _arrayLikeToArray(o, minLen);
670           var n = Object.prototype.toString.call(o).slice(8, -1);
671           if (n === "Object" && o.constructor) n = o.constructor.name;
672           if (n === "Map" || n === "Set") return Array.from(o);
673           if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
674         }
675
676         function _arrayLikeToArray(arr, len) {
677           if (len == null || len > arr.length) len = arr.length;
678
679           for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
680
681           return arr2;
682         }
683
684         function _nonIterableSpread() {
685           throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
686         }
687
688         function _nonIterableRest() {
689           throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
690         }
691
692         function _createForOfIteratorHelper(o, allowArrayLike) {
693           var it;
694
695           if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
696             if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
697               if (it) o = it;
698               var i = 0;
699
700               var F = function () {};
701
702               return {
703                 s: F,
704                 n: function () {
705                   if (i >= o.length) return {
706                     done: true
707                   };
708                   return {
709                     done: false,
710                     value: o[i++]
711                   };
712                 },
713                 e: function (e) {
714                   throw e;
715                 },
716                 f: F
717               };
718             }
719
720             throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
721           }
722
723           var normalCompletion = true,
724               didErr = false,
725               err;
726           return {
727             s: function () {
728               it = o[Symbol.iterator]();
729             },
730             n: function () {
731               var step = it.next();
732               normalCompletion = step.done;
733               return step;
734             },
735             e: function (e) {
736               didErr = true;
737               err = e;
738             },
739             f: function () {
740               try {
741                 if (!normalCompletion && it.return != null) it.return();
742               } finally {
743                 if (didErr) throw err;
744               }
745             }
746           };
747         }
748
749         var engineIsNode = classofRaw(global_1.process) == 'process';
750
751         var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';
752
753         var process$1 = global_1.process;
754         var versions = process$1 && process$1.versions;
755         var v8 = versions && versions.v8;
756         var match, version;
757
758         if (v8) {
759           match = v8.split('.');
760           version = match[0] + match[1];
761         } else if (engineUserAgent) {
762           match = engineUserAgent.match(/Edge\/(\d+)/);
763           if (!match || match[1] >= 74) {
764             match = engineUserAgent.match(/Chrome\/(\d+)/);
765             if (match) version = match[1];
766           }
767         }
768
769         var engineV8Version = version && +version;
770
771         var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
772           /* global Symbol -- required for testing */
773           return !Symbol.sham &&
774             // Chrome 38 Symbol has incorrect toString conversion
775             // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
776             (engineIsNode ? engineV8Version === 38 : engineV8Version > 37 && engineV8Version < 41);
777         });
778
779         var useSymbolAsUid = nativeSymbol
780           /* global Symbol -- safe */
781           && !Symbol.sham
782           && typeof Symbol.iterator == 'symbol';
783
784         var WellKnownSymbolsStore = shared('wks');
785         var Symbol$1 = global_1.Symbol;
786         var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;
787
788         var wellKnownSymbol = function (name) {
789           if (!has(WellKnownSymbolsStore, name) || !(nativeSymbol || typeof WellKnownSymbolsStore[name] == 'string')) {
790             if (nativeSymbol && has(Symbol$1, name)) {
791               WellKnownSymbolsStore[name] = Symbol$1[name];
792             } else {
793               WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
794             }
795           } return WellKnownSymbolsStore[name];
796         };
797
798         var f$5 = wellKnownSymbol;
799
800         var wellKnownSymbolWrapped = {
801                 f: f$5
802         };
803
804         var defineProperty = objectDefineProperty.f;
805
806         var defineWellKnownSymbol = function (NAME) {
807           var Symbol = path.Symbol || (path.Symbol = {});
808           if (!has(Symbol, NAME)) defineProperty(Symbol, NAME, {
809             value: wellKnownSymbolWrapped.f(NAME)
810           });
811         };
812
813         // `Symbol.iterator` well-known symbol
814         // https://tc39.es/ecma262/#sec-symbol.iterator
815         defineWellKnownSymbol('iterator');
816
817         var TO_STRING_TAG = wellKnownSymbol('toStringTag');
818         var test = {};
819
820         test[TO_STRING_TAG] = 'z';
821
822         var toStringTagSupport = String(test) === '[object z]';
823
824         var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
825         // ES3 wrong here
826         var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
827
828         // fallback for IE11 Script Access Denied error
829         var tryGet = function (it, key) {
830           try {
831             return it[key];
832           } catch (error) { /* empty */ }
833         };
834
835         // getting tag from ES6+ `Object.prototype.toString`
836         var classof = toStringTagSupport ? classofRaw : function (it) {
837           var O, tag, result;
838           return it === undefined ? 'Undefined' : it === null ? 'Null'
839             // @@toStringTag case
840             : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$1)) == 'string' ? tag
841             // builtinTag case
842             : CORRECT_ARGUMENTS ? classofRaw(O)
843             // ES3 arguments fallback
844             : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
845         };
846
847         // `Object.prototype.toString` method implementation
848         // https://tc39.es/ecma262/#sec-object.prototype.tostring
849         var objectToString = toStringTagSupport ? {}.toString : function toString() {
850           return '[object ' + classof(this) + ']';
851         };
852
853         // `Object.prototype.toString` method
854         // https://tc39.es/ecma262/#sec-object.prototype.tostring
855         if (!toStringTagSupport) {
856           redefine(Object.prototype, 'toString', objectToString, { unsafe: true });
857         }
858
859         // `String.prototype.{ codePointAt, at }` methods implementation
860         var createMethod$1 = function (CONVERT_TO_STRING) {
861           return function ($this, pos) {
862             var S = String(requireObjectCoercible($this));
863             var position = toInteger(pos);
864             var size = S.length;
865             var first, second;
866             if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
867             first = S.charCodeAt(position);
868             return first < 0xD800 || first > 0xDBFF || position + 1 === size
869               || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
870                 ? CONVERT_TO_STRING ? S.charAt(position) : first
871                 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
872           };
873         };
874
875         var stringMultibyte = {
876           // `String.prototype.codePointAt` method
877           // https://tc39.es/ecma262/#sec-string.prototype.codepointat
878           codeAt: createMethod$1(false),
879           // `String.prototype.at` method
880           // https://github.com/mathiasbynens/String.prototype.at
881           charAt: createMethod$1(true)
882         };
883
884         // `ToObject` abstract operation
885         // https://tc39.es/ecma262/#sec-toobject
886         var toObject = function (argument) {
887           return Object(requireObjectCoercible(argument));
888         };
889
890         var correctPrototypeGetter = !fails(function () {
891           function F() { /* empty */ }
892           F.prototype.constructor = null;
893           return Object.getPrototypeOf(new F()) !== F.prototype;
894         });
895
896         var IE_PROTO = sharedKey('IE_PROTO');
897         var ObjectPrototype = Object.prototype;
898
899         // `Object.getPrototypeOf` method
900         // https://tc39.es/ecma262/#sec-object.getprototypeof
901         var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
902           O = toObject(O);
903           if (has(O, IE_PROTO)) return O[IE_PROTO];
904           if (typeof O.constructor == 'function' && O instanceof O.constructor) {
905             return O.constructor.prototype;
906           } return O instanceof Object ? ObjectPrototype : null;
907         };
908
909         var ITERATOR = wellKnownSymbol('iterator');
910         var BUGGY_SAFARI_ITERATORS = false;
911
912         var returnThis = function () { return this; };
913
914         // `%IteratorPrototype%` object
915         // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
916         var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;
917
918         if ([].keys) {
919           arrayIterator = [].keys();
920           // Safari 8 has buggy iterators w/o `next`
921           if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;
922           else {
923             PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
924             if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
925           }
926         }
927
928         var NEW_ITERATOR_PROTOTYPE = IteratorPrototype == undefined || fails(function () {
929           var test = {};
930           // FF44- legacy iterators case
931           return IteratorPrototype[ITERATOR].call(test) !== test;
932         });
933
934         if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype = {};
935
936         // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
937         if ( !has(IteratorPrototype, ITERATOR)) {
938           createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis);
939         }
940
941         var iteratorsCore = {
942           IteratorPrototype: IteratorPrototype,
943           BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
944         };
945
946         // `Object.keys` method
947         // https://tc39.es/ecma262/#sec-object.keys
948         var objectKeys = Object.keys || function keys(O) {
949           return objectKeysInternal(O, enumBugKeys);
950         };
951
952         // `Object.defineProperties` method
953         // https://tc39.es/ecma262/#sec-object.defineproperties
954         var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
955           anObject(O);
956           var keys = objectKeys(Properties);
957           var length = keys.length;
958           var index = 0;
959           var key;
960           while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
961           return O;
962         };
963
964         var html = getBuiltIn('document', 'documentElement');
965
966         var GT = '>';
967         var LT = '<';
968         var PROTOTYPE = 'prototype';
969         var SCRIPT = 'script';
970         var IE_PROTO$1 = sharedKey('IE_PROTO');
971
972         var EmptyConstructor = function () { /* empty */ };
973
974         var scriptTag = function (content) {
975           return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
976         };
977
978         // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
979         var NullProtoObjectViaActiveX = function (activeXDocument) {
980           activeXDocument.write(scriptTag(''));
981           activeXDocument.close();
982           var temp = activeXDocument.parentWindow.Object;
983           activeXDocument = null; // avoid memory leak
984           return temp;
985         };
986
987         // Create object with fake `null` prototype: use iframe Object with cleared prototype
988         var NullProtoObjectViaIFrame = function () {
989           // Thrash, waste and sodomy: IE GC bug
990           var iframe = documentCreateElement('iframe');
991           var JS = 'java' + SCRIPT + ':';
992           var iframeDocument;
993           iframe.style.display = 'none';
994           html.appendChild(iframe);
995           // https://github.com/zloirock/core-js/issues/475
996           iframe.src = String(JS);
997           iframeDocument = iframe.contentWindow.document;
998           iframeDocument.open();
999           iframeDocument.write(scriptTag('document.F=Object'));
1000           iframeDocument.close();
1001           return iframeDocument.F;
1002         };
1003
1004         // Check for document.domain and active x support
1005         // No need to use active x approach when document.domain is not set
1006         // see https://github.com/es-shims/es5-shim/issues/150
1007         // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
1008         // avoid IE GC bug
1009         var activeXDocument;
1010         var NullProtoObject = function () {
1011           try {
1012             /* global ActiveXObject -- old IE */
1013             activeXDocument = document.domain && new ActiveXObject('htmlfile');
1014           } catch (error) { /* ignore */ }
1015           NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
1016           var length = enumBugKeys.length;
1017           while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];
1018           return NullProtoObject();
1019         };
1020
1021         hiddenKeys[IE_PROTO$1] = true;
1022
1023         // `Object.create` method
1024         // https://tc39.es/ecma262/#sec-object.create
1025         var objectCreate = Object.create || function create(O, Properties) {
1026           var result;
1027           if (O !== null) {
1028             EmptyConstructor[PROTOTYPE] = anObject(O);
1029             result = new EmptyConstructor();
1030             EmptyConstructor[PROTOTYPE] = null;
1031             // add "__proto__" for Object.getPrototypeOf polyfill
1032             result[IE_PROTO$1] = O;
1033           } else result = NullProtoObject();
1034           return Properties === undefined ? result : objectDefineProperties(result, Properties);
1035         };
1036
1037         var defineProperty$1 = objectDefineProperty.f;
1038
1039
1040
1041         var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');
1042
1043         var setToStringTag = function (it, TAG, STATIC) {
1044           if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG$2)) {
1045             defineProperty$1(it, TO_STRING_TAG$2, { configurable: true, value: TAG });
1046           }
1047         };
1048
1049         var iterators = {};
1050
1051         var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1052
1053
1054
1055
1056
1057         var returnThis$1 = function () { return this; };
1058
1059         var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
1060           var TO_STRING_TAG = NAME + ' Iterator';
1061           IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) });
1062           setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
1063           iterators[TO_STRING_TAG] = returnThis$1;
1064           return IteratorConstructor;
1065         };
1066
1067         var aPossiblePrototype = function (it) {
1068           if (!isObject(it) && it !== null) {
1069             throw TypeError("Can't set " + String(it) + ' as a prototype');
1070           } return it;
1071         };
1072
1073         /* eslint-disable no-proto -- safe */
1074
1075
1076
1077         // `Object.setPrototypeOf` method
1078         // https://tc39.es/ecma262/#sec-object.setprototypeof
1079         // Works with __proto__ only. Old v8 can't work with null proto objects.
1080         var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1081           var CORRECT_SETTER = false;
1082           var test = {};
1083           var setter;
1084           try {
1085             setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1086             setter.call(test, []);
1087             CORRECT_SETTER = test instanceof Array;
1088           } catch (error) { /* empty */ }
1089           return function setPrototypeOf(O, proto) {
1090             anObject(O);
1091             aPossiblePrototype(proto);
1092             if (CORRECT_SETTER) setter.call(O, proto);
1093             else O.__proto__ = proto;
1094             return O;
1095           };
1096         }() : undefined);
1097
1098         var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
1099         var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
1100         var ITERATOR$1 = wellKnownSymbol('iterator');
1101         var KEYS = 'keys';
1102         var VALUES = 'values';
1103         var ENTRIES = 'entries';
1104
1105         var returnThis$2 = function () { return this; };
1106
1107         var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1108           createIteratorConstructor(IteratorConstructor, NAME, next);
1109
1110           var getIterationMethod = function (KIND) {
1111             if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1112             if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
1113             switch (KIND) {
1114               case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
1115               case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
1116               case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
1117             } return function () { return new IteratorConstructor(this); };
1118           };
1119
1120           var TO_STRING_TAG = NAME + ' Iterator';
1121           var INCORRECT_VALUES_NAME = false;
1122           var IterablePrototype = Iterable.prototype;
1123           var nativeIterator = IterablePrototype[ITERATOR$1]
1124             || IterablePrototype['@@iterator']
1125             || DEFAULT && IterablePrototype[DEFAULT];
1126           var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
1127           var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1128           var CurrentIteratorPrototype, methods, KEY;
1129
1130           // fix native
1131           if (anyNativeIterator) {
1132             CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
1133             if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
1134               if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
1135                 if (objectSetPrototypeOf) {
1136                   objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
1137                 } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') {
1138                   createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$2);
1139                 }
1140               }
1141               // Set @@toStringTag to native iterators
1142               setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
1143             }
1144           }
1145
1146           // fix Array#{values, @@iterator}.name in V8 / FF
1147           if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1148             INCORRECT_VALUES_NAME = true;
1149             defaultIterator = function values() { return nativeIterator.call(this); };
1150           }
1151
1152           // define iterator
1153           if ( IterablePrototype[ITERATOR$1] !== defaultIterator) {
1154             createNonEnumerableProperty(IterablePrototype, ITERATOR$1, defaultIterator);
1155           }
1156           iterators[NAME] = defaultIterator;
1157
1158           // export additional methods
1159           if (DEFAULT) {
1160             methods = {
1161               values: getIterationMethod(VALUES),
1162               keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1163               entries: getIterationMethod(ENTRIES)
1164             };
1165             if (FORCED) for (KEY in methods) {
1166               if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1167                 redefine(IterablePrototype, KEY, methods[KEY]);
1168               }
1169             } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME }, methods);
1170           }
1171
1172           return methods;
1173         };
1174
1175         var charAt = stringMultibyte.charAt;
1176
1177
1178
1179         var STRING_ITERATOR = 'String Iterator';
1180         var setInternalState = internalState.set;
1181         var getInternalState = internalState.getterFor(STRING_ITERATOR);
1182
1183         // `String.prototype[@@iterator]` method
1184         // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
1185         defineIterator(String, 'String', function (iterated) {
1186           setInternalState(this, {
1187             type: STRING_ITERATOR,
1188             string: String(iterated),
1189             index: 0
1190           });
1191         // `%StringIteratorPrototype%.next` method
1192         // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
1193         }, function next() {
1194           var state = getInternalState(this);
1195           var string = state.string;
1196           var index = state.index;
1197           var point;
1198           if (index >= string.length) return { value: undefined, done: true };
1199           point = charAt(string, index);
1200           state.index += point.length;
1201           return { value: point, done: false };
1202         });
1203
1204         var UNSCOPABLES = wellKnownSymbol('unscopables');
1205         var ArrayPrototype = Array.prototype;
1206
1207         // Array.prototype[@@unscopables]
1208         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1209         if (ArrayPrototype[UNSCOPABLES] == undefined) {
1210           objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, {
1211             configurable: true,
1212             value: objectCreate(null)
1213           });
1214         }
1215
1216         // add a key to Array.prototype[@@unscopables]
1217         var addToUnscopables = function (key) {
1218           ArrayPrototype[UNSCOPABLES][key] = true;
1219         };
1220
1221         var ARRAY_ITERATOR = 'Array Iterator';
1222         var setInternalState$1 = internalState.set;
1223         var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR);
1224
1225         // `Array.prototype.entries` method
1226         // https://tc39.es/ecma262/#sec-array.prototype.entries
1227         // `Array.prototype.keys` method
1228         // https://tc39.es/ecma262/#sec-array.prototype.keys
1229         // `Array.prototype.values` method
1230         // https://tc39.es/ecma262/#sec-array.prototype.values
1231         // `Array.prototype[@@iterator]` method
1232         // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
1233         // `CreateArrayIterator` internal method
1234         // https://tc39.es/ecma262/#sec-createarrayiterator
1235         var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
1236           setInternalState$1(this, {
1237             type: ARRAY_ITERATOR,
1238             target: toIndexedObject(iterated), // target
1239             index: 0,                          // next index
1240             kind: kind                         // kind
1241           });
1242         // `%ArrayIteratorPrototype%.next` method
1243         // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
1244         }, function () {
1245           var state = getInternalState$1(this);
1246           var target = state.target;
1247           var kind = state.kind;
1248           var index = state.index++;
1249           if (!target || index >= target.length) {
1250             state.target = undefined;
1251             return { value: undefined, done: true };
1252           }
1253           if (kind == 'keys') return { value: index, done: false };
1254           if (kind == 'values') return { value: target[index], done: false };
1255           return { value: [index, target[index]], done: false };
1256         }, 'values');
1257
1258         // argumentsList[@@iterator] is %ArrayProto_values%
1259         // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
1260         // https://tc39.es/ecma262/#sec-createmappedargumentsobject
1261         iterators.Arguments = iterators.Array;
1262
1263         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1264         addToUnscopables('keys');
1265         addToUnscopables('values');
1266         addToUnscopables('entries');
1267
1268         // iterable DOM collections
1269         // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
1270         var domIterables = {
1271           CSSRuleList: 0,
1272           CSSStyleDeclaration: 0,
1273           CSSValueList: 0,
1274           ClientRectList: 0,
1275           DOMRectList: 0,
1276           DOMStringList: 0,
1277           DOMTokenList: 1,
1278           DataTransferItemList: 0,
1279           FileList: 0,
1280           HTMLAllCollection: 0,
1281           HTMLCollection: 0,
1282           HTMLFormElement: 0,
1283           HTMLSelectElement: 0,
1284           MediaList: 0,
1285           MimeTypeArray: 0,
1286           NamedNodeMap: 0,
1287           NodeList: 1,
1288           PaintRequestList: 0,
1289           Plugin: 0,
1290           PluginArray: 0,
1291           SVGLengthList: 0,
1292           SVGNumberList: 0,
1293           SVGPathSegList: 0,
1294           SVGPointList: 0,
1295           SVGStringList: 0,
1296           SVGTransformList: 0,
1297           SourceBufferList: 0,
1298           StyleSheetList: 0,
1299           TextTrackCueList: 0,
1300           TextTrackList: 0,
1301           TouchList: 0
1302         };
1303
1304         var ITERATOR$2 = wellKnownSymbol('iterator');
1305         var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
1306         var ArrayValues = es_array_iterator.values;
1307
1308         for (var COLLECTION_NAME in domIterables) {
1309           var Collection = global_1[COLLECTION_NAME];
1310           var CollectionPrototype = Collection && Collection.prototype;
1311           if (CollectionPrototype) {
1312             // some Chrome versions have non-configurable methods on DOMTokenList
1313             if (CollectionPrototype[ITERATOR$2] !== ArrayValues) try {
1314               createNonEnumerableProperty(CollectionPrototype, ITERATOR$2, ArrayValues);
1315             } catch (error) {
1316               CollectionPrototype[ITERATOR$2] = ArrayValues;
1317             }
1318             if (!CollectionPrototype[TO_STRING_TAG$3]) {
1319               createNonEnumerableProperty(CollectionPrototype, TO_STRING_TAG$3, COLLECTION_NAME);
1320             }
1321             if (domIterables[COLLECTION_NAME]) for (var METHOD_NAME in es_array_iterator) {
1322               // some Chrome versions have non-configurable methods on DOMTokenList
1323               if (CollectionPrototype[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
1324                 createNonEnumerableProperty(CollectionPrototype, METHOD_NAME, es_array_iterator[METHOD_NAME]);
1325               } catch (error) {
1326                 CollectionPrototype[METHOD_NAME] = es_array_iterator[METHOD_NAME];
1327               }
1328             }
1329           }
1330         }
1331
1332         // `IsArray` abstract operation
1333         // https://tc39.es/ecma262/#sec-isarray
1334         var isArray = Array.isArray || function isArray(arg) {
1335           return classofRaw(arg) == 'Array';
1336         };
1337
1338         var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
1339
1340         var toString$1 = {}.toString;
1341
1342         var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
1343           ? Object.getOwnPropertyNames(window) : [];
1344
1345         var getWindowNames = function (it) {
1346           try {
1347             return nativeGetOwnPropertyNames(it);
1348           } catch (error) {
1349             return windowNames.slice();
1350           }
1351         };
1352
1353         // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
1354         var f$6 = function getOwnPropertyNames(it) {
1355           return windowNames && toString$1.call(it) == '[object Window]'
1356             ? getWindowNames(it)
1357             : nativeGetOwnPropertyNames(toIndexedObject(it));
1358         };
1359
1360         var objectGetOwnPropertyNamesExternal = {
1361                 f: f$6
1362         };
1363
1364         var aFunction$1 = function (it) {
1365           if (typeof it != 'function') {
1366             throw TypeError(String(it) + ' is not a function');
1367           } return it;
1368         };
1369
1370         // optional / simple context binding
1371         var functionBindContext = function (fn, that, length) {
1372           aFunction$1(fn);
1373           if (that === undefined) return fn;
1374           switch (length) {
1375             case 0: return function () {
1376               return fn.call(that);
1377             };
1378             case 1: return function (a) {
1379               return fn.call(that, a);
1380             };
1381             case 2: return function (a, b) {
1382               return fn.call(that, a, b);
1383             };
1384             case 3: return function (a, b, c) {
1385               return fn.call(that, a, b, c);
1386             };
1387           }
1388           return function (/* ...args */) {
1389             return fn.apply(that, arguments);
1390           };
1391         };
1392
1393         var SPECIES = wellKnownSymbol('species');
1394
1395         // `ArraySpeciesCreate` abstract operation
1396         // https://tc39.es/ecma262/#sec-arrayspeciescreate
1397         var arraySpeciesCreate = function (originalArray, length) {
1398           var C;
1399           if (isArray(originalArray)) {
1400             C = originalArray.constructor;
1401             // cross-realm fallback
1402             if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
1403             else if (isObject(C)) {
1404               C = C[SPECIES];
1405               if (C === null) C = undefined;
1406             }
1407           } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
1408         };
1409
1410         var push = [].push;
1411
1412         // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterOut }` methods implementation
1413         var createMethod$2 = function (TYPE) {
1414           var IS_MAP = TYPE == 1;
1415           var IS_FILTER = TYPE == 2;
1416           var IS_SOME = TYPE == 3;
1417           var IS_EVERY = TYPE == 4;
1418           var IS_FIND_INDEX = TYPE == 6;
1419           var IS_FILTER_OUT = TYPE == 7;
1420           var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
1421           return function ($this, callbackfn, that, specificCreate) {
1422             var O = toObject($this);
1423             var self = indexedObject(O);
1424             var boundFunction = functionBindContext(callbackfn, that, 3);
1425             var length = toLength(self.length);
1426             var index = 0;
1427             var create = specificCreate || arraySpeciesCreate;
1428             var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_OUT ? create($this, 0) : undefined;
1429             var value, result;
1430             for (;length > index; index++) if (NO_HOLES || index in self) {
1431               value = self[index];
1432               result = boundFunction(value, index, O);
1433               if (TYPE) {
1434                 if (IS_MAP) target[index] = result; // map
1435                 else if (result) switch (TYPE) {
1436                   case 3: return true;              // some
1437                   case 5: return value;             // find
1438                   case 6: return index;             // findIndex
1439                   case 2: push.call(target, value); // filter
1440                 } else switch (TYPE) {
1441                   case 4: return false;             // every
1442                   case 7: push.call(target, value); // filterOut
1443                 }
1444               }
1445             }
1446             return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
1447           };
1448         };
1449
1450         var arrayIteration = {
1451           // `Array.prototype.forEach` method
1452           // https://tc39.es/ecma262/#sec-array.prototype.foreach
1453           forEach: createMethod$2(0),
1454           // `Array.prototype.map` method
1455           // https://tc39.es/ecma262/#sec-array.prototype.map
1456           map: createMethod$2(1),
1457           // `Array.prototype.filter` method
1458           // https://tc39.es/ecma262/#sec-array.prototype.filter
1459           filter: createMethod$2(2),
1460           // `Array.prototype.some` method
1461           // https://tc39.es/ecma262/#sec-array.prototype.some
1462           some: createMethod$2(3),
1463           // `Array.prototype.every` method
1464           // https://tc39.es/ecma262/#sec-array.prototype.every
1465           every: createMethod$2(4),
1466           // `Array.prototype.find` method
1467           // https://tc39.es/ecma262/#sec-array.prototype.find
1468           find: createMethod$2(5),
1469           // `Array.prototype.findIndex` method
1470           // https://tc39.es/ecma262/#sec-array.prototype.findIndex
1471           findIndex: createMethod$2(6),
1472           // `Array.prototype.filterOut` method
1473           // https://github.com/tc39/proposal-array-filtering
1474           filterOut: createMethod$2(7)
1475         };
1476
1477         var $forEach = arrayIteration.forEach;
1478
1479         var HIDDEN = sharedKey('hidden');
1480         var SYMBOL = 'Symbol';
1481         var PROTOTYPE$1 = 'prototype';
1482         var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
1483         var setInternalState$2 = internalState.set;
1484         var getInternalState$2 = internalState.getterFor(SYMBOL);
1485         var ObjectPrototype$1 = Object[PROTOTYPE$1];
1486         var $Symbol = global_1.Symbol;
1487         var $stringify = getBuiltIn('JSON', 'stringify');
1488         var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
1489         var nativeDefineProperty$1 = objectDefineProperty.f;
1490         var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
1491         var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
1492         var AllSymbols = shared('symbols');
1493         var ObjectPrototypeSymbols = shared('op-symbols');
1494         var StringToSymbolRegistry = shared('string-to-symbol-registry');
1495         var SymbolToStringRegistry = shared('symbol-to-string-registry');
1496         var WellKnownSymbolsStore$1 = shared('wks');
1497         var QObject = global_1.QObject;
1498         // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
1499         var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild;
1500
1501         // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
1502         var setSymbolDescriptor = descriptors && fails(function () {
1503           return objectCreate(nativeDefineProperty$1({}, 'a', {
1504             get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; }
1505           })).a != 7;
1506         }) ? function (O, P, Attributes) {
1507           var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype$1, P);
1508           if (ObjectPrototypeDescriptor) delete ObjectPrototype$1[P];
1509           nativeDefineProperty$1(O, P, Attributes);
1510           if (ObjectPrototypeDescriptor && O !== ObjectPrototype$1) {
1511             nativeDefineProperty$1(ObjectPrototype$1, P, ObjectPrototypeDescriptor);
1512           }
1513         } : nativeDefineProperty$1;
1514
1515         var wrap = function (tag, description) {
1516           var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]);
1517           setInternalState$2(symbol, {
1518             type: SYMBOL,
1519             tag: tag,
1520             description: description
1521           });
1522           if (!descriptors) symbol.description = description;
1523           return symbol;
1524         };
1525
1526         var isSymbol = useSymbolAsUid ? function (it) {
1527           return typeof it == 'symbol';
1528         } : function (it) {
1529           return Object(it) instanceof $Symbol;
1530         };
1531
1532         var $defineProperty = function defineProperty(O, P, Attributes) {
1533           if (O === ObjectPrototype$1) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
1534           anObject(O);
1535           var key = toPrimitive(P, true);
1536           anObject(Attributes);
1537           if (has(AllSymbols, key)) {
1538             if (!Attributes.enumerable) {
1539               if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {}));
1540               O[HIDDEN][key] = true;
1541             } else {
1542               if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
1543               Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) });
1544             } return setSymbolDescriptor(O, key, Attributes);
1545           } return nativeDefineProperty$1(O, key, Attributes);
1546         };
1547
1548         var $defineProperties = function defineProperties(O, Properties) {
1549           anObject(O);
1550           var properties = toIndexedObject(Properties);
1551           var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
1552           $forEach(keys, function (key) {
1553             if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
1554           });
1555           return O;
1556         };
1557
1558         var $create = function create(O, Properties) {
1559           return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
1560         };
1561
1562         var $propertyIsEnumerable = function propertyIsEnumerable(V) {
1563           var P = toPrimitive(V, true);
1564           var enumerable = nativePropertyIsEnumerable$1.call(this, P);
1565           if (this === ObjectPrototype$1 && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false;
1566           return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
1567         };
1568
1569         var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
1570           var it = toIndexedObject(O);
1571           var key = toPrimitive(P, true);
1572           if (it === ObjectPrototype$1 && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return;
1573           var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
1574           if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) {
1575             descriptor.enumerable = true;
1576           }
1577           return descriptor;
1578         };
1579
1580         var $getOwnPropertyNames = function getOwnPropertyNames(O) {
1581           var names = nativeGetOwnPropertyNames$1(toIndexedObject(O));
1582           var result = [];
1583           $forEach(names, function (key) {
1584             if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key);
1585           });
1586           return result;
1587         };
1588
1589         var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
1590           var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$1;
1591           var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
1592           var result = [];
1593           $forEach(names, function (key) {
1594             if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype$1, key))) {
1595               result.push(AllSymbols[key]);
1596             }
1597           });
1598           return result;
1599         };
1600
1601         // `Symbol` constructor
1602         // https://tc39.es/ecma262/#sec-symbol-constructor
1603         if (!nativeSymbol) {
1604           $Symbol = function Symbol() {
1605             if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
1606             var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
1607             var tag = uid(description);
1608             var setter = function (value) {
1609               if (this === ObjectPrototype$1) setter.call(ObjectPrototypeSymbols, value);
1610               if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
1611               setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
1612             };
1613             if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype$1, tag, { configurable: true, set: setter });
1614             return wrap(tag, description);
1615           };
1616
1617           redefine($Symbol[PROTOTYPE$1], 'toString', function toString() {
1618             return getInternalState$2(this).tag;
1619           });
1620
1621           redefine($Symbol, 'withoutSetter', function (description) {
1622             return wrap(uid(description), description);
1623           });
1624
1625           objectPropertyIsEnumerable.f = $propertyIsEnumerable;
1626           objectDefineProperty.f = $defineProperty;
1627           objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
1628           objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
1629           objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;
1630
1631           wellKnownSymbolWrapped.f = function (name) {
1632             return wrap(wellKnownSymbol(name), name);
1633           };
1634
1635           if (descriptors) {
1636             // https://github.com/tc39/proposal-Symbol-description
1637             nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
1638               configurable: true,
1639               get: function description() {
1640                 return getInternalState$2(this).description;
1641               }
1642             });
1643             {
1644               redefine(ObjectPrototype$1, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true });
1645             }
1646           }
1647         }
1648
1649         _export({ global: true, wrap: true, forced: !nativeSymbol, sham: !nativeSymbol }, {
1650           Symbol: $Symbol
1651         });
1652
1653         $forEach(objectKeys(WellKnownSymbolsStore$1), function (name) {
1654           defineWellKnownSymbol(name);
1655         });
1656
1657         _export({ target: SYMBOL, stat: true, forced: !nativeSymbol }, {
1658           // `Symbol.for` method
1659           // https://tc39.es/ecma262/#sec-symbol.for
1660           'for': function (key) {
1661             var string = String(key);
1662             if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
1663             var symbol = $Symbol(string);
1664             StringToSymbolRegistry[string] = symbol;
1665             SymbolToStringRegistry[symbol] = string;
1666             return symbol;
1667           },
1668           // `Symbol.keyFor` method
1669           // https://tc39.es/ecma262/#sec-symbol.keyfor
1670           keyFor: function keyFor(sym) {
1671             if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
1672             if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
1673           },
1674           useSetter: function () { USE_SETTER = true; },
1675           useSimple: function () { USE_SETTER = false; }
1676         });
1677
1678         _export({ target: 'Object', stat: true, forced: !nativeSymbol, sham: !descriptors }, {
1679           // `Object.create` method
1680           // https://tc39.es/ecma262/#sec-object.create
1681           create: $create,
1682           // `Object.defineProperty` method
1683           // https://tc39.es/ecma262/#sec-object.defineproperty
1684           defineProperty: $defineProperty,
1685           // `Object.defineProperties` method
1686           // https://tc39.es/ecma262/#sec-object.defineproperties
1687           defineProperties: $defineProperties,
1688           // `Object.getOwnPropertyDescriptor` method
1689           // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
1690           getOwnPropertyDescriptor: $getOwnPropertyDescriptor
1691         });
1692
1693         _export({ target: 'Object', stat: true, forced: !nativeSymbol }, {
1694           // `Object.getOwnPropertyNames` method
1695           // https://tc39.es/ecma262/#sec-object.getownpropertynames
1696           getOwnPropertyNames: $getOwnPropertyNames,
1697           // `Object.getOwnPropertySymbols` method
1698           // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
1699           getOwnPropertySymbols: $getOwnPropertySymbols
1700         });
1701
1702         // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
1703         // https://bugs.chromium.org/p/v8/issues/detail?id=3443
1704         _export({ target: 'Object', stat: true, forced: fails(function () { objectGetOwnPropertySymbols.f(1); }) }, {
1705           getOwnPropertySymbols: function getOwnPropertySymbols(it) {
1706             return objectGetOwnPropertySymbols.f(toObject(it));
1707           }
1708         });
1709
1710         // `JSON.stringify` method behavior with symbols
1711         // https://tc39.es/ecma262/#sec-json.stringify
1712         if ($stringify) {
1713           var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {
1714             var symbol = $Symbol();
1715             // MS Edge converts symbol values to JSON as {}
1716             return $stringify([symbol]) != '[null]'
1717               // WebKit converts symbol values to JSON as null
1718               || $stringify({ a: symbol }) != '{}'
1719               // V8 throws on boxed symbols
1720               || $stringify(Object(symbol)) != '{}';
1721           });
1722
1723           _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {
1724             // eslint-disable-next-line no-unused-vars -- required for `.length`
1725             stringify: function stringify(it, replacer, space) {
1726               var args = [it];
1727               var index = 1;
1728               var $replacer;
1729               while (arguments.length > index) args.push(arguments[index++]);
1730               $replacer = replacer;
1731               if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
1732               if (!isArray(replacer)) replacer = function (key, value) {
1733                 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
1734                 if (!isSymbol(value)) return value;
1735               };
1736               args[1] = replacer;
1737               return $stringify.apply(null, args);
1738             }
1739           });
1740         }
1741
1742         // `Symbol.prototype[@@toPrimitive]` method
1743         // https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
1744         if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
1745           createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
1746         }
1747         // `Symbol.prototype[@@toStringTag]` property
1748         // https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
1749         setToStringTag($Symbol, SYMBOL);
1750
1751         hiddenKeys[HIDDEN] = true;
1752
1753         var defineProperty$2 = objectDefineProperty.f;
1754
1755
1756         var NativeSymbol = global_1.Symbol;
1757
1758         if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
1759           // Safari 12 bug
1760           NativeSymbol().description !== undefined
1761         )) {
1762           var EmptyStringDescriptionStore = {};
1763           // wrap Symbol constructor for correct work with undefined description
1764           var SymbolWrapper = function Symbol() {
1765             var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
1766             var result = this instanceof SymbolWrapper
1767               ? new NativeSymbol(description)
1768               // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
1769               : description === undefined ? NativeSymbol() : NativeSymbol(description);
1770             if (description === '') EmptyStringDescriptionStore[result] = true;
1771             return result;
1772           };
1773           copyConstructorProperties(SymbolWrapper, NativeSymbol);
1774           var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
1775           symbolPrototype.constructor = SymbolWrapper;
1776
1777           var symbolToString = symbolPrototype.toString;
1778           var native = String(NativeSymbol('test')) == 'Symbol(test)';
1779           var regexp = /^Symbol\((.*)\)[^)]+$/;
1780           defineProperty$2(symbolPrototype, 'description', {
1781             configurable: true,
1782             get: function description() {
1783               var symbol = isObject(this) ? this.valueOf() : this;
1784               var string = symbolToString.call(symbol);
1785               if (has(EmptyStringDescriptionStore, symbol)) return '';
1786               var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
1787               return desc === '' ? undefined : desc;
1788             }
1789           });
1790
1791           _export({ global: true, forced: true }, {
1792             Symbol: SymbolWrapper
1793           });
1794         }
1795
1796         var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';
1797
1798         var redefineAll = function (target, src, options) {
1799           for (var key in src) redefine(target, key, src[key], options);
1800           return target;
1801         };
1802
1803         var anInstance = function (it, Constructor, name) {
1804           if (!(it instanceof Constructor)) {
1805             throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
1806           } return it;
1807         };
1808
1809         // `ToIndex` abstract operation
1810         // https://tc39.es/ecma262/#sec-toindex
1811         var toIndex = function (it) {
1812           if (it === undefined) return 0;
1813           var number = toInteger(it);
1814           var length = toLength(number);
1815           if (number !== length) throw RangeError('Wrong length or index');
1816           return length;
1817         };
1818
1819         // IEEE754 conversions based on https://github.com/feross/ieee754
1820         var abs = Math.abs;
1821         var pow = Math.pow;
1822         var floor$1 = Math.floor;
1823         var log = Math.log;
1824         var LN2 = Math.LN2;
1825
1826         var pack = function (number, mantissaLength, bytes) {
1827           var buffer = new Array(bytes);
1828           var exponentLength = bytes * 8 - mantissaLength - 1;
1829           var eMax = (1 << exponentLength) - 1;
1830           var eBias = eMax >> 1;
1831           var rt = mantissaLength === 23 ? pow(2, -24) - pow(2, -77) : 0;
1832           var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
1833           var index = 0;
1834           var exponent, mantissa, c;
1835           number = abs(number);
1836           // eslint-disable-next-line no-self-compare -- NaN check
1837           if (number != number || number === Infinity) {
1838             // eslint-disable-next-line no-self-compare -- NaN check
1839             mantissa = number != number ? 1 : 0;
1840             exponent = eMax;
1841           } else {
1842             exponent = floor$1(log(number) / LN2);
1843             if (number * (c = pow(2, -exponent)) < 1) {
1844               exponent--;
1845               c *= 2;
1846             }
1847             if (exponent + eBias >= 1) {
1848               number += rt / c;
1849             } else {
1850               number += rt * pow(2, 1 - eBias);
1851             }
1852             if (number * c >= 2) {
1853               exponent++;
1854               c /= 2;
1855             }
1856             if (exponent + eBias >= eMax) {
1857               mantissa = 0;
1858               exponent = eMax;
1859             } else if (exponent + eBias >= 1) {
1860               mantissa = (number * c - 1) * pow(2, mantissaLength);
1861               exponent = exponent + eBias;
1862             } else {
1863               mantissa = number * pow(2, eBias - 1) * pow(2, mantissaLength);
1864               exponent = 0;
1865             }
1866           }
1867           for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
1868           exponent = exponent << mantissaLength | mantissa;
1869           exponentLength += mantissaLength;
1870           for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
1871           buffer[--index] |= sign * 128;
1872           return buffer;
1873         };
1874
1875         var unpack = function (buffer, mantissaLength) {
1876           var bytes = buffer.length;
1877           var exponentLength = bytes * 8 - mantissaLength - 1;
1878           var eMax = (1 << exponentLength) - 1;
1879           var eBias = eMax >> 1;
1880           var nBits = exponentLength - 7;
1881           var index = bytes - 1;
1882           var sign = buffer[index--];
1883           var exponent = sign & 127;
1884           var mantissa;
1885           sign >>= 7;
1886           for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
1887           mantissa = exponent & (1 << -nBits) - 1;
1888           exponent >>= -nBits;
1889           nBits += mantissaLength;
1890           for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
1891           if (exponent === 0) {
1892             exponent = 1 - eBias;
1893           } else if (exponent === eMax) {
1894             return mantissa ? NaN : sign ? -Infinity : Infinity;
1895           } else {
1896             mantissa = mantissa + pow(2, mantissaLength);
1897             exponent = exponent - eBias;
1898           } return (sign ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
1899         };
1900
1901         var ieee754 = {
1902           pack: pack,
1903           unpack: unpack
1904         };
1905
1906         // `Array.prototype.fill` method implementation
1907         // https://tc39.es/ecma262/#sec-array.prototype.fill
1908         var arrayFill = function fill(value /* , start = 0, end = @length */) {
1909           var O = toObject(this);
1910           var length = toLength(O.length);
1911           var argumentsLength = arguments.length;
1912           var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
1913           var end = argumentsLength > 2 ? arguments[2] : undefined;
1914           var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
1915           while (endPos > index) O[index++] = value;
1916           return O;
1917         };
1918
1919         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
1920         var defineProperty$3 = objectDefineProperty.f;
1921
1922
1923
1924
1925         var getInternalState$3 = internalState.get;
1926         var setInternalState$3 = internalState.set;
1927         var ARRAY_BUFFER = 'ArrayBuffer';
1928         var DATA_VIEW = 'DataView';
1929         var PROTOTYPE$2 = 'prototype';
1930         var WRONG_LENGTH = 'Wrong length';
1931         var WRONG_INDEX = 'Wrong index';
1932         var NativeArrayBuffer = global_1[ARRAY_BUFFER];
1933         var $ArrayBuffer = NativeArrayBuffer;
1934         var $DataView = global_1[DATA_VIEW];
1935         var $DataViewPrototype = $DataView && $DataView[PROTOTYPE$2];
1936         var ObjectPrototype$2 = Object.prototype;
1937         var RangeError$1 = global_1.RangeError;
1938
1939         var packIEEE754 = ieee754.pack;
1940         var unpackIEEE754 = ieee754.unpack;
1941
1942         var packInt8 = function (number) {
1943           return [number & 0xFF];
1944         };
1945
1946         var packInt16 = function (number) {
1947           return [number & 0xFF, number >> 8 & 0xFF];
1948         };
1949
1950         var packInt32 = function (number) {
1951           return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
1952         };
1953
1954         var unpackInt32 = function (buffer) {
1955           return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
1956         };
1957
1958         var packFloat32 = function (number) {
1959           return packIEEE754(number, 23, 4);
1960         };
1961
1962         var packFloat64 = function (number) {
1963           return packIEEE754(number, 52, 8);
1964         };
1965
1966         var addGetter = function (Constructor, key) {
1967           defineProperty$3(Constructor[PROTOTYPE$2], key, { get: function () { return getInternalState$3(this)[key]; } });
1968         };
1969
1970         var get$1 = function (view, count, index, isLittleEndian) {
1971           var intIndex = toIndex(index);
1972           var store = getInternalState$3(view);
1973           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1974           var bytes = getInternalState$3(store.buffer).bytes;
1975           var start = intIndex + store.byteOffset;
1976           var pack = bytes.slice(start, start + count);
1977           return isLittleEndian ? pack : pack.reverse();
1978         };
1979
1980         var set$1 = function (view, count, index, conversion, value, isLittleEndian) {
1981           var intIndex = toIndex(index);
1982           var store = getInternalState$3(view);
1983           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1984           var bytes = getInternalState$3(store.buffer).bytes;
1985           var start = intIndex + store.byteOffset;
1986           var pack = conversion(+value);
1987           for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
1988         };
1989
1990         if (!arrayBufferNative) {
1991           $ArrayBuffer = function ArrayBuffer(length) {
1992             anInstance(this, $ArrayBuffer, ARRAY_BUFFER);
1993             var byteLength = toIndex(length);
1994             setInternalState$3(this, {
1995               bytes: arrayFill.call(new Array(byteLength), 0),
1996               byteLength: byteLength
1997             });
1998             if (!descriptors) this.byteLength = byteLength;
1999           };
2000
2001           $DataView = function DataView(buffer, byteOffset, byteLength) {
2002             anInstance(this, $DataView, DATA_VIEW);
2003             anInstance(buffer, $ArrayBuffer, DATA_VIEW);
2004             var bufferLength = getInternalState$3(buffer).byteLength;
2005             var offset = toInteger(byteOffset);
2006             if (offset < 0 || offset > bufferLength) throw RangeError$1('Wrong offset');
2007             byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
2008             if (offset + byteLength > bufferLength) throw RangeError$1(WRONG_LENGTH);
2009             setInternalState$3(this, {
2010               buffer: buffer,
2011               byteLength: byteLength,
2012               byteOffset: offset
2013             });
2014             if (!descriptors) {
2015               this.buffer = buffer;
2016               this.byteLength = byteLength;
2017               this.byteOffset = offset;
2018             }
2019           };
2020
2021           if (descriptors) {
2022             addGetter($ArrayBuffer, 'byteLength');
2023             addGetter($DataView, 'buffer');
2024             addGetter($DataView, 'byteLength');
2025             addGetter($DataView, 'byteOffset');
2026           }
2027
2028           redefineAll($DataView[PROTOTYPE$2], {
2029             getInt8: function getInt8(byteOffset) {
2030               return get$1(this, 1, byteOffset)[0] << 24 >> 24;
2031             },
2032             getUint8: function getUint8(byteOffset) {
2033               return get$1(this, 1, byteOffset)[0];
2034             },
2035             getInt16: function getInt16(byteOffset /* , littleEndian */) {
2036               var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2037               return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
2038             },
2039             getUint16: function getUint16(byteOffset /* , littleEndian */) {
2040               var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2041               return bytes[1] << 8 | bytes[0];
2042             },
2043             getInt32: function getInt32(byteOffset /* , littleEndian */) {
2044               return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
2045             },
2046             getUint32: function getUint32(byteOffset /* , littleEndian */) {
2047               return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
2048             },
2049             getFloat32: function getFloat32(byteOffset /* , littleEndian */) {
2050               return unpackIEEE754(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
2051             },
2052             getFloat64: function getFloat64(byteOffset /* , littleEndian */) {
2053               return unpackIEEE754(get$1(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
2054             },
2055             setInt8: function setInt8(byteOffset, value) {
2056               set$1(this, 1, byteOffset, packInt8, value);
2057             },
2058             setUint8: function setUint8(byteOffset, value) {
2059               set$1(this, 1, byteOffset, packInt8, value);
2060             },
2061             setInt16: function setInt16(byteOffset, value /* , littleEndian */) {
2062               set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2063             },
2064             setUint16: function setUint16(byteOffset, value /* , littleEndian */) {
2065               set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2066             },
2067             setInt32: function setInt32(byteOffset, value /* , littleEndian */) {
2068               set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2069             },
2070             setUint32: function setUint32(byteOffset, value /* , littleEndian */) {
2071               set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2072             },
2073             setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {
2074               set$1(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
2075             },
2076             setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {
2077               set$1(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
2078             }
2079           });
2080         } else {
2081           /* eslint-disable no-new -- required for testing */
2082           if (!fails(function () {
2083             NativeArrayBuffer(1);
2084           }) || !fails(function () {
2085             new NativeArrayBuffer(-1);
2086           }) || fails(function () {
2087             new NativeArrayBuffer();
2088             new NativeArrayBuffer(1.5);
2089             new NativeArrayBuffer(NaN);
2090             return NativeArrayBuffer.name != ARRAY_BUFFER;
2091           })) {
2092           /* eslint-enable no-new -- required for testing */
2093             $ArrayBuffer = function ArrayBuffer(length) {
2094               anInstance(this, $ArrayBuffer);
2095               return new NativeArrayBuffer(toIndex(length));
2096             };
2097             var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE$2] = NativeArrayBuffer[PROTOTYPE$2];
2098             for (var keys$1 = getOwnPropertyNames(NativeArrayBuffer), j = 0, key; keys$1.length > j;) {
2099               if (!((key = keys$1[j++]) in $ArrayBuffer)) {
2100                 createNonEnumerableProperty($ArrayBuffer, key, NativeArrayBuffer[key]);
2101               }
2102             }
2103             ArrayBufferPrototype.constructor = $ArrayBuffer;
2104           }
2105
2106           // WebKit bug - the same parent prototype for typed arrays and data view
2107           if (objectSetPrototypeOf && objectGetPrototypeOf($DataViewPrototype) !== ObjectPrototype$2) {
2108             objectSetPrototypeOf($DataViewPrototype, ObjectPrototype$2);
2109           }
2110
2111           // iOS Safari 7.x bug
2112           var testView = new $DataView(new $ArrayBuffer(2));
2113           var nativeSetInt8 = $DataViewPrototype.setInt8;
2114           testView.setInt8(0, 2147483648);
2115           testView.setInt8(1, 2147483649);
2116           if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll($DataViewPrototype, {
2117             setInt8: function setInt8(byteOffset, value) {
2118               nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
2119             },
2120             setUint8: function setUint8(byteOffset, value) {
2121               nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
2122             }
2123           }, { unsafe: true });
2124         }
2125
2126         setToStringTag($ArrayBuffer, ARRAY_BUFFER);
2127         setToStringTag($DataView, DATA_VIEW);
2128
2129         var arrayBuffer = {
2130           ArrayBuffer: $ArrayBuffer,
2131           DataView: $DataView
2132         };
2133
2134         // `DataView` constructor
2135         // https://tc39.es/ecma262/#sec-dataview-constructor
2136         _export({ global: true, forced: !arrayBufferNative }, {
2137           DataView: arrayBuffer.DataView
2138         });
2139
2140         var SPECIES$1 = wellKnownSymbol('species');
2141
2142         // `SpeciesConstructor` abstract operation
2143         // https://tc39.es/ecma262/#sec-speciesconstructor
2144         var speciesConstructor = function (O, defaultConstructor) {
2145           var C = anObject(O).constructor;
2146           var S;
2147           return C === undefined || (S = anObject(C)[SPECIES$1]) == undefined ? defaultConstructor : aFunction$1(S);
2148         };
2149
2150         var ArrayBuffer$1 = arrayBuffer.ArrayBuffer;
2151         var DataView$1 = arrayBuffer.DataView;
2152         var nativeArrayBufferSlice = ArrayBuffer$1.prototype.slice;
2153
2154         var INCORRECT_SLICE = fails(function () {
2155           return !new ArrayBuffer$1(2).slice(1, undefined).byteLength;
2156         });
2157
2158         // `ArrayBuffer.prototype.slice` method
2159         // https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
2160         _export({ target: 'ArrayBuffer', proto: true, unsafe: true, forced: INCORRECT_SLICE }, {
2161           slice: function slice(start, end) {
2162             if (nativeArrayBufferSlice !== undefined && end === undefined) {
2163               return nativeArrayBufferSlice.call(anObject(this), start); // FF fix
2164             }
2165             var length = anObject(this).byteLength;
2166             var first = toAbsoluteIndex(start, length);
2167             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
2168             var result = new (speciesConstructor(this, ArrayBuffer$1))(toLength(fin - first));
2169             var viewSource = new DataView$1(this);
2170             var viewTarget = new DataView$1(result);
2171             var index = 0;
2172             while (first < fin) {
2173               viewTarget.setUint8(index++, viewSource.getUint8(first++));
2174             } return result;
2175           }
2176         });
2177
2178         var defineProperty$4 = objectDefineProperty.f;
2179
2180
2181
2182
2183
2184         var Int8Array$1 = global_1.Int8Array;
2185         var Int8ArrayPrototype = Int8Array$1 && Int8Array$1.prototype;
2186         var Uint8ClampedArray = global_1.Uint8ClampedArray;
2187         var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
2188         var TypedArray = Int8Array$1 && objectGetPrototypeOf(Int8Array$1);
2189         var TypedArrayPrototype = Int8ArrayPrototype && objectGetPrototypeOf(Int8ArrayPrototype);
2190         var ObjectPrototype$3 = Object.prototype;
2191         var isPrototypeOf = ObjectPrototype$3.isPrototypeOf;
2192
2193         var TO_STRING_TAG$4 = wellKnownSymbol('toStringTag');
2194         var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
2195         // Fixing native typed arrays in Opera Presto crashes the browser, see #595
2196         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferNative && !!objectSetPrototypeOf && classof(global_1.opera) !== 'Opera';
2197         var TYPED_ARRAY_TAG_REQIRED = false;
2198         var NAME;
2199
2200         var TypedArrayConstructorsList = {
2201           Int8Array: 1,
2202           Uint8Array: 1,
2203           Uint8ClampedArray: 1,
2204           Int16Array: 2,
2205           Uint16Array: 2,
2206           Int32Array: 4,
2207           Uint32Array: 4,
2208           Float32Array: 4,
2209           Float64Array: 8
2210         };
2211
2212         var BigIntArrayConstructorsList = {
2213           BigInt64Array: 8,
2214           BigUint64Array: 8
2215         };
2216
2217         var isView = function isView(it) {
2218           if (!isObject(it)) return false;
2219           var klass = classof(it);
2220           return klass === 'DataView'
2221             || has(TypedArrayConstructorsList, klass)
2222             || has(BigIntArrayConstructorsList, klass);
2223         };
2224
2225         var isTypedArray = function (it) {
2226           if (!isObject(it)) return false;
2227           var klass = classof(it);
2228           return has(TypedArrayConstructorsList, klass)
2229             || has(BigIntArrayConstructorsList, klass);
2230         };
2231
2232         var aTypedArray = function (it) {
2233           if (isTypedArray(it)) return it;
2234           throw TypeError('Target is not a typed array');
2235         };
2236
2237         var aTypedArrayConstructor = function (C) {
2238           if (objectSetPrototypeOf) {
2239             if (isPrototypeOf.call(TypedArray, C)) return C;
2240           } else for (var ARRAY in TypedArrayConstructorsList) if (has(TypedArrayConstructorsList, NAME)) {
2241             var TypedArrayConstructor = global_1[ARRAY];
2242             if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
2243               return C;
2244             }
2245           } throw TypeError('Target is not a typed array constructor');
2246         };
2247
2248         var exportTypedArrayMethod = function (KEY, property, forced) {
2249           if (!descriptors) return;
2250           if (forced) for (var ARRAY in TypedArrayConstructorsList) {
2251             var TypedArrayConstructor = global_1[ARRAY];
2252             if (TypedArrayConstructor && has(TypedArrayConstructor.prototype, KEY)) {
2253               delete TypedArrayConstructor.prototype[KEY];
2254             }
2255           }
2256           if (!TypedArrayPrototype[KEY] || forced) {
2257             redefine(TypedArrayPrototype, KEY, forced ? property
2258               : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property);
2259           }
2260         };
2261
2262         var exportTypedArrayStaticMethod = function (KEY, property, forced) {
2263           var ARRAY, TypedArrayConstructor;
2264           if (!descriptors) return;
2265           if (objectSetPrototypeOf) {
2266             if (forced) for (ARRAY in TypedArrayConstructorsList) {
2267               TypedArrayConstructor = global_1[ARRAY];
2268               if (TypedArrayConstructor && has(TypedArrayConstructor, KEY)) {
2269                 delete TypedArrayConstructor[KEY];
2270               }
2271             }
2272             if (!TypedArray[KEY] || forced) {
2273               // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
2274               try {
2275                 return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8Array$1[KEY] || property);
2276               } catch (error) { /* empty */ }
2277             } else return;
2278           }
2279           for (ARRAY in TypedArrayConstructorsList) {
2280             TypedArrayConstructor = global_1[ARRAY];
2281             if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
2282               redefine(TypedArrayConstructor, KEY, property);
2283             }
2284           }
2285         };
2286
2287         for (NAME in TypedArrayConstructorsList) {
2288           if (!global_1[NAME]) NATIVE_ARRAY_BUFFER_VIEWS = false;
2289         }
2290
2291         // WebKit bug - typed arrays constructors prototype is Object.prototype
2292         if (!NATIVE_ARRAY_BUFFER_VIEWS || typeof TypedArray != 'function' || TypedArray === Function.prototype) {
2293           // eslint-disable-next-line no-shadow -- safe
2294           TypedArray = function TypedArray() {
2295             throw TypeError('Incorrect invocation');
2296           };
2297           if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
2298             if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME], TypedArray);
2299           }
2300         }
2301
2302         if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype$3) {
2303           TypedArrayPrototype = TypedArray.prototype;
2304           if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
2305             if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME].prototype, TypedArrayPrototype);
2306           }
2307         }
2308
2309         // WebKit bug - one more object in Uint8ClampedArray prototype chain
2310         if (NATIVE_ARRAY_BUFFER_VIEWS && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
2311           objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
2312         }
2313
2314         if (descriptors && !has(TypedArrayPrototype, TO_STRING_TAG$4)) {
2315           TYPED_ARRAY_TAG_REQIRED = true;
2316           defineProperty$4(TypedArrayPrototype, TO_STRING_TAG$4, { get: function () {
2317             return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
2318           } });
2319           for (NAME in TypedArrayConstructorsList) if (global_1[NAME]) {
2320             createNonEnumerableProperty(global_1[NAME], TYPED_ARRAY_TAG, NAME);
2321           }
2322         }
2323
2324         var arrayBufferViewCore = {
2325           NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
2326           TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG,
2327           aTypedArray: aTypedArray,
2328           aTypedArrayConstructor: aTypedArrayConstructor,
2329           exportTypedArrayMethod: exportTypedArrayMethod,
2330           exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,
2331           isView: isView,
2332           isTypedArray: isTypedArray,
2333           TypedArray: TypedArray,
2334           TypedArrayPrototype: TypedArrayPrototype
2335         };
2336
2337         var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
2338
2339         // `ArrayBuffer.isView` method
2340         // https://tc39.es/ecma262/#sec-arraybuffer.isview
2341         _export({ target: 'ArrayBuffer', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS$1 }, {
2342           isView: arrayBufferViewCore.isView
2343         });
2344
2345         var SPECIES$2 = wellKnownSymbol('species');
2346
2347         var setSpecies = function (CONSTRUCTOR_NAME) {
2348           var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
2349           var defineProperty = objectDefineProperty.f;
2350
2351           if (descriptors && Constructor && !Constructor[SPECIES$2]) {
2352             defineProperty(Constructor, SPECIES$2, {
2353               configurable: true,
2354               get: function () { return this; }
2355             });
2356           }
2357         };
2358
2359         var ARRAY_BUFFER$1 = 'ArrayBuffer';
2360         var ArrayBuffer$2 = arrayBuffer[ARRAY_BUFFER$1];
2361         var NativeArrayBuffer$1 = global_1[ARRAY_BUFFER$1];
2362
2363         // `ArrayBuffer` constructor
2364         // https://tc39.es/ecma262/#sec-arraybuffer-constructor
2365         _export({ global: true, forced: NativeArrayBuffer$1 !== ArrayBuffer$2 }, {
2366           ArrayBuffer: ArrayBuffer$2
2367         });
2368
2369         setSpecies(ARRAY_BUFFER$1);
2370
2371         var arrayMethodIsStrict = function (METHOD_NAME, argument) {
2372           var method = [][METHOD_NAME];
2373           return !!method && fails(function () {
2374             // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
2375             method.call(null, argument || function () { throw 1; }, 1);
2376           });
2377         };
2378
2379         var $indexOf = arrayIncludes.indexOf;
2380
2381
2382         var nativeIndexOf = [].indexOf;
2383
2384         var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
2385         var STRICT_METHOD = arrayMethodIsStrict('indexOf');
2386
2387         // `Array.prototype.indexOf` method
2388         // https://tc39.es/ecma262/#sec-array.prototype.indexof
2389         _export({ target: 'Array', proto: true, forced: NEGATIVE_ZERO || !STRICT_METHOD }, {
2390           indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
2391             return NEGATIVE_ZERO
2392               // convert -0 to +0
2393               ? nativeIndexOf.apply(this, arguments) || 0
2394               : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
2395           }
2396         });
2397
2398         var SPECIES$3 = wellKnownSymbol('species');
2399
2400         var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
2401           // We can't use this feature detection in V8 since it causes
2402           // deoptimization and serious performance degradation
2403           // https://github.com/zloirock/core-js/issues/677
2404           return engineV8Version >= 51 || !fails(function () {
2405             var array = [];
2406             var constructor = array.constructor = {};
2407             constructor[SPECIES$3] = function () {
2408               return { foo: 1 };
2409             };
2410             return array[METHOD_NAME](Boolean).foo !== 1;
2411           });
2412         };
2413
2414         var $map = arrayIteration.map;
2415
2416
2417         var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('map');
2418
2419         // `Array.prototype.map` method
2420         // https://tc39.es/ecma262/#sec-array.prototype.map
2421         // with adding support of @@species
2422         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT }, {
2423           map: function map(callbackfn /* , thisArg */) {
2424             return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2425           }
2426         });
2427
2428         var $forEach$1 = arrayIteration.forEach;
2429
2430
2431         var STRICT_METHOD$1 = arrayMethodIsStrict('forEach');
2432
2433         // `Array.prototype.forEach` method implementation
2434         // https://tc39.es/ecma262/#sec-array.prototype.foreach
2435         var arrayForEach = !STRICT_METHOD$1 ? function forEach(callbackfn /* , thisArg */) {
2436           return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2437         } : [].forEach;
2438
2439         // `Array.prototype.forEach` method
2440         // https://tc39.es/ecma262/#sec-array.prototype.foreach
2441         _export({ target: 'Array', proto: true, forced: [].forEach != arrayForEach }, {
2442           forEach: arrayForEach
2443         });
2444
2445         for (var COLLECTION_NAME$1 in domIterables) {
2446           var Collection$1 = global_1[COLLECTION_NAME$1];
2447           var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
2448           // some Chrome versions have non-configurable methods on DOMTokenList
2449           if (CollectionPrototype$1 && CollectionPrototype$1.forEach !== arrayForEach) try {
2450             createNonEnumerableProperty(CollectionPrototype$1, 'forEach', arrayForEach);
2451           } catch (error) {
2452             CollectionPrototype$1.forEach = arrayForEach;
2453           }
2454         }
2455
2456         // `Array.isArray` method
2457         // https://tc39.es/ecma262/#sec-array.isarray
2458         _export({ target: 'Array', stat: true }, {
2459           isArray: isArray
2460         });
2461
2462         var nativeGetOwnPropertyNames$2 = objectGetOwnPropertyNamesExternal.f;
2463
2464         var FAILS_ON_PRIMITIVES = fails(function () { return !Object.getOwnPropertyNames(1); });
2465
2466         // `Object.getOwnPropertyNames` method
2467         // https://tc39.es/ecma262/#sec-object.getownpropertynames
2468         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
2469           getOwnPropertyNames: nativeGetOwnPropertyNames$2
2470         });
2471
2472         var nativePromiseConstructor = global_1.Promise;
2473
2474         var ITERATOR$3 = wellKnownSymbol('iterator');
2475         var ArrayPrototype$1 = Array.prototype;
2476
2477         // check on default Array iterator
2478         var isArrayIteratorMethod = function (it) {
2479           return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$3] === it);
2480         };
2481
2482         var ITERATOR$4 = wellKnownSymbol('iterator');
2483
2484         var getIteratorMethod = function (it) {
2485           if (it != undefined) return it[ITERATOR$4]
2486             || it['@@iterator']
2487             || iterators[classof(it)];
2488         };
2489
2490         var iteratorClose = function (iterator) {
2491           var returnMethod = iterator['return'];
2492           if (returnMethod !== undefined) {
2493             return anObject(returnMethod.call(iterator)).value;
2494           }
2495         };
2496
2497         var Result = function (stopped, result) {
2498           this.stopped = stopped;
2499           this.result = result;
2500         };
2501
2502         var iterate = function (iterable, unboundFunction, options) {
2503           var that = options && options.that;
2504           var AS_ENTRIES = !!(options && options.AS_ENTRIES);
2505           var IS_ITERATOR = !!(options && options.IS_ITERATOR);
2506           var INTERRUPTED = !!(options && options.INTERRUPTED);
2507           var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
2508           var iterator, iterFn, index, length, result, next, step;
2509
2510           var stop = function (condition) {
2511             if (iterator) iteratorClose(iterator);
2512             return new Result(true, condition);
2513           };
2514
2515           var callFn = function (value) {
2516             if (AS_ENTRIES) {
2517               anObject(value);
2518               return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
2519             } return INTERRUPTED ? fn(value, stop) : fn(value);
2520           };
2521
2522           if (IS_ITERATOR) {
2523             iterator = iterable;
2524           } else {
2525             iterFn = getIteratorMethod(iterable);
2526             if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
2527             // optimisation for array iterators
2528             if (isArrayIteratorMethod(iterFn)) {
2529               for (index = 0, length = toLength(iterable.length); length > index; index++) {
2530                 result = callFn(iterable[index]);
2531                 if (result && result instanceof Result) return result;
2532               } return new Result(false);
2533             }
2534             iterator = iterFn.call(iterable);
2535           }
2536
2537           next = iterator.next;
2538           while (!(step = next.call(iterator)).done) {
2539             try {
2540               result = callFn(step.value);
2541             } catch (error) {
2542               iteratorClose(iterator);
2543               throw error;
2544             }
2545             if (typeof result == 'object' && result && result instanceof Result) return result;
2546           } return new Result(false);
2547         };
2548
2549         var ITERATOR$5 = wellKnownSymbol('iterator');
2550         var SAFE_CLOSING = false;
2551
2552         try {
2553           var called = 0;
2554           var iteratorWithReturn = {
2555             next: function () {
2556               return { done: !!called++ };
2557             },
2558             'return': function () {
2559               SAFE_CLOSING = true;
2560             }
2561           };
2562           iteratorWithReturn[ITERATOR$5] = function () {
2563             return this;
2564           };
2565           // eslint-disable-next-line no-throw-literal -- required for testing
2566           Array.from(iteratorWithReturn, function () { throw 2; });
2567         } catch (error) { /* empty */ }
2568
2569         var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
2570           if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2571           var ITERATION_SUPPORT = false;
2572           try {
2573             var object = {};
2574             object[ITERATOR$5] = function () {
2575               return {
2576                 next: function () {
2577                   return { done: ITERATION_SUPPORT = true };
2578                 }
2579               };
2580             };
2581             exec(object);
2582           } catch (error) { /* empty */ }
2583           return ITERATION_SUPPORT;
2584         };
2585
2586         var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);
2587
2588         var location$1 = global_1.location;
2589         var set$2 = global_1.setImmediate;
2590         var clear = global_1.clearImmediate;
2591         var process$2 = global_1.process;
2592         var MessageChannel = global_1.MessageChannel;
2593         var Dispatch = global_1.Dispatch;
2594         var counter = 0;
2595         var queue = {};
2596         var ONREADYSTATECHANGE = 'onreadystatechange';
2597         var defer, channel, port;
2598
2599         var run = function (id) {
2600           // eslint-disable-next-line no-prototype-builtins -- safe
2601           if (queue.hasOwnProperty(id)) {
2602             var fn = queue[id];
2603             delete queue[id];
2604             fn();
2605           }
2606         };
2607
2608         var runner = function (id) {
2609           return function () {
2610             run(id);
2611           };
2612         };
2613
2614         var listener = function (event) {
2615           run(event.data);
2616         };
2617
2618         var post = function (id) {
2619           // old engines have not location.origin
2620           global_1.postMessage(id + '', location$1.protocol + '//' + location$1.host);
2621         };
2622
2623         // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
2624         if (!set$2 || !clear) {
2625           set$2 = function setImmediate(fn) {
2626             var args = [];
2627             var i = 1;
2628             while (arguments.length > i) args.push(arguments[i++]);
2629             queue[++counter] = function () {
2630               // eslint-disable-next-line no-new-func -- spec requirement
2631               (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
2632             };
2633             defer(counter);
2634             return counter;
2635           };
2636           clear = function clearImmediate(id) {
2637             delete queue[id];
2638           };
2639           // Node.js 0.8-
2640           if (engineIsNode) {
2641             defer = function (id) {
2642               process$2.nextTick(runner(id));
2643             };
2644           // Sphere (JS game engine) Dispatch API
2645           } else if (Dispatch && Dispatch.now) {
2646             defer = function (id) {
2647               Dispatch.now(runner(id));
2648             };
2649           // Browsers with MessageChannel, includes WebWorkers
2650           // except iOS - https://github.com/zloirock/core-js/issues/624
2651           } else if (MessageChannel && !engineIsIos) {
2652             channel = new MessageChannel();
2653             port = channel.port2;
2654             channel.port1.onmessage = listener;
2655             defer = functionBindContext(port.postMessage, port, 1);
2656           // Browsers with postMessage, skip WebWorkers
2657           // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
2658           } else if (
2659             global_1.addEventListener &&
2660             typeof postMessage == 'function' &&
2661             !global_1.importScripts &&
2662             location$1 && location$1.protocol !== 'file:' &&
2663             !fails(post)
2664           ) {
2665             defer = post;
2666             global_1.addEventListener('message', listener, false);
2667           // IE8-
2668           } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
2669             defer = function (id) {
2670               html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
2671                 html.removeChild(this);
2672                 run(id);
2673               };
2674             };
2675           // Rest old browsers
2676           } else {
2677             defer = function (id) {
2678               setTimeout(runner(id), 0);
2679             };
2680           }
2681         }
2682
2683         var task = {
2684           set: set$2,
2685           clear: clear
2686         };
2687
2688         var engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(engineUserAgent);
2689
2690         var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
2691         var macrotask = task.set;
2692
2693
2694
2695
2696         var MutationObserver = global_1.MutationObserver || global_1.WebKitMutationObserver;
2697         var document$2 = global_1.document;
2698         var process$3 = global_1.process;
2699         var Promise$1 = global_1.Promise;
2700         // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
2701         var queueMicrotaskDescriptor = getOwnPropertyDescriptor$2(global_1, 'queueMicrotask');
2702         var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
2703
2704         var flush, head, last, notify, toggle, node, promise, then;
2705
2706         // modern engines have queueMicrotask method
2707         if (!queueMicrotask) {
2708           flush = function () {
2709             var parent, fn;
2710             if (engineIsNode && (parent = process$3.domain)) parent.exit();
2711             while (head) {
2712               fn = head.fn;
2713               head = head.next;
2714               try {
2715                 fn();
2716               } catch (error) {
2717                 if (head) notify();
2718                 else last = undefined;
2719                 throw error;
2720               }
2721             } last = undefined;
2722             if (parent) parent.enter();
2723           };
2724
2725           // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
2726           // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898
2727           if (!engineIsIos && !engineIsNode && !engineIsWebosWebkit && MutationObserver && document$2) {
2728             toggle = true;
2729             node = document$2.createTextNode('');
2730             new MutationObserver(flush).observe(node, { characterData: true });
2731             notify = function () {
2732               node.data = toggle = !toggle;
2733             };
2734           // environments with maybe non-completely correct, but existent Promise
2735           } else if (Promise$1 && Promise$1.resolve) {
2736             // Promise.resolve without an argument throws an error in LG WebOS 2
2737             promise = Promise$1.resolve(undefined);
2738             then = promise.then;
2739             notify = function () {
2740               then.call(promise, flush);
2741             };
2742           // Node.js without promises
2743           } else if (engineIsNode) {
2744             notify = function () {
2745               process$3.nextTick(flush);
2746             };
2747           // for other environments - macrotask based on:
2748           // - setImmediate
2749           // - MessageChannel
2750           // - window.postMessag
2751           // - onreadystatechange
2752           // - setTimeout
2753           } else {
2754             notify = function () {
2755               // strange IE + webpack dev server bug - use .call(global)
2756               macrotask.call(global_1, flush);
2757             };
2758           }
2759         }
2760
2761         var microtask = queueMicrotask || function (fn) {
2762           var task = { fn: fn, next: undefined };
2763           if (last) last.next = task;
2764           if (!head) {
2765             head = task;
2766             notify();
2767           } last = task;
2768         };
2769
2770         var PromiseCapability = function (C) {
2771           var resolve, reject;
2772           this.promise = new C(function ($$resolve, $$reject) {
2773             if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
2774             resolve = $$resolve;
2775             reject = $$reject;
2776           });
2777           this.resolve = aFunction$1(resolve);
2778           this.reject = aFunction$1(reject);
2779         };
2780
2781         // 25.4.1.5 NewPromiseCapability(C)
2782         var f$7 = function (C) {
2783           return new PromiseCapability(C);
2784         };
2785
2786         var newPromiseCapability = {
2787                 f: f$7
2788         };
2789
2790         var promiseResolve = function (C, x) {
2791           anObject(C);
2792           if (isObject(x) && x.constructor === C) return x;
2793           var promiseCapability = newPromiseCapability.f(C);
2794           var resolve = promiseCapability.resolve;
2795           resolve(x);
2796           return promiseCapability.promise;
2797         };
2798
2799         var hostReportErrors = function (a, b) {
2800           var console = global_1.console;
2801           if (console && console.error) {
2802             arguments.length === 1 ? console.error(a) : console.error(a, b);
2803           }
2804         };
2805
2806         var perform = function (exec) {
2807           try {
2808             return { error: false, value: exec() };
2809           } catch (error) {
2810             return { error: true, value: error };
2811           }
2812         };
2813
2814         var task$1 = task.set;
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826         var SPECIES$4 = wellKnownSymbol('species');
2827         var PROMISE = 'Promise';
2828         var getInternalState$4 = internalState.get;
2829         var setInternalState$4 = internalState.set;
2830         var getInternalPromiseState = internalState.getterFor(PROMISE);
2831         var PromiseConstructor = nativePromiseConstructor;
2832         var TypeError$1 = global_1.TypeError;
2833         var document$3 = global_1.document;
2834         var process$4 = global_1.process;
2835         var $fetch = getBuiltIn('fetch');
2836         var newPromiseCapability$1 = newPromiseCapability.f;
2837         var newGenericPromiseCapability = newPromiseCapability$1;
2838         var DISPATCH_EVENT = !!(document$3 && document$3.createEvent && global_1.dispatchEvent);
2839         var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
2840         var UNHANDLED_REJECTION = 'unhandledrejection';
2841         var REJECTION_HANDLED = 'rejectionhandled';
2842         var PENDING = 0;
2843         var FULFILLED = 1;
2844         var REJECTED = 2;
2845         var HANDLED = 1;
2846         var UNHANDLED = 2;
2847         var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
2848
2849         var FORCED = isForced_1(PROMISE, function () {
2850           var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
2851           if (!GLOBAL_CORE_JS_PROMISE) {
2852             // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
2853             // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
2854             // We can't detect it synchronously, so just check versions
2855             if (engineV8Version === 66) return true;
2856             // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
2857             if (!engineIsNode && !NATIVE_REJECTION_EVENT) return true;
2858           }
2859           // We can't use @@species feature detection in V8 since it causes
2860           // deoptimization and performance degradation
2861           // https://github.com/zloirock/core-js/issues/679
2862           if (engineV8Version >= 51 && /native code/.test(PromiseConstructor)) return false;
2863           // Detect correctness of subclassing with @@species support
2864           var promise = PromiseConstructor.resolve(1);
2865           var FakePromise = function (exec) {
2866             exec(function () { /* empty */ }, function () { /* empty */ });
2867           };
2868           var constructor = promise.constructor = {};
2869           constructor[SPECIES$4] = FakePromise;
2870           return !(promise.then(function () { /* empty */ }) instanceof FakePromise);
2871         });
2872
2873         var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) {
2874           PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
2875         });
2876
2877         // helpers
2878         var isThenable = function (it) {
2879           var then;
2880           return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
2881         };
2882
2883         var notify$1 = function (state, isReject) {
2884           if (state.notified) return;
2885           state.notified = true;
2886           var chain = state.reactions;
2887           microtask(function () {
2888             var value = state.value;
2889             var ok = state.state == FULFILLED;
2890             var index = 0;
2891             // variable length - can't use forEach
2892             while (chain.length > index) {
2893               var reaction = chain[index++];
2894               var handler = ok ? reaction.ok : reaction.fail;
2895               var resolve = reaction.resolve;
2896               var reject = reaction.reject;
2897               var domain = reaction.domain;
2898               var result, then, exited;
2899               try {
2900                 if (handler) {
2901                   if (!ok) {
2902                     if (state.rejection === UNHANDLED) onHandleUnhandled(state);
2903                     state.rejection = HANDLED;
2904                   }
2905                   if (handler === true) result = value;
2906                   else {
2907                     if (domain) domain.enter();
2908                     result = handler(value); // can throw
2909                     if (domain) {
2910                       domain.exit();
2911                       exited = true;
2912                     }
2913                   }
2914                   if (result === reaction.promise) {
2915                     reject(TypeError$1('Promise-chain cycle'));
2916                   } else if (then = isThenable(result)) {
2917                     then.call(result, resolve, reject);
2918                   } else resolve(result);
2919                 } else reject(value);
2920               } catch (error) {
2921                 if (domain && !exited) domain.exit();
2922                 reject(error);
2923               }
2924             }
2925             state.reactions = [];
2926             state.notified = false;
2927             if (isReject && !state.rejection) onUnhandled(state);
2928           });
2929         };
2930
2931         var dispatchEvent = function (name, promise, reason) {
2932           var event, handler;
2933           if (DISPATCH_EVENT) {
2934             event = document$3.createEvent('Event');
2935             event.promise = promise;
2936             event.reason = reason;
2937             event.initEvent(name, false, true);
2938             global_1.dispatchEvent(event);
2939           } else event = { promise: promise, reason: reason };
2940           if (!NATIVE_REJECTION_EVENT && (handler = global_1['on' + name])) handler(event);
2941           else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
2942         };
2943
2944         var onUnhandled = function (state) {
2945           task$1.call(global_1, function () {
2946             var promise = state.facade;
2947             var value = state.value;
2948             var IS_UNHANDLED = isUnhandled(state);
2949             var result;
2950             if (IS_UNHANDLED) {
2951               result = perform(function () {
2952                 if (engineIsNode) {
2953                   process$4.emit('unhandledRejection', value, promise);
2954                 } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
2955               });
2956               // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
2957               state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;
2958               if (result.error) throw result.value;
2959             }
2960           });
2961         };
2962
2963         var isUnhandled = function (state) {
2964           return state.rejection !== HANDLED && !state.parent;
2965         };
2966
2967         var onHandleUnhandled = function (state) {
2968           task$1.call(global_1, function () {
2969             var promise = state.facade;
2970             if (engineIsNode) {
2971               process$4.emit('rejectionHandled', promise);
2972             } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
2973           });
2974         };
2975
2976         var bind = function (fn, state, unwrap) {
2977           return function (value) {
2978             fn(state, value, unwrap);
2979           };
2980         };
2981
2982         var internalReject = function (state, value, unwrap) {
2983           if (state.done) return;
2984           state.done = true;
2985           if (unwrap) state = unwrap;
2986           state.value = value;
2987           state.state = REJECTED;
2988           notify$1(state, true);
2989         };
2990
2991         var internalResolve = function (state, value, unwrap) {
2992           if (state.done) return;
2993           state.done = true;
2994           if (unwrap) state = unwrap;
2995           try {
2996             if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
2997             var then = isThenable(value);
2998             if (then) {
2999               microtask(function () {
3000                 var wrapper = { done: false };
3001                 try {
3002                   then.call(value,
3003                     bind(internalResolve, wrapper, state),
3004                     bind(internalReject, wrapper, state)
3005                   );
3006                 } catch (error) {
3007                   internalReject(wrapper, error, state);
3008                 }
3009               });
3010             } else {
3011               state.value = value;
3012               state.state = FULFILLED;
3013               notify$1(state, false);
3014             }
3015           } catch (error) {
3016             internalReject({ done: false }, error, state);
3017           }
3018         };
3019
3020         // constructor polyfill
3021         if (FORCED) {
3022           // 25.4.3.1 Promise(executor)
3023           PromiseConstructor = function Promise(executor) {
3024             anInstance(this, PromiseConstructor, PROMISE);
3025             aFunction$1(executor);
3026             Internal.call(this);
3027             var state = getInternalState$4(this);
3028             try {
3029               executor(bind(internalResolve, state), bind(internalReject, state));
3030             } catch (error) {
3031               internalReject(state, error);
3032             }
3033           };
3034           // eslint-disable-next-line no-unused-vars -- required for `.length`
3035           Internal = function Promise(executor) {
3036             setInternalState$4(this, {
3037               type: PROMISE,
3038               done: false,
3039               notified: false,
3040               parent: false,
3041               reactions: [],
3042               rejection: false,
3043               state: PENDING,
3044               value: undefined
3045             });
3046           };
3047           Internal.prototype = redefineAll(PromiseConstructor.prototype, {
3048             // `Promise.prototype.then` method
3049             // https://tc39.es/ecma262/#sec-promise.prototype.then
3050             then: function then(onFulfilled, onRejected) {
3051               var state = getInternalPromiseState(this);
3052               var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
3053               reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
3054               reaction.fail = typeof onRejected == 'function' && onRejected;
3055               reaction.domain = engineIsNode ? process$4.domain : undefined;
3056               state.parent = true;
3057               state.reactions.push(reaction);
3058               if (state.state != PENDING) notify$1(state, false);
3059               return reaction.promise;
3060             },
3061             // `Promise.prototype.catch` method
3062             // https://tc39.es/ecma262/#sec-promise.prototype.catch
3063             'catch': function (onRejected) {
3064               return this.then(undefined, onRejected);
3065             }
3066           });
3067           OwnPromiseCapability = function () {
3068             var promise = new Internal();
3069             var state = getInternalState$4(promise);
3070             this.promise = promise;
3071             this.resolve = bind(internalResolve, state);
3072             this.reject = bind(internalReject, state);
3073           };
3074           newPromiseCapability.f = newPromiseCapability$1 = function (C) {
3075             return C === PromiseConstructor || C === PromiseWrapper
3076               ? new OwnPromiseCapability(C)
3077               : newGenericPromiseCapability(C);
3078           };
3079
3080           if ( typeof nativePromiseConstructor == 'function') {
3081             nativeThen = nativePromiseConstructor.prototype.then;
3082
3083             // wrap native Promise#then for native async functions
3084             redefine(nativePromiseConstructor.prototype, 'then', function then(onFulfilled, onRejected) {
3085               var that = this;
3086               return new PromiseConstructor(function (resolve, reject) {
3087                 nativeThen.call(that, resolve, reject);
3088               }).then(onFulfilled, onRejected);
3089             // https://github.com/zloirock/core-js/issues/640
3090             }, { unsafe: true });
3091
3092             // wrap fetch result
3093             if (typeof $fetch == 'function') _export({ global: true, enumerable: true, forced: true }, {
3094               // eslint-disable-next-line no-unused-vars -- required for `.length`
3095               fetch: function fetch(input /* , init */) {
3096                 return promiseResolve(PromiseConstructor, $fetch.apply(global_1, arguments));
3097               }
3098             });
3099           }
3100         }
3101
3102         _export({ global: true, wrap: true, forced: FORCED }, {
3103           Promise: PromiseConstructor
3104         });
3105
3106         setToStringTag(PromiseConstructor, PROMISE, false);
3107         setSpecies(PROMISE);
3108
3109         PromiseWrapper = getBuiltIn(PROMISE);
3110
3111         // statics
3112         _export({ target: PROMISE, stat: true, forced: FORCED }, {
3113           // `Promise.reject` method
3114           // https://tc39.es/ecma262/#sec-promise.reject
3115           reject: function reject(r) {
3116             var capability = newPromiseCapability$1(this);
3117             capability.reject.call(undefined, r);
3118             return capability.promise;
3119           }
3120         });
3121
3122         _export({ target: PROMISE, stat: true, forced:  FORCED }, {
3123           // `Promise.resolve` method
3124           // https://tc39.es/ecma262/#sec-promise.resolve
3125           resolve: function resolve(x) {
3126             return promiseResolve( this, x);
3127           }
3128         });
3129
3130         _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION }, {
3131           // `Promise.all` method
3132           // https://tc39.es/ecma262/#sec-promise.all
3133           all: function all(iterable) {
3134             var C = this;
3135             var capability = newPromiseCapability$1(C);
3136             var resolve = capability.resolve;
3137             var reject = capability.reject;
3138             var result = perform(function () {
3139               var $promiseResolve = aFunction$1(C.resolve);
3140               var values = [];
3141               var counter = 0;
3142               var remaining = 1;
3143               iterate(iterable, function (promise) {
3144                 var index = counter++;
3145                 var alreadyCalled = false;
3146                 values.push(undefined);
3147                 remaining++;
3148                 $promiseResolve.call(C, promise).then(function (value) {
3149                   if (alreadyCalled) return;
3150                   alreadyCalled = true;
3151                   values[index] = value;
3152                   --remaining || resolve(values);
3153                 }, reject);
3154               });
3155               --remaining || resolve(values);
3156             });
3157             if (result.error) reject(result.value);
3158             return capability.promise;
3159           },
3160           // `Promise.race` method
3161           // https://tc39.es/ecma262/#sec-promise.race
3162           race: function race(iterable) {
3163             var C = this;
3164             var capability = newPromiseCapability$1(C);
3165             var reject = capability.reject;
3166             var result = perform(function () {
3167               var $promiseResolve = aFunction$1(C.resolve);
3168               iterate(iterable, function (promise) {
3169                 $promiseResolve.call(C, promise).then(capability.resolve, reject);
3170               });
3171             });
3172             if (result.error) reject(result.value);
3173             return capability.promise;
3174           }
3175         });
3176
3177         /* eslint-disable no-new -- required for testing */
3178
3179
3180
3181         var NATIVE_ARRAY_BUFFER_VIEWS$2 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3182
3183         var ArrayBuffer$3 = global_1.ArrayBuffer;
3184         var Int8Array$2 = global_1.Int8Array;
3185
3186         var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS$2 || !fails(function () {
3187           Int8Array$2(1);
3188         }) || !fails(function () {
3189           new Int8Array$2(-1);
3190         }) || !checkCorrectnessOfIteration(function (iterable) {
3191           new Int8Array$2();
3192           new Int8Array$2(null);
3193           new Int8Array$2(1.5);
3194           new Int8Array$2(iterable);
3195         }, true) || fails(function () {
3196           // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
3197           return new Int8Array$2(new ArrayBuffer$3(2), 1, undefined).length !== 1;
3198         });
3199
3200         var toPositiveInteger = function (it) {
3201           var result = toInteger(it);
3202           if (result < 0) throw RangeError("The argument can't be less than 0");
3203           return result;
3204         };
3205
3206         var toOffset = function (it, BYTES) {
3207           var offset = toPositiveInteger(it);
3208           if (offset % BYTES) throw RangeError('Wrong offset');
3209           return offset;
3210         };
3211
3212         var aTypedArrayConstructor$1 = arrayBufferViewCore.aTypedArrayConstructor;
3213
3214         var typedArrayFrom = function from(source /* , mapfn, thisArg */) {
3215           var O = toObject(source);
3216           var argumentsLength = arguments.length;
3217           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
3218           var mapping = mapfn !== undefined;
3219           var iteratorMethod = getIteratorMethod(O);
3220           var i, length, result, step, iterator, next;
3221           if (iteratorMethod != undefined && !isArrayIteratorMethod(iteratorMethod)) {
3222             iterator = iteratorMethod.call(O);
3223             next = iterator.next;
3224             O = [];
3225             while (!(step = next.call(iterator)).done) {
3226               O.push(step.value);
3227             }
3228           }
3229           if (mapping && argumentsLength > 2) {
3230             mapfn = functionBindContext(mapfn, arguments[2], 2);
3231           }
3232           length = toLength(O.length);
3233           result = new (aTypedArrayConstructor$1(this))(length);
3234           for (i = 0; length > i; i++) {
3235             result[i] = mapping ? mapfn(O[i], i) : O[i];
3236           }
3237           return result;
3238         };
3239
3240         // makes subclassing work correct for wrapped built-ins
3241         var inheritIfRequired = function ($this, dummy, Wrapper) {
3242           var NewTarget, NewTargetPrototype;
3243           if (
3244             // it can work only with native `setPrototypeOf`
3245             objectSetPrototypeOf &&
3246             // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
3247             typeof (NewTarget = dummy.constructor) == 'function' &&
3248             NewTarget !== Wrapper &&
3249             isObject(NewTargetPrototype = NewTarget.prototype) &&
3250             NewTargetPrototype !== Wrapper.prototype
3251           ) objectSetPrototypeOf($this, NewTargetPrototype);
3252           return $this;
3253         };
3254
3255         var typedArrayConstructor = createCommonjsModule(function (module) {
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
3275
3276         var forEach = arrayIteration.forEach;
3277
3278
3279
3280
3281
3282
3283         var getInternalState = internalState.get;
3284         var setInternalState = internalState.set;
3285         var nativeDefineProperty = objectDefineProperty.f;
3286         var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
3287         var round = Math.round;
3288         var RangeError = global_1.RangeError;
3289         var ArrayBuffer = arrayBuffer.ArrayBuffer;
3290         var DataView = arrayBuffer.DataView;
3291         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3292         var TYPED_ARRAY_TAG = arrayBufferViewCore.TYPED_ARRAY_TAG;
3293         var TypedArray = arrayBufferViewCore.TypedArray;
3294         var TypedArrayPrototype = arrayBufferViewCore.TypedArrayPrototype;
3295         var aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;
3296         var isTypedArray = arrayBufferViewCore.isTypedArray;
3297         var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
3298         var WRONG_LENGTH = 'Wrong length';
3299
3300         var fromList = function (C, list) {
3301           var index = 0;
3302           var length = list.length;
3303           var result = new (aTypedArrayConstructor(C))(length);
3304           while (length > index) result[index] = list[index++];
3305           return result;
3306         };
3307
3308         var addGetter = function (it, key) {
3309           nativeDefineProperty(it, key, { get: function () {
3310             return getInternalState(this)[key];
3311           } });
3312         };
3313
3314         var isArrayBuffer = function (it) {
3315           var klass;
3316           return it instanceof ArrayBuffer || (klass = classof(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
3317         };
3318
3319         var isTypedArrayIndex = function (target, key) {
3320           return isTypedArray(target)
3321             && typeof key != 'symbol'
3322             && key in target
3323             && String(+key) == String(key);
3324         };
3325
3326         var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
3327           return isTypedArrayIndex(target, key = toPrimitive(key, true))
3328             ? createPropertyDescriptor(2, target[key])
3329             : nativeGetOwnPropertyDescriptor(target, key);
3330         };
3331
3332         var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
3333           if (isTypedArrayIndex(target, key = toPrimitive(key, true))
3334             && isObject(descriptor)
3335             && has(descriptor, 'value')
3336             && !has(descriptor, 'get')
3337             && !has(descriptor, 'set')
3338             // TODO: add validation descriptor w/o calling accessors
3339             && !descriptor.configurable
3340             && (!has(descriptor, 'writable') || descriptor.writable)
3341             && (!has(descriptor, 'enumerable') || descriptor.enumerable)
3342           ) {
3343             target[key] = descriptor.value;
3344             return target;
3345           } return nativeDefineProperty(target, key, descriptor);
3346         };
3347
3348         if (descriptors) {
3349           if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3350             objectGetOwnPropertyDescriptor.f = wrappedGetOwnPropertyDescriptor;
3351             objectDefineProperty.f = wrappedDefineProperty;
3352             addGetter(TypedArrayPrototype, 'buffer');
3353             addGetter(TypedArrayPrototype, 'byteOffset');
3354             addGetter(TypedArrayPrototype, 'byteLength');
3355             addGetter(TypedArrayPrototype, 'length');
3356           }
3357
3358           _export({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {
3359             getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
3360             defineProperty: wrappedDefineProperty
3361           });
3362
3363           module.exports = function (TYPE, wrapper, CLAMPED) {
3364             var BYTES = TYPE.match(/\d+$/)[0] / 8;
3365             var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
3366             var GETTER = 'get' + TYPE;
3367             var SETTER = 'set' + TYPE;
3368             var NativeTypedArrayConstructor = global_1[CONSTRUCTOR_NAME];
3369             var TypedArrayConstructor = NativeTypedArrayConstructor;
3370             var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
3371             var exported = {};
3372
3373             var getter = function (that, index) {
3374               var data = getInternalState(that);
3375               return data.view[GETTER](index * BYTES + data.byteOffset, true);
3376             };
3377
3378             var setter = function (that, index, value) {
3379               var data = getInternalState(that);
3380               if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
3381               data.view[SETTER](index * BYTES + data.byteOffset, value, true);
3382             };
3383
3384             var addElement = function (that, index) {
3385               nativeDefineProperty(that, index, {
3386                 get: function () {
3387                   return getter(this, index);
3388                 },
3389                 set: function (value) {
3390                   return setter(this, index, value);
3391                 },
3392                 enumerable: true
3393               });
3394             };
3395
3396             if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3397               TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
3398                 anInstance(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
3399                 var index = 0;
3400                 var byteOffset = 0;
3401                 var buffer, byteLength, length;
3402                 if (!isObject(data)) {
3403                   length = toIndex(data);
3404                   byteLength = length * BYTES;
3405                   buffer = new ArrayBuffer(byteLength);
3406                 } else if (isArrayBuffer(data)) {
3407                   buffer = data;
3408                   byteOffset = toOffset(offset, BYTES);
3409                   var $len = data.byteLength;
3410                   if ($length === undefined) {
3411                     if ($len % BYTES) throw RangeError(WRONG_LENGTH);
3412                     byteLength = $len - byteOffset;
3413                     if (byteLength < 0) throw RangeError(WRONG_LENGTH);
3414                   } else {
3415                     byteLength = toLength($length) * BYTES;
3416                     if (byteLength + byteOffset > $len) throw RangeError(WRONG_LENGTH);
3417                   }
3418                   length = byteLength / BYTES;
3419                 } else if (isTypedArray(data)) {
3420                   return fromList(TypedArrayConstructor, data);
3421                 } else {
3422                   return typedArrayFrom.call(TypedArrayConstructor, data);
3423                 }
3424                 setInternalState(that, {
3425                   buffer: buffer,
3426                   byteOffset: byteOffset,
3427                   byteLength: byteLength,
3428                   length: length,
3429                   view: new DataView(buffer)
3430                 });
3431                 while (index < length) addElement(that, index++);
3432               });
3433
3434               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3435               TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = objectCreate(TypedArrayPrototype);
3436             } else if (typedArrayConstructorsRequireWrappers) {
3437               TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
3438                 anInstance(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
3439                 return inheritIfRequired(function () {
3440                   if (!isObject(data)) return new NativeTypedArrayConstructor(toIndex(data));
3441                   if (isArrayBuffer(data)) return $length !== undefined
3442                     ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES), $length)
3443                     : typedArrayOffset !== undefined
3444                       ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES))
3445                       : new NativeTypedArrayConstructor(data);
3446                   if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
3447                   return typedArrayFrom.call(TypedArrayConstructor, data);
3448                 }(), dummy, TypedArrayConstructor);
3449               });
3450
3451               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3452               forEach(getOwnPropertyNames(NativeTypedArrayConstructor), function (key) {
3453                 if (!(key in TypedArrayConstructor)) {
3454                   createNonEnumerableProperty(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
3455                 }
3456               });
3457               TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
3458             }
3459
3460             if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
3461               createNonEnumerableProperty(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
3462             }
3463
3464             if (TYPED_ARRAY_TAG) {
3465               createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
3466             }
3467
3468             exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
3469
3470             _export({
3471               global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS
3472             }, exported);
3473
3474             if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
3475               createNonEnumerableProperty(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
3476             }
3477
3478             if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
3479               createNonEnumerableProperty(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
3480             }
3481
3482             setSpecies(CONSTRUCTOR_NAME);
3483           };
3484         } else module.exports = function () { /* empty */ };
3485         });
3486
3487         // `Uint8Array` constructor
3488         // https://tc39.es/ecma262/#sec-typedarray-objects
3489         typedArrayConstructor('Uint8', function (init) {
3490           return function Uint8Array(data, byteOffset, length) {
3491             return init(this, data, byteOffset, length);
3492           };
3493         });
3494
3495         var min$2 = Math.min;
3496
3497         // `Array.prototype.copyWithin` method implementation
3498         // https://tc39.es/ecma262/#sec-array.prototype.copywithin
3499         var arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {
3500           var O = toObject(this);
3501           var len = toLength(O.length);
3502           var to = toAbsoluteIndex(target, len);
3503           var from = toAbsoluteIndex(start, len);
3504           var end = arguments.length > 2 ? arguments[2] : undefined;
3505           var count = min$2((end === undefined ? len : toAbsoluteIndex(end, len)) - from, len - to);
3506           var inc = 1;
3507           if (from < to && to < from + count) {
3508             inc = -1;
3509             from += count - 1;
3510             to += count - 1;
3511           }
3512           while (count-- > 0) {
3513             if (from in O) O[to] = O[from];
3514             else delete O[to];
3515             to += inc;
3516             from += inc;
3517           } return O;
3518         };
3519
3520         var aTypedArray$1 = arrayBufferViewCore.aTypedArray;
3521         var exportTypedArrayMethod$1 = arrayBufferViewCore.exportTypedArrayMethod;
3522
3523         // `%TypedArray%.prototype.copyWithin` method
3524         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin
3525         exportTypedArrayMethod$1('copyWithin', function copyWithin(target, start /* , end */) {
3526           return arrayCopyWithin.call(aTypedArray$1(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
3527         });
3528
3529         var $every = arrayIteration.every;
3530
3531         var aTypedArray$2 = arrayBufferViewCore.aTypedArray;
3532         var exportTypedArrayMethod$2 = arrayBufferViewCore.exportTypedArrayMethod;
3533
3534         // `%TypedArray%.prototype.every` method
3535         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
3536         exportTypedArrayMethod$2('every', function every(callbackfn /* , thisArg */) {
3537           return $every(aTypedArray$2(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3538         });
3539
3540         var aTypedArray$3 = arrayBufferViewCore.aTypedArray;
3541         var exportTypedArrayMethod$3 = arrayBufferViewCore.exportTypedArrayMethod;
3542
3543         // `%TypedArray%.prototype.fill` method
3544         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill
3545         // eslint-disable-next-line no-unused-vars -- required for `.length`
3546         exportTypedArrayMethod$3('fill', function fill(value /* , start, end */) {
3547           return arrayFill.apply(aTypedArray$3(this), arguments);
3548         });
3549
3550         var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
3551
3552
3553         var typedArrayFromSpeciesAndList = function (instance, list) {
3554           var C = speciesConstructor(instance, instance.constructor);
3555           var index = 0;
3556           var length = list.length;
3557           var result = new (aTypedArrayConstructor$2(C))(length);
3558           while (length > index) result[index] = list[index++];
3559           return result;
3560         };
3561
3562         var $filter = arrayIteration.filter;
3563
3564
3565         var aTypedArray$4 = arrayBufferViewCore.aTypedArray;
3566         var exportTypedArrayMethod$4 = arrayBufferViewCore.exportTypedArrayMethod;
3567
3568         // `%TypedArray%.prototype.filter` method
3569         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter
3570         exportTypedArrayMethod$4('filter', function filter(callbackfn /* , thisArg */) {
3571           var list = $filter(aTypedArray$4(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3572           return typedArrayFromSpeciesAndList(this, list);
3573         });
3574
3575         var $find = arrayIteration.find;
3576
3577         var aTypedArray$5 = arrayBufferViewCore.aTypedArray;
3578         var exportTypedArrayMethod$5 = arrayBufferViewCore.exportTypedArrayMethod;
3579
3580         // `%TypedArray%.prototype.find` method
3581         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.find
3582         exportTypedArrayMethod$5('find', function find(predicate /* , thisArg */) {
3583           return $find(aTypedArray$5(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
3584         });
3585
3586         var $findIndex = arrayIteration.findIndex;
3587
3588         var aTypedArray$6 = arrayBufferViewCore.aTypedArray;
3589         var exportTypedArrayMethod$6 = arrayBufferViewCore.exportTypedArrayMethod;
3590
3591         // `%TypedArray%.prototype.findIndex` method
3592         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex
3593         exportTypedArrayMethod$6('findIndex', function findIndex(predicate /* , thisArg */) {
3594           return $findIndex(aTypedArray$6(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
3595         });
3596
3597         var $forEach$2 = arrayIteration.forEach;
3598
3599         var aTypedArray$7 = arrayBufferViewCore.aTypedArray;
3600         var exportTypedArrayMethod$7 = arrayBufferViewCore.exportTypedArrayMethod;
3601
3602         // `%TypedArray%.prototype.forEach` method
3603         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach
3604         exportTypedArrayMethod$7('forEach', function forEach(callbackfn /* , thisArg */) {
3605           $forEach$2(aTypedArray$7(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3606         });
3607
3608         var $includes = arrayIncludes.includes;
3609
3610         var aTypedArray$8 = arrayBufferViewCore.aTypedArray;
3611         var exportTypedArrayMethod$8 = arrayBufferViewCore.exportTypedArrayMethod;
3612
3613         // `%TypedArray%.prototype.includes` method
3614         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes
3615         exportTypedArrayMethod$8('includes', function includes(searchElement /* , fromIndex */) {
3616           return $includes(aTypedArray$8(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
3617         });
3618
3619         var $indexOf$1 = arrayIncludes.indexOf;
3620
3621         var aTypedArray$9 = arrayBufferViewCore.aTypedArray;
3622         var exportTypedArrayMethod$9 = arrayBufferViewCore.exportTypedArrayMethod;
3623
3624         // `%TypedArray%.prototype.indexOf` method
3625         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof
3626         exportTypedArrayMethod$9('indexOf', function indexOf(searchElement /* , fromIndex */) {
3627           return $indexOf$1(aTypedArray$9(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
3628         });
3629
3630         var ITERATOR$6 = wellKnownSymbol('iterator');
3631         var Uint8Array$1 = global_1.Uint8Array;
3632         var arrayValues = es_array_iterator.values;
3633         var arrayKeys = es_array_iterator.keys;
3634         var arrayEntries = es_array_iterator.entries;
3635         var aTypedArray$a = arrayBufferViewCore.aTypedArray;
3636         var exportTypedArrayMethod$a = arrayBufferViewCore.exportTypedArrayMethod;
3637         var nativeTypedArrayIterator = Uint8Array$1 && Uint8Array$1.prototype[ITERATOR$6];
3638
3639         var CORRECT_ITER_NAME = !!nativeTypedArrayIterator
3640           && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);
3641
3642         var typedArrayValues = function values() {
3643           return arrayValues.call(aTypedArray$a(this));
3644         };
3645
3646         // `%TypedArray%.prototype.entries` method
3647         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries
3648         exportTypedArrayMethod$a('entries', function entries() {
3649           return arrayEntries.call(aTypedArray$a(this));
3650         });
3651         // `%TypedArray%.prototype.keys` method
3652         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys
3653         exportTypedArrayMethod$a('keys', function keys() {
3654           return arrayKeys.call(aTypedArray$a(this));
3655         });
3656         // `%TypedArray%.prototype.values` method
3657         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.values
3658         exportTypedArrayMethod$a('values', typedArrayValues, !CORRECT_ITER_NAME);
3659         // `%TypedArray%.prototype[@@iterator]` method
3660         // https://tc39.es/ecma262/#sec-%typedarray%.prototype-@@iterator
3661         exportTypedArrayMethod$a(ITERATOR$6, typedArrayValues, !CORRECT_ITER_NAME);
3662
3663         var aTypedArray$b = arrayBufferViewCore.aTypedArray;
3664         var exportTypedArrayMethod$b = arrayBufferViewCore.exportTypedArrayMethod;
3665         var $join = [].join;
3666
3667         // `%TypedArray%.prototype.join` method
3668         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.join
3669         // eslint-disable-next-line no-unused-vars -- required for `.length`
3670         exportTypedArrayMethod$b('join', function join(separator) {
3671           return $join.apply(aTypedArray$b(this), arguments);
3672         });
3673
3674         var min$3 = Math.min;
3675         var nativeLastIndexOf = [].lastIndexOf;
3676         var NEGATIVE_ZERO$1 = !!nativeLastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0;
3677         var STRICT_METHOD$2 = arrayMethodIsStrict('lastIndexOf');
3678         var FORCED$1 = NEGATIVE_ZERO$1 || !STRICT_METHOD$2;
3679
3680         // `Array.prototype.lastIndexOf` method implementation
3681         // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
3682         var arrayLastIndexOf = FORCED$1 ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {
3683           // convert -0 to +0
3684           if (NEGATIVE_ZERO$1) return nativeLastIndexOf.apply(this, arguments) || 0;
3685           var O = toIndexedObject(this);
3686           var length = toLength(O.length);
3687           var index = length - 1;
3688           if (arguments.length > 1) index = min$3(index, toInteger(arguments[1]));
3689           if (index < 0) index = length + index;
3690           for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;
3691           return -1;
3692         } : nativeLastIndexOf;
3693
3694         var aTypedArray$c = arrayBufferViewCore.aTypedArray;
3695         var exportTypedArrayMethod$c = arrayBufferViewCore.exportTypedArrayMethod;
3696
3697         // `%TypedArray%.prototype.lastIndexOf` method
3698         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
3699         // eslint-disable-next-line no-unused-vars -- required for `.length`
3700         exportTypedArrayMethod$c('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {
3701           return arrayLastIndexOf.apply(aTypedArray$c(this), arguments);
3702         });
3703
3704         var $map$1 = arrayIteration.map;
3705
3706
3707         var aTypedArray$d = arrayBufferViewCore.aTypedArray;
3708         var aTypedArrayConstructor$3 = arrayBufferViewCore.aTypedArrayConstructor;
3709         var exportTypedArrayMethod$d = arrayBufferViewCore.exportTypedArrayMethod;
3710
3711         // `%TypedArray%.prototype.map` method
3712         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.map
3713         exportTypedArrayMethod$d('map', function map(mapfn /* , thisArg */) {
3714           return $map$1(aTypedArray$d(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
3715             return new (aTypedArrayConstructor$3(speciesConstructor(O, O.constructor)))(length);
3716           });
3717         });
3718
3719         // `Array.prototype.{ reduce, reduceRight }` methods implementation
3720         var createMethod$3 = function (IS_RIGHT) {
3721           return function (that, callbackfn, argumentsLength, memo) {
3722             aFunction$1(callbackfn);
3723             var O = toObject(that);
3724             var self = indexedObject(O);
3725             var length = toLength(O.length);
3726             var index = IS_RIGHT ? length - 1 : 0;
3727             var i = IS_RIGHT ? -1 : 1;
3728             if (argumentsLength < 2) while (true) {
3729               if (index in self) {
3730                 memo = self[index];
3731                 index += i;
3732                 break;
3733               }
3734               index += i;
3735               if (IS_RIGHT ? index < 0 : length <= index) {
3736                 throw TypeError('Reduce of empty array with no initial value');
3737               }
3738             }
3739             for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
3740               memo = callbackfn(memo, self[index], index, O);
3741             }
3742             return memo;
3743           };
3744         };
3745
3746         var arrayReduce = {
3747           // `Array.prototype.reduce` method
3748           // https://tc39.es/ecma262/#sec-array.prototype.reduce
3749           left: createMethod$3(false),
3750           // `Array.prototype.reduceRight` method
3751           // https://tc39.es/ecma262/#sec-array.prototype.reduceright
3752           right: createMethod$3(true)
3753         };
3754
3755         var $reduce = arrayReduce.left;
3756
3757         var aTypedArray$e = arrayBufferViewCore.aTypedArray;
3758         var exportTypedArrayMethod$e = arrayBufferViewCore.exportTypedArrayMethod;
3759
3760         // `%TypedArray%.prototype.reduce` method
3761         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce
3762         exportTypedArrayMethod$e('reduce', function reduce(callbackfn /* , initialValue */) {
3763           return $reduce(aTypedArray$e(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
3764         });
3765
3766         var $reduceRight = arrayReduce.right;
3767
3768         var aTypedArray$f = arrayBufferViewCore.aTypedArray;
3769         var exportTypedArrayMethod$f = arrayBufferViewCore.exportTypedArrayMethod;
3770
3771         // `%TypedArray%.prototype.reduceRicht` method
3772         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright
3773         exportTypedArrayMethod$f('reduceRight', function reduceRight(callbackfn /* , initialValue */) {
3774           return $reduceRight(aTypedArray$f(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
3775         });
3776
3777         var aTypedArray$g = arrayBufferViewCore.aTypedArray;
3778         var exportTypedArrayMethod$g = arrayBufferViewCore.exportTypedArrayMethod;
3779         var floor$2 = Math.floor;
3780
3781         // `%TypedArray%.prototype.reverse` method
3782         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse
3783         exportTypedArrayMethod$g('reverse', function reverse() {
3784           var that = this;
3785           var length = aTypedArray$g(that).length;
3786           var middle = floor$2(length / 2);
3787           var index = 0;
3788           var value;
3789           while (index < middle) {
3790             value = that[index];
3791             that[index++] = that[--length];
3792             that[length] = value;
3793           } return that;
3794         });
3795
3796         var aTypedArray$h = arrayBufferViewCore.aTypedArray;
3797         var exportTypedArrayMethod$h = arrayBufferViewCore.exportTypedArrayMethod;
3798
3799         var FORCED$2 = fails(function () {
3800           /* global Int8Array -- safe */
3801           new Int8Array(1).set({});
3802         });
3803
3804         // `%TypedArray%.prototype.set` method
3805         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
3806         exportTypedArrayMethod$h('set', function set(arrayLike /* , offset */) {
3807           aTypedArray$h(this);
3808           var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
3809           var length = this.length;
3810           var src = toObject(arrayLike);
3811           var len = toLength(src.length);
3812           var index = 0;
3813           if (len + offset > length) throw RangeError('Wrong length');
3814           while (index < len) this[offset + index] = src[index++];
3815         }, FORCED$2);
3816
3817         var aTypedArray$i = arrayBufferViewCore.aTypedArray;
3818         var aTypedArrayConstructor$4 = arrayBufferViewCore.aTypedArrayConstructor;
3819         var exportTypedArrayMethod$i = arrayBufferViewCore.exportTypedArrayMethod;
3820         var $slice = [].slice;
3821
3822         var FORCED$3 = fails(function () {
3823           /* global Int8Array -- safe */
3824           new Int8Array(1).slice();
3825         });
3826
3827         // `%TypedArray%.prototype.slice` method
3828         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
3829         exportTypedArrayMethod$i('slice', function slice(start, end) {
3830           var list = $slice.call(aTypedArray$i(this), start, end);
3831           var C = speciesConstructor(this, this.constructor);
3832           var index = 0;
3833           var length = list.length;
3834           var result = new (aTypedArrayConstructor$4(C))(length);
3835           while (length > index) result[index] = list[index++];
3836           return result;
3837         }, FORCED$3);
3838
3839         var $some = arrayIteration.some;
3840
3841         var aTypedArray$j = arrayBufferViewCore.aTypedArray;
3842         var exportTypedArrayMethod$j = arrayBufferViewCore.exportTypedArrayMethod;
3843
3844         // `%TypedArray%.prototype.some` method
3845         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.some
3846         exportTypedArrayMethod$j('some', function some(callbackfn /* , thisArg */) {
3847           return $some(aTypedArray$j(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3848         });
3849
3850         var aTypedArray$k = arrayBufferViewCore.aTypedArray;
3851         var exportTypedArrayMethod$k = arrayBufferViewCore.exportTypedArrayMethod;
3852         var $sort = [].sort;
3853
3854         // `%TypedArray%.prototype.sort` method
3855         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort
3856         exportTypedArrayMethod$k('sort', function sort(comparefn) {
3857           return $sort.call(aTypedArray$k(this), comparefn);
3858         });
3859
3860         var aTypedArray$l = arrayBufferViewCore.aTypedArray;
3861         var exportTypedArrayMethod$l = arrayBufferViewCore.exportTypedArrayMethod;
3862
3863         // `%TypedArray%.prototype.subarray` method
3864         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray
3865         exportTypedArrayMethod$l('subarray', function subarray(begin, end) {
3866           var O = aTypedArray$l(this);
3867           var length = O.length;
3868           var beginIndex = toAbsoluteIndex(begin, length);
3869           return new (speciesConstructor(O, O.constructor))(
3870             O.buffer,
3871             O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,
3872             toLength((end === undefined ? length : toAbsoluteIndex(end, length)) - beginIndex)
3873           );
3874         });
3875
3876         var Int8Array$3 = global_1.Int8Array;
3877         var aTypedArray$m = arrayBufferViewCore.aTypedArray;
3878         var exportTypedArrayMethod$m = arrayBufferViewCore.exportTypedArrayMethod;
3879         var $toLocaleString = [].toLocaleString;
3880         var $slice$1 = [].slice;
3881
3882         // iOS Safari 6.x fails here
3883         var TO_LOCALE_STRING_BUG = !!Int8Array$3 && fails(function () {
3884           $toLocaleString.call(new Int8Array$3(1));
3885         });
3886
3887         var FORCED$4 = fails(function () {
3888           return [1, 2].toLocaleString() != new Int8Array$3([1, 2]).toLocaleString();
3889         }) || !fails(function () {
3890           Int8Array$3.prototype.toLocaleString.call([1, 2]);
3891         });
3892
3893         // `%TypedArray%.prototype.toLocaleString` method
3894         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring
3895         exportTypedArrayMethod$m('toLocaleString', function toLocaleString() {
3896           return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice$1.call(aTypedArray$m(this)) : aTypedArray$m(this), arguments);
3897         }, FORCED$4);
3898
3899         var exportTypedArrayMethod$n = arrayBufferViewCore.exportTypedArrayMethod;
3900
3901
3902
3903         var Uint8Array$2 = global_1.Uint8Array;
3904         var Uint8ArrayPrototype = Uint8Array$2 && Uint8Array$2.prototype || {};
3905         var arrayToString = [].toString;
3906         var arrayJoin = [].join;
3907
3908         if (fails(function () { arrayToString.call({}); })) {
3909           arrayToString = function toString() {
3910             return arrayJoin.call(this);
3911           };
3912         }
3913
3914         var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;
3915
3916         // `%TypedArray%.prototype.toString` method
3917         // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tostring
3918         exportTypedArrayMethod$n('toString', arrayToString, IS_NOT_ARRAY_METHOD);
3919
3920         var nativeJoin = [].join;
3921
3922         var ES3_STRINGS = indexedObject != Object;
3923         var STRICT_METHOD$3 = arrayMethodIsStrict('join', ',');
3924
3925         // `Array.prototype.join` method
3926         // https://tc39.es/ecma262/#sec-array.prototype.join
3927         _export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$3 }, {
3928           join: function join(separator) {
3929             return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
3930           }
3931         });
3932
3933         var createProperty = function (object, key, value) {
3934           var propertyKey = toPrimitive(key);
3935           if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
3936           else object[propertyKey] = value;
3937         };
3938
3939         var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('slice');
3940
3941         var SPECIES$5 = wellKnownSymbol('species');
3942         var nativeSlice = [].slice;
3943         var max$1 = Math.max;
3944
3945         // `Array.prototype.slice` method
3946         // https://tc39.es/ecma262/#sec-array.prototype.slice
3947         // fallback for not array-like ES3 strings and DOM objects
3948         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 }, {
3949           slice: function slice(start, end) {
3950             var O = toIndexedObject(this);
3951             var length = toLength(O.length);
3952             var k = toAbsoluteIndex(start, length);
3953             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
3954             // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
3955             var Constructor, result, n;
3956             if (isArray(O)) {
3957               Constructor = O.constructor;
3958               // cross-realm fallback
3959               if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
3960                 Constructor = undefined;
3961               } else if (isObject(Constructor)) {
3962                 Constructor = Constructor[SPECIES$5];
3963                 if (Constructor === null) Constructor = undefined;
3964               }
3965               if (Constructor === Array || Constructor === undefined) {
3966                 return nativeSlice.call(O, k, fin);
3967               }
3968             }
3969             result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));
3970             for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
3971             result.length = n;
3972             return result;
3973           }
3974         });
3975
3976         var ITERATOR$7 = wellKnownSymbol('iterator');
3977
3978         var nativeUrl = !fails(function () {
3979           var url = new URL('b?a=1&b=2&c=3', 'http://a');
3980           var searchParams = url.searchParams;
3981           var result = '';
3982           url.pathname = 'c%20d';
3983           searchParams.forEach(function (value, key) {
3984             searchParams['delete']('b');
3985             result += key + value;
3986           });
3987           return (isPure && !url.toJSON)
3988             || !searchParams.sort
3989             || url.href !== 'http://a/c%20d?a=1&c=3'
3990             || searchParams.get('c') !== '3'
3991             || String(new URLSearchParams('?a=1')) !== 'a=1'
3992             || !searchParams[ITERATOR$7]
3993             // throws in Edge
3994             || new URL('https://a@b').username !== 'a'
3995             || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
3996             // not punycoded in Edge
3997             || new URL('http://тест').host !== 'xn--e1aybc'
3998             // not escaped in Chrome 62-
3999             || new URL('http://a#б').hash !== '#%D0%B1'
4000             // fails in Chrome 66-
4001             || result !== 'a1c3'
4002             // throws in Safari
4003             || new URL('http://x', undefined).host !== 'x';
4004         });
4005
4006         var nativeAssign = Object.assign;
4007         var defineProperty$5 = Object.defineProperty;
4008
4009         // `Object.assign` method
4010         // https://tc39.es/ecma262/#sec-object.assign
4011         var objectAssign = !nativeAssign || fails(function () {
4012           // should have correct order of operations (Edge bug)
4013           if (descriptors && nativeAssign({ b: 1 }, nativeAssign(defineProperty$5({}, 'a', {
4014             enumerable: true,
4015             get: function () {
4016               defineProperty$5(this, 'b', {
4017                 value: 3,
4018                 enumerable: false
4019               });
4020             }
4021           }), { b: 2 })).b !== 1) return true;
4022           // should work with symbols and should have deterministic property order (V8 bug)
4023           var A = {};
4024           var B = {};
4025           /* global Symbol -- required for testing */
4026           var symbol = Symbol();
4027           var alphabet = 'abcdefghijklmnopqrst';
4028           A[symbol] = 7;
4029           alphabet.split('').forEach(function (chr) { B[chr] = chr; });
4030           return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
4031         }) ? function assign(target, source) { // eslint-disable-line no-unused-vars -- required for `.length`
4032           var T = toObject(target);
4033           var argumentsLength = arguments.length;
4034           var index = 1;
4035           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
4036           var propertyIsEnumerable = objectPropertyIsEnumerable.f;
4037           while (argumentsLength > index) {
4038             var S = indexedObject(arguments[index++]);
4039             var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
4040             var length = keys.length;
4041             var j = 0;
4042             var key;
4043             while (length > j) {
4044               key = keys[j++];
4045               if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
4046             }
4047           } return T;
4048         } : nativeAssign;
4049
4050         // call something on iterator step with safe closing on error
4051         var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
4052           try {
4053             return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
4054           // 7.4.6 IteratorClose(iterator, completion)
4055           } catch (error) {
4056             iteratorClose(iterator);
4057             throw error;
4058           }
4059         };
4060
4061         // `Array.from` method implementation
4062         // https://tc39.es/ecma262/#sec-array.from
4063         var arrayFrom = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
4064           var O = toObject(arrayLike);
4065           var C = typeof this == 'function' ? this : Array;
4066           var argumentsLength = arguments.length;
4067           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
4068           var mapping = mapfn !== undefined;
4069           var iteratorMethod = getIteratorMethod(O);
4070           var index = 0;
4071           var length, result, step, iterator, next, value;
4072           if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
4073           // if the target is not iterable or it's an array with the default iterator - use a simple case
4074           if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
4075             iterator = iteratorMethod.call(O);
4076             next = iterator.next;
4077             result = new C();
4078             for (;!(step = next.call(iterator)).done; index++) {
4079               value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
4080               createProperty(result, index, value);
4081             }
4082           } else {
4083             length = toLength(O.length);
4084             result = new C(length);
4085             for (;length > index; index++) {
4086               value = mapping ? mapfn(O[index], index) : O[index];
4087               createProperty(result, index, value);
4088             }
4089           }
4090           result.length = index;
4091           return result;
4092         };
4093
4094         // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
4095         var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
4096         var base = 36;
4097         var tMin = 1;
4098         var tMax = 26;
4099         var skew = 38;
4100         var damp = 700;
4101         var initialBias = 72;
4102         var initialN = 128; // 0x80
4103         var delimiter = '-'; // '\x2D'
4104         var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
4105         var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
4106         var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
4107         var baseMinusTMin = base - tMin;
4108         var floor$3 = Math.floor;
4109         var stringFromCharCode = String.fromCharCode;
4110
4111         /**
4112          * Creates an array containing the numeric code points of each Unicode
4113          * character in the string. While JavaScript uses UCS-2 internally,
4114          * this function will convert a pair of surrogate halves (each of which
4115          * UCS-2 exposes as separate characters) into a single code point,
4116          * matching UTF-16.
4117          */
4118         var ucs2decode = function (string) {
4119           var output = [];
4120           var counter = 0;
4121           var length = string.length;
4122           while (counter < length) {
4123             var value = string.charCodeAt(counter++);
4124             if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4125               // It's a high surrogate, and there is a next character.
4126               var extra = string.charCodeAt(counter++);
4127               if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
4128                 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4129               } else {
4130                 // It's an unmatched surrogate; only append this code unit, in case the
4131                 // next code unit is the high surrogate of a surrogate pair.
4132                 output.push(value);
4133                 counter--;
4134               }
4135             } else {
4136               output.push(value);
4137             }
4138           }
4139           return output;
4140         };
4141
4142         /**
4143          * Converts a digit/integer into a basic code point.
4144          */
4145         var digitToBasic = function (digit) {
4146           //  0..25 map to ASCII a..z or A..Z
4147           // 26..35 map to ASCII 0..9
4148           return digit + 22 + 75 * (digit < 26);
4149         };
4150
4151         /**
4152          * Bias adaptation function as per section 3.4 of RFC 3492.
4153          * https://tools.ietf.org/html/rfc3492#section-3.4
4154          */
4155         var adapt = function (delta, numPoints, firstTime) {
4156           var k = 0;
4157           delta = firstTime ? floor$3(delta / damp) : delta >> 1;
4158           delta += floor$3(delta / numPoints);
4159           for (; delta > baseMinusTMin * tMax >> 1; k += base) {
4160             delta = floor$3(delta / baseMinusTMin);
4161           }
4162           return floor$3(k + (baseMinusTMin + 1) * delta / (delta + skew));
4163         };
4164
4165         /**
4166          * Converts a string of Unicode symbols (e.g. a domain name label) to a
4167          * Punycode string of ASCII-only symbols.
4168          */
4169         // eslint-disable-next-line max-statements -- TODO
4170         var encode = function (input) {
4171           var output = [];
4172
4173           // Convert the input in UCS-2 to an array of Unicode code points.
4174           input = ucs2decode(input);
4175
4176           // Cache the length.
4177           var inputLength = input.length;
4178
4179           // Initialize the state.
4180           var n = initialN;
4181           var delta = 0;
4182           var bias = initialBias;
4183           var i, currentValue;
4184
4185           // Handle the basic code points.
4186           for (i = 0; i < input.length; i++) {
4187             currentValue = input[i];
4188             if (currentValue < 0x80) {
4189               output.push(stringFromCharCode(currentValue));
4190             }
4191           }
4192
4193           var basicLength = output.length; // number of basic code points.
4194           var handledCPCount = basicLength; // number of code points that have been handled;
4195
4196           // Finish the basic string with a delimiter unless it's empty.
4197           if (basicLength) {
4198             output.push(delimiter);
4199           }
4200
4201           // Main encoding loop:
4202           while (handledCPCount < inputLength) {
4203             // All non-basic code points < n have been handled already. Find the next larger one:
4204             var m = maxInt;
4205             for (i = 0; i < input.length; i++) {
4206               currentValue = input[i];
4207               if (currentValue >= n && currentValue < m) {
4208                 m = currentValue;
4209               }
4210             }
4211
4212             // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
4213             var handledCPCountPlusOne = handledCPCount + 1;
4214             if (m - n > floor$3((maxInt - delta) / handledCPCountPlusOne)) {
4215               throw RangeError(OVERFLOW_ERROR);
4216             }
4217
4218             delta += (m - n) * handledCPCountPlusOne;
4219             n = m;
4220
4221             for (i = 0; i < input.length; i++) {
4222               currentValue = input[i];
4223               if (currentValue < n && ++delta > maxInt) {
4224                 throw RangeError(OVERFLOW_ERROR);
4225               }
4226               if (currentValue == n) {
4227                 // Represent delta as a generalized variable-length integer.
4228                 var q = delta;
4229                 for (var k = base; /* no condition */; k += base) {
4230                   var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
4231                   if (q < t) break;
4232                   var qMinusT = q - t;
4233                   var baseMinusT = base - t;
4234                   output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
4235                   q = floor$3(qMinusT / baseMinusT);
4236                 }
4237
4238                 output.push(stringFromCharCode(digitToBasic(q)));
4239                 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
4240                 delta = 0;
4241                 ++handledCPCount;
4242               }
4243             }
4244
4245             ++delta;
4246             ++n;
4247           }
4248           return output.join('');
4249         };
4250
4251         var stringPunycodeToAscii = function (input) {
4252           var encoded = [];
4253           var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
4254           var i, label;
4255           for (i = 0; i < labels.length; i++) {
4256             label = labels[i];
4257             encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
4258           }
4259           return encoded.join('.');
4260         };
4261
4262         var getIterator = function (it) {
4263           var iteratorMethod = getIteratorMethod(it);
4264           if (typeof iteratorMethod != 'function') {
4265             throw TypeError(String(it) + ' is not iterable');
4266           } return anObject(iteratorMethod.call(it));
4267         };
4268
4269         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291         var $fetch$1 = getBuiltIn('fetch');
4292         var Headers = getBuiltIn('Headers');
4293         var ITERATOR$8 = wellKnownSymbol('iterator');
4294         var URL_SEARCH_PARAMS = 'URLSearchParams';
4295         var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
4296         var setInternalState$5 = internalState.set;
4297         var getInternalParamsState = internalState.getterFor(URL_SEARCH_PARAMS);
4298         var getInternalIteratorState = internalState.getterFor(URL_SEARCH_PARAMS_ITERATOR);
4299
4300         var plus = /\+/g;
4301         var sequences = Array(4);
4302
4303         var percentSequence = function (bytes) {
4304           return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
4305         };
4306
4307         var percentDecode = function (sequence) {
4308           try {
4309             return decodeURIComponent(sequence);
4310           } catch (error) {
4311             return sequence;
4312           }
4313         };
4314
4315         var deserialize = function (it) {
4316           var result = it.replace(plus, ' ');
4317           var bytes = 4;
4318           try {
4319             return decodeURIComponent(result);
4320           } catch (error) {
4321             while (bytes) {
4322               result = result.replace(percentSequence(bytes--), percentDecode);
4323             }
4324             return result;
4325           }
4326         };
4327
4328         var find = /[!'()~]|%20/g;
4329
4330         var replace = {
4331           '!': '%21',
4332           "'": '%27',
4333           '(': '%28',
4334           ')': '%29',
4335           '~': '%7E',
4336           '%20': '+'
4337         };
4338
4339         var replacer = function (match) {
4340           return replace[match];
4341         };
4342
4343         var serialize = function (it) {
4344           return encodeURIComponent(it).replace(find, replacer);
4345         };
4346
4347         var parseSearchParams = function (result, query) {
4348           if (query) {
4349             var attributes = query.split('&');
4350             var index = 0;
4351             var attribute, entry;
4352             while (index < attributes.length) {
4353               attribute = attributes[index++];
4354               if (attribute.length) {
4355                 entry = attribute.split('=');
4356                 result.push({
4357                   key: deserialize(entry.shift()),
4358                   value: deserialize(entry.join('='))
4359                 });
4360               }
4361             }
4362           }
4363         };
4364
4365         var updateSearchParams = function (query) {
4366           this.entries.length = 0;
4367           parseSearchParams(this.entries, query);
4368         };
4369
4370         var validateArgumentsLength = function (passed, required) {
4371           if (passed < required) throw TypeError('Not enough arguments');
4372         };
4373
4374         var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
4375           setInternalState$5(this, {
4376             type: URL_SEARCH_PARAMS_ITERATOR,
4377             iterator: getIterator(getInternalParamsState(params).entries),
4378             kind: kind
4379           });
4380         }, 'Iterator', function next() {
4381           var state = getInternalIteratorState(this);
4382           var kind = state.kind;
4383           var step = state.iterator.next();
4384           var entry = step.value;
4385           if (!step.done) {
4386             step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
4387           } return step;
4388         });
4389
4390         // `URLSearchParams` constructor
4391         // https://url.spec.whatwg.org/#interface-urlsearchparams
4392         var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
4393           anInstance(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
4394           var init = arguments.length > 0 ? arguments[0] : undefined;
4395           var that = this;
4396           var entries = [];
4397           var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
4398
4399           setInternalState$5(that, {
4400             type: URL_SEARCH_PARAMS,
4401             entries: entries,
4402             updateURL: function () { /* empty */ },
4403             updateSearchParams: updateSearchParams
4404           });
4405
4406           if (init !== undefined) {
4407             if (isObject(init)) {
4408               iteratorMethod = getIteratorMethod(init);
4409               if (typeof iteratorMethod === 'function') {
4410                 iterator = iteratorMethod.call(init);
4411                 next = iterator.next;
4412                 while (!(step = next.call(iterator)).done) {
4413                   entryIterator = getIterator(anObject(step.value));
4414                   entryNext = entryIterator.next;
4415                   if (
4416                     (first = entryNext.call(entryIterator)).done ||
4417                     (second = entryNext.call(entryIterator)).done ||
4418                     !entryNext.call(entryIterator).done
4419                   ) throw TypeError('Expected sequence with length 2');
4420                   entries.push({ key: first.value + '', value: second.value + '' });
4421                 }
4422               } else for (key in init) if (has(init, key)) entries.push({ key: key, value: init[key] + '' });
4423             } else {
4424               parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
4425             }
4426           }
4427         };
4428
4429         var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
4430
4431         redefineAll(URLSearchParamsPrototype, {
4432           // `URLSearchParams.prototype.append` method
4433           // https://url.spec.whatwg.org/#dom-urlsearchparams-append
4434           append: function append(name, value) {
4435             validateArgumentsLength(arguments.length, 2);
4436             var state = getInternalParamsState(this);
4437             state.entries.push({ key: name + '', value: value + '' });
4438             state.updateURL();
4439           },
4440           // `URLSearchParams.prototype.delete` method
4441           // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
4442           'delete': function (name) {
4443             validateArgumentsLength(arguments.length, 1);
4444             var state = getInternalParamsState(this);
4445             var entries = state.entries;
4446             var key = name + '';
4447             var index = 0;
4448             while (index < entries.length) {
4449               if (entries[index].key === key) entries.splice(index, 1);
4450               else index++;
4451             }
4452             state.updateURL();
4453           },
4454           // `URLSearchParams.prototype.get` method
4455           // https://url.spec.whatwg.org/#dom-urlsearchparams-get
4456           get: function get(name) {
4457             validateArgumentsLength(arguments.length, 1);
4458             var entries = getInternalParamsState(this).entries;
4459             var key = name + '';
4460             var index = 0;
4461             for (; index < entries.length; index++) {
4462               if (entries[index].key === key) return entries[index].value;
4463             }
4464             return null;
4465           },
4466           // `URLSearchParams.prototype.getAll` method
4467           // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
4468           getAll: function getAll(name) {
4469             validateArgumentsLength(arguments.length, 1);
4470             var entries = getInternalParamsState(this).entries;
4471             var key = name + '';
4472             var result = [];
4473             var index = 0;
4474             for (; index < entries.length; index++) {
4475               if (entries[index].key === key) result.push(entries[index].value);
4476             }
4477             return result;
4478           },
4479           // `URLSearchParams.prototype.has` method
4480           // https://url.spec.whatwg.org/#dom-urlsearchparams-has
4481           has: function has(name) {
4482             validateArgumentsLength(arguments.length, 1);
4483             var entries = getInternalParamsState(this).entries;
4484             var key = name + '';
4485             var index = 0;
4486             while (index < entries.length) {
4487               if (entries[index++].key === key) return true;
4488             }
4489             return false;
4490           },
4491           // `URLSearchParams.prototype.set` method
4492           // https://url.spec.whatwg.org/#dom-urlsearchparams-set
4493           set: function set(name, value) {
4494             validateArgumentsLength(arguments.length, 1);
4495             var state = getInternalParamsState(this);
4496             var entries = state.entries;
4497             var found = false;
4498             var key = name + '';
4499             var val = value + '';
4500             var index = 0;
4501             var entry;
4502             for (; index < entries.length; index++) {
4503               entry = entries[index];
4504               if (entry.key === key) {
4505                 if (found) entries.splice(index--, 1);
4506                 else {
4507                   found = true;
4508                   entry.value = val;
4509                 }
4510               }
4511             }
4512             if (!found) entries.push({ key: key, value: val });
4513             state.updateURL();
4514           },
4515           // `URLSearchParams.prototype.sort` method
4516           // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
4517           sort: function sort() {
4518             var state = getInternalParamsState(this);
4519             var entries = state.entries;
4520             // Array#sort is not stable in some engines
4521             var slice = entries.slice();
4522             var entry, entriesIndex, sliceIndex;
4523             entries.length = 0;
4524             for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
4525               entry = slice[sliceIndex];
4526               for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
4527                 if (entries[entriesIndex].key > entry.key) {
4528                   entries.splice(entriesIndex, 0, entry);
4529                   break;
4530                 }
4531               }
4532               if (entriesIndex === sliceIndex) entries.push(entry);
4533             }
4534             state.updateURL();
4535           },
4536           // `URLSearchParams.prototype.forEach` method
4537           forEach: function forEach(callback /* , thisArg */) {
4538             var entries = getInternalParamsState(this).entries;
4539             var boundFunction = functionBindContext(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
4540             var index = 0;
4541             var entry;
4542             while (index < entries.length) {
4543               entry = entries[index++];
4544               boundFunction(entry.value, entry.key, this);
4545             }
4546           },
4547           // `URLSearchParams.prototype.keys` method
4548           keys: function keys() {
4549             return new URLSearchParamsIterator(this, 'keys');
4550           },
4551           // `URLSearchParams.prototype.values` method
4552           values: function values() {
4553             return new URLSearchParamsIterator(this, 'values');
4554           },
4555           // `URLSearchParams.prototype.entries` method
4556           entries: function entries() {
4557             return new URLSearchParamsIterator(this, 'entries');
4558           }
4559         }, { enumerable: true });
4560
4561         // `URLSearchParams.prototype[@@iterator]` method
4562         redefine(URLSearchParamsPrototype, ITERATOR$8, URLSearchParamsPrototype.entries);
4563
4564         // `URLSearchParams.prototype.toString` method
4565         // https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
4566         redefine(URLSearchParamsPrototype, 'toString', function toString() {
4567           var entries = getInternalParamsState(this).entries;
4568           var result = [];
4569           var index = 0;
4570           var entry;
4571           while (index < entries.length) {
4572             entry = entries[index++];
4573             result.push(serialize(entry.key) + '=' + serialize(entry.value));
4574           } return result.join('&');
4575         }, { enumerable: true });
4576
4577         setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
4578
4579         _export({ global: true, forced: !nativeUrl }, {
4580           URLSearchParams: URLSearchParamsConstructor
4581         });
4582
4583         // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
4584         // https://github.com/zloirock/core-js/issues/674
4585         if (!nativeUrl && typeof $fetch$1 == 'function' && typeof Headers == 'function') {
4586           _export({ global: true, enumerable: true, forced: true }, {
4587             fetch: function fetch(input /* , init */) {
4588               var args = [input];
4589               var init, body, headers;
4590               if (arguments.length > 1) {
4591                 init = arguments[1];
4592                 if (isObject(init)) {
4593                   body = init.body;
4594                   if (classof(body) === URL_SEARCH_PARAMS) {
4595                     headers = init.headers ? new Headers(init.headers) : new Headers();
4596                     if (!headers.has('content-type')) {
4597                       headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
4598                     }
4599                     init = objectCreate(init, {
4600                       body: createPropertyDescriptor(0, String(body)),
4601                       headers: createPropertyDescriptor(0, headers)
4602                     });
4603                   }
4604                 }
4605                 args.push(init);
4606               } return $fetch$1.apply(this, args);
4607             }
4608           });
4609         }
4610
4611         var web_urlSearchParams = {
4612           URLSearchParams: URLSearchParamsConstructor,
4613           getState: getInternalParamsState
4614         };
4615
4616         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628         var codeAt = stringMultibyte.codeAt;
4629
4630
4631
4632
4633
4634         var NativeURL = global_1.URL;
4635         var URLSearchParams$1 = web_urlSearchParams.URLSearchParams;
4636         var getInternalSearchParamsState = web_urlSearchParams.getState;
4637         var setInternalState$6 = internalState.set;
4638         var getInternalURLState = internalState.getterFor('URL');
4639         var floor$4 = Math.floor;
4640         var pow$1 = Math.pow;
4641
4642         var INVALID_AUTHORITY = 'Invalid authority';
4643         var INVALID_SCHEME = 'Invalid scheme';
4644         var INVALID_HOST = 'Invalid host';
4645         var INVALID_PORT = 'Invalid port';
4646
4647         var ALPHA = /[A-Za-z]/;
4648         var ALPHANUMERIC = /[\d+-.A-Za-z]/;
4649         var DIGIT = /\d/;
4650         var HEX_START = /^(0x|0X)/;
4651         var OCT = /^[0-7]+$/;
4652         var DEC = /^\d+$/;
4653         var HEX = /^[\dA-Fa-f]+$/;
4654         /* eslint-disable no-control-regex -- safe */
4655         var FORBIDDEN_HOST_CODE_POINT = /[\u0000\t\u000A\u000D #%/:?@[\\]]/;
4656         var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\u0000\t\u000A\u000D #/:?@[\\]]/;
4657         var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
4658         var TAB_AND_NEW_LINE = /[\t\u000A\u000D]/g;
4659         /* eslint-enable no-control-regex -- safe */
4660         var EOF;
4661
4662         var parseHost = function (url, input) {
4663           var result, codePoints, index;
4664           if (input.charAt(0) == '[') {
4665             if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
4666             result = parseIPv6(input.slice(1, -1));
4667             if (!result) return INVALID_HOST;
4668             url.host = result;
4669           // opaque host
4670           } else if (!isSpecial(url)) {
4671             if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
4672             result = '';
4673             codePoints = arrayFrom(input);
4674             for (index = 0; index < codePoints.length; index++) {
4675               result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
4676             }
4677             url.host = result;
4678           } else {
4679             input = stringPunycodeToAscii(input);
4680             if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
4681             result = parseIPv4(input);
4682             if (result === null) return INVALID_HOST;
4683             url.host = result;
4684           }
4685         };
4686
4687         var parseIPv4 = function (input) {
4688           var parts = input.split('.');
4689           var partsLength, numbers, index, part, radix, number, ipv4;
4690           if (parts.length && parts[parts.length - 1] == '') {
4691             parts.pop();
4692           }
4693           partsLength = parts.length;
4694           if (partsLength > 4) return input;
4695           numbers = [];
4696           for (index = 0; index < partsLength; index++) {
4697             part = parts[index];
4698             if (part == '') return input;
4699             radix = 10;
4700             if (part.length > 1 && part.charAt(0) == '0') {
4701               radix = HEX_START.test(part) ? 16 : 8;
4702               part = part.slice(radix == 8 ? 1 : 2);
4703             }
4704             if (part === '') {
4705               number = 0;
4706             } else {
4707               if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
4708               number = parseInt(part, radix);
4709             }
4710             numbers.push(number);
4711           }
4712           for (index = 0; index < partsLength; index++) {
4713             number = numbers[index];
4714             if (index == partsLength - 1) {
4715               if (number >= pow$1(256, 5 - partsLength)) return null;
4716             } else if (number > 255) return null;
4717           }
4718           ipv4 = numbers.pop();
4719           for (index = 0; index < numbers.length; index++) {
4720             ipv4 += numbers[index] * pow$1(256, 3 - index);
4721           }
4722           return ipv4;
4723         };
4724
4725         // eslint-disable-next-line max-statements -- TODO
4726         var parseIPv6 = function (input) {
4727           var address = [0, 0, 0, 0, 0, 0, 0, 0];
4728           var pieceIndex = 0;
4729           var compress = null;
4730           var pointer = 0;
4731           var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
4732
4733           var char = function () {
4734             return input.charAt(pointer);
4735           };
4736
4737           if (char() == ':') {
4738             if (input.charAt(1) != ':') return;
4739             pointer += 2;
4740             pieceIndex++;
4741             compress = pieceIndex;
4742           }
4743           while (char()) {
4744             if (pieceIndex == 8) return;
4745             if (char() == ':') {
4746               if (compress !== null) return;
4747               pointer++;
4748               pieceIndex++;
4749               compress = pieceIndex;
4750               continue;
4751             }
4752             value = length = 0;
4753             while (length < 4 && HEX.test(char())) {
4754               value = value * 16 + parseInt(char(), 16);
4755               pointer++;
4756               length++;
4757             }
4758             if (char() == '.') {
4759               if (length == 0) return;
4760               pointer -= length;
4761               if (pieceIndex > 6) return;
4762               numbersSeen = 0;
4763               while (char()) {
4764                 ipv4Piece = null;
4765                 if (numbersSeen > 0) {
4766                   if (char() == '.' && numbersSeen < 4) pointer++;
4767                   else return;
4768                 }
4769                 if (!DIGIT.test(char())) return;
4770                 while (DIGIT.test(char())) {
4771                   number = parseInt(char(), 10);
4772                   if (ipv4Piece === null) ipv4Piece = number;
4773                   else if (ipv4Piece == 0) return;
4774                   else ipv4Piece = ipv4Piece * 10 + number;
4775                   if (ipv4Piece > 255) return;
4776                   pointer++;
4777                 }
4778                 address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
4779                 numbersSeen++;
4780                 if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
4781               }
4782               if (numbersSeen != 4) return;
4783               break;
4784             } else if (char() == ':') {
4785               pointer++;
4786               if (!char()) return;
4787             } else if (char()) return;
4788             address[pieceIndex++] = value;
4789           }
4790           if (compress !== null) {
4791             swaps = pieceIndex - compress;
4792             pieceIndex = 7;
4793             while (pieceIndex != 0 && swaps > 0) {
4794               swap = address[pieceIndex];
4795               address[pieceIndex--] = address[compress + swaps - 1];
4796               address[compress + --swaps] = swap;
4797             }
4798           } else if (pieceIndex != 8) return;
4799           return address;
4800         };
4801
4802         var findLongestZeroSequence = function (ipv6) {
4803           var maxIndex = null;
4804           var maxLength = 1;
4805           var currStart = null;
4806           var currLength = 0;
4807           var index = 0;
4808           for (; index < 8; index++) {
4809             if (ipv6[index] !== 0) {
4810               if (currLength > maxLength) {
4811                 maxIndex = currStart;
4812                 maxLength = currLength;
4813               }
4814               currStart = null;
4815               currLength = 0;
4816             } else {
4817               if (currStart === null) currStart = index;
4818               ++currLength;
4819             }
4820           }
4821           if (currLength > maxLength) {
4822             maxIndex = currStart;
4823             maxLength = currLength;
4824           }
4825           return maxIndex;
4826         };
4827
4828         var serializeHost = function (host) {
4829           var result, index, compress, ignore0;
4830           // ipv4
4831           if (typeof host == 'number') {
4832             result = [];
4833             for (index = 0; index < 4; index++) {
4834               result.unshift(host % 256);
4835               host = floor$4(host / 256);
4836             } return result.join('.');
4837           // ipv6
4838           } else if (typeof host == 'object') {
4839             result = '';
4840             compress = findLongestZeroSequence(host);
4841             for (index = 0; index < 8; index++) {
4842               if (ignore0 && host[index] === 0) continue;
4843               if (ignore0) ignore0 = false;
4844               if (compress === index) {
4845                 result += index ? ':' : '::';
4846                 ignore0 = true;
4847               } else {
4848                 result += host[index].toString(16);
4849                 if (index < 7) result += ':';
4850               }
4851             }
4852             return '[' + result + ']';
4853           } return host;
4854         };
4855
4856         var C0ControlPercentEncodeSet = {};
4857         var fragmentPercentEncodeSet = objectAssign({}, C0ControlPercentEncodeSet, {
4858           ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
4859         });
4860         var pathPercentEncodeSet = objectAssign({}, fragmentPercentEncodeSet, {
4861           '#': 1, '?': 1, '{': 1, '}': 1
4862         });
4863         var userinfoPercentEncodeSet = objectAssign({}, pathPercentEncodeSet, {
4864           '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
4865         });
4866
4867         var percentEncode = function (char, set) {
4868           var code = codeAt(char, 0);
4869           return code > 0x20 && code < 0x7F && !has(set, char) ? char : encodeURIComponent(char);
4870         };
4871
4872         var specialSchemes = {
4873           ftp: 21,
4874           file: null,
4875           http: 80,
4876           https: 443,
4877           ws: 80,
4878           wss: 443
4879         };
4880
4881         var isSpecial = function (url) {
4882           return has(specialSchemes, url.scheme);
4883         };
4884
4885         var includesCredentials = function (url) {
4886           return url.username != '' || url.password != '';
4887         };
4888
4889         var cannotHaveUsernamePasswordPort = function (url) {
4890           return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
4891         };
4892
4893         var isWindowsDriveLetter = function (string, normalized) {
4894           var second;
4895           return string.length == 2 && ALPHA.test(string.charAt(0))
4896             && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
4897         };
4898
4899         var startsWithWindowsDriveLetter = function (string) {
4900           var third;
4901           return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
4902             string.length == 2 ||
4903             ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
4904           );
4905         };
4906
4907         var shortenURLsPath = function (url) {
4908           var path = url.path;
4909           var pathSize = path.length;
4910           if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
4911             path.pop();
4912           }
4913         };
4914
4915         var isSingleDot = function (segment) {
4916           return segment === '.' || segment.toLowerCase() === '%2e';
4917         };
4918
4919         var isDoubleDot = function (segment) {
4920           segment = segment.toLowerCase();
4921           return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
4922         };
4923
4924         // States:
4925         var SCHEME_START = {};
4926         var SCHEME = {};
4927         var NO_SCHEME = {};
4928         var SPECIAL_RELATIVE_OR_AUTHORITY = {};
4929         var PATH_OR_AUTHORITY = {};
4930         var RELATIVE = {};
4931         var RELATIVE_SLASH = {};
4932         var SPECIAL_AUTHORITY_SLASHES = {};
4933         var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
4934         var AUTHORITY = {};
4935         var HOST = {};
4936         var HOSTNAME = {};
4937         var PORT = {};
4938         var FILE = {};
4939         var FILE_SLASH = {};
4940         var FILE_HOST = {};
4941         var PATH_START = {};
4942         var PATH = {};
4943         var CANNOT_BE_A_BASE_URL_PATH = {};
4944         var QUERY = {};
4945         var FRAGMENT = {};
4946
4947         // eslint-disable-next-line max-statements -- TODO
4948         var parseURL = function (url, input, stateOverride, base) {
4949           var state = stateOverride || SCHEME_START;
4950           var pointer = 0;
4951           var buffer = '';
4952           var seenAt = false;
4953           var seenBracket = false;
4954           var seenPasswordToken = false;
4955           var codePoints, char, bufferCodePoints, failure;
4956
4957           if (!stateOverride) {
4958             url.scheme = '';
4959             url.username = '';
4960             url.password = '';
4961             url.host = null;
4962             url.port = null;
4963             url.path = [];
4964             url.query = null;
4965             url.fragment = null;
4966             url.cannotBeABaseURL = false;
4967             input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
4968           }
4969
4970           input = input.replace(TAB_AND_NEW_LINE, '');
4971
4972           codePoints = arrayFrom(input);
4973
4974           while (pointer <= codePoints.length) {
4975             char = codePoints[pointer];
4976             switch (state) {
4977               case SCHEME_START:
4978                 if (char && ALPHA.test(char)) {
4979                   buffer += char.toLowerCase();
4980                   state = SCHEME;
4981                 } else if (!stateOverride) {
4982                   state = NO_SCHEME;
4983                   continue;
4984                 } else return INVALID_SCHEME;
4985                 break;
4986
4987               case SCHEME:
4988                 if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
4989                   buffer += char.toLowerCase();
4990                 } else if (char == ':') {
4991                   if (stateOverride && (
4992                     (isSpecial(url) != has(specialSchemes, buffer)) ||
4993                     (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
4994                     (url.scheme == 'file' && !url.host)
4995                   )) return;
4996                   url.scheme = buffer;
4997                   if (stateOverride) {
4998                     if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
4999                     return;
5000                   }
5001                   buffer = '';
5002                   if (url.scheme == 'file') {
5003                     state = FILE;
5004                   } else if (isSpecial(url) && base && base.scheme == url.scheme) {
5005                     state = SPECIAL_RELATIVE_OR_AUTHORITY;
5006                   } else if (isSpecial(url)) {
5007                     state = SPECIAL_AUTHORITY_SLASHES;
5008                   } else if (codePoints[pointer + 1] == '/') {
5009                     state = PATH_OR_AUTHORITY;
5010                     pointer++;
5011                   } else {
5012                     url.cannotBeABaseURL = true;
5013                     url.path.push('');
5014                     state = CANNOT_BE_A_BASE_URL_PATH;
5015                   }
5016                 } else if (!stateOverride) {
5017                   buffer = '';
5018                   state = NO_SCHEME;
5019                   pointer = 0;
5020                   continue;
5021                 } else return INVALID_SCHEME;
5022                 break;
5023
5024               case NO_SCHEME:
5025                 if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
5026                 if (base.cannotBeABaseURL && char == '#') {
5027                   url.scheme = base.scheme;
5028                   url.path = base.path.slice();
5029                   url.query = base.query;
5030                   url.fragment = '';
5031                   url.cannotBeABaseURL = true;
5032                   state = FRAGMENT;
5033                   break;
5034                 }
5035                 state = base.scheme == 'file' ? FILE : RELATIVE;
5036                 continue;
5037
5038               case SPECIAL_RELATIVE_OR_AUTHORITY:
5039                 if (char == '/' && codePoints[pointer + 1] == '/') {
5040                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5041                   pointer++;
5042                 } else {
5043                   state = RELATIVE;
5044                   continue;
5045                 } break;
5046
5047               case PATH_OR_AUTHORITY:
5048                 if (char == '/') {
5049                   state = AUTHORITY;
5050                   break;
5051                 } else {
5052                   state = PATH;
5053                   continue;
5054                 }
5055
5056               case RELATIVE:
5057                 url.scheme = base.scheme;
5058                 if (char == EOF) {
5059                   url.username = base.username;
5060                   url.password = base.password;
5061                   url.host = base.host;
5062                   url.port = base.port;
5063                   url.path = base.path.slice();
5064                   url.query = base.query;
5065                 } else if (char == '/' || (char == '\\' && isSpecial(url))) {
5066                   state = RELATIVE_SLASH;
5067                 } else if (char == '?') {
5068                   url.username = base.username;
5069                   url.password = base.password;
5070                   url.host = base.host;
5071                   url.port = base.port;
5072                   url.path = base.path.slice();
5073                   url.query = '';
5074                   state = QUERY;
5075                 } else if (char == '#') {
5076                   url.username = base.username;
5077                   url.password = base.password;
5078                   url.host = base.host;
5079                   url.port = base.port;
5080                   url.path = base.path.slice();
5081                   url.query = base.query;
5082                   url.fragment = '';
5083                   state = FRAGMENT;
5084                 } else {
5085                   url.username = base.username;
5086                   url.password = base.password;
5087                   url.host = base.host;
5088                   url.port = base.port;
5089                   url.path = base.path.slice();
5090                   url.path.pop();
5091                   state = PATH;
5092                   continue;
5093                 } break;
5094
5095               case RELATIVE_SLASH:
5096                 if (isSpecial(url) && (char == '/' || char == '\\')) {
5097                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5098                 } else if (char == '/') {
5099                   state = AUTHORITY;
5100                 } else {
5101                   url.username = base.username;
5102                   url.password = base.password;
5103                   url.host = base.host;
5104                   url.port = base.port;
5105                   state = PATH;
5106                   continue;
5107                 } break;
5108
5109               case SPECIAL_AUTHORITY_SLASHES:
5110                 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5111                 if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
5112                 pointer++;
5113                 break;
5114
5115               case SPECIAL_AUTHORITY_IGNORE_SLASHES:
5116                 if (char != '/' && char != '\\') {
5117                   state = AUTHORITY;
5118                   continue;
5119                 } break;
5120
5121               case AUTHORITY:
5122                 if (char == '@') {
5123                   if (seenAt) buffer = '%40' + buffer;
5124                   seenAt = true;
5125                   bufferCodePoints = arrayFrom(buffer);
5126                   for (var i = 0; i < bufferCodePoints.length; i++) {
5127                     var codePoint = bufferCodePoints[i];
5128                     if (codePoint == ':' && !seenPasswordToken) {
5129                       seenPasswordToken = true;
5130                       continue;
5131                     }
5132                     var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
5133                     if (seenPasswordToken) url.password += encodedCodePoints;
5134                     else url.username += encodedCodePoints;
5135                   }
5136                   buffer = '';
5137                 } else if (
5138                   char == EOF || char == '/' || char == '?' || char == '#' ||
5139                   (char == '\\' && isSpecial(url))
5140                 ) {
5141                   if (seenAt && buffer == '') return INVALID_AUTHORITY;
5142                   pointer -= arrayFrom(buffer).length + 1;
5143                   buffer = '';
5144                   state = HOST;
5145                 } else buffer += char;
5146                 break;
5147
5148               case HOST:
5149               case HOSTNAME:
5150                 if (stateOverride && url.scheme == 'file') {
5151                   state = FILE_HOST;
5152                   continue;
5153                 } else if (char == ':' && !seenBracket) {
5154                   if (buffer == '') return INVALID_HOST;
5155                   failure = parseHost(url, buffer);
5156                   if (failure) return failure;
5157                   buffer = '';
5158                   state = PORT;
5159                   if (stateOverride == HOSTNAME) return;
5160                 } else if (
5161                   char == EOF || char == '/' || char == '?' || char == '#' ||
5162                   (char == '\\' && isSpecial(url))
5163                 ) {
5164                   if (isSpecial(url) && buffer == '') return INVALID_HOST;
5165                   if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
5166                   failure = parseHost(url, buffer);
5167                   if (failure) return failure;
5168                   buffer = '';
5169                   state = PATH_START;
5170                   if (stateOverride) return;
5171                   continue;
5172                 } else {
5173                   if (char == '[') seenBracket = true;
5174                   else if (char == ']') seenBracket = false;
5175                   buffer += char;
5176                 } break;
5177
5178               case PORT:
5179                 if (DIGIT.test(char)) {
5180                   buffer += char;
5181                 } else if (
5182                   char == EOF || char == '/' || char == '?' || char == '#' ||
5183                   (char == '\\' && isSpecial(url)) ||
5184                   stateOverride
5185                 ) {
5186                   if (buffer != '') {
5187                     var port = parseInt(buffer, 10);
5188                     if (port > 0xFFFF) return INVALID_PORT;
5189                     url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
5190                     buffer = '';
5191                   }
5192                   if (stateOverride) return;
5193                   state = PATH_START;
5194                   continue;
5195                 } else return INVALID_PORT;
5196                 break;
5197
5198               case FILE:
5199                 url.scheme = 'file';
5200                 if (char == '/' || char == '\\') state = FILE_SLASH;
5201                 else if (base && base.scheme == 'file') {
5202                   if (char == EOF) {
5203                     url.host = base.host;
5204                     url.path = base.path.slice();
5205                     url.query = base.query;
5206                   } else if (char == '?') {
5207                     url.host = base.host;
5208                     url.path = base.path.slice();
5209                     url.query = '';
5210                     state = QUERY;
5211                   } else if (char == '#') {
5212                     url.host = base.host;
5213                     url.path = base.path.slice();
5214                     url.query = base.query;
5215                     url.fragment = '';
5216                     state = FRAGMENT;
5217                   } else {
5218                     if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5219                       url.host = base.host;
5220                       url.path = base.path.slice();
5221                       shortenURLsPath(url);
5222                     }
5223                     state = PATH;
5224                     continue;
5225                   }
5226                 } else {
5227                   state = PATH;
5228                   continue;
5229                 } break;
5230
5231               case FILE_SLASH:
5232                 if (char == '/' || char == '\\') {
5233                   state = FILE_HOST;
5234                   break;
5235                 }
5236                 if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5237                   if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
5238                   else url.host = base.host;
5239                 }
5240                 state = PATH;
5241                 continue;
5242
5243               case FILE_HOST:
5244                 if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
5245                   if (!stateOverride && isWindowsDriveLetter(buffer)) {
5246                     state = PATH;
5247                   } else if (buffer == '') {
5248                     url.host = '';
5249                     if (stateOverride) return;
5250                     state = PATH_START;
5251                   } else {
5252                     failure = parseHost(url, buffer);
5253                     if (failure) return failure;
5254                     if (url.host == 'localhost') url.host = '';
5255                     if (stateOverride) return;
5256                     buffer = '';
5257                     state = PATH_START;
5258                   } continue;
5259                 } else buffer += char;
5260                 break;
5261
5262               case PATH_START:
5263                 if (isSpecial(url)) {
5264                   state = PATH;
5265                   if (char != '/' && char != '\\') continue;
5266                 } else if (!stateOverride && char == '?') {
5267                   url.query = '';
5268                   state = QUERY;
5269                 } else if (!stateOverride && char == '#') {
5270                   url.fragment = '';
5271                   state = FRAGMENT;
5272                 } else if (char != EOF) {
5273                   state = PATH;
5274                   if (char != '/') continue;
5275                 } break;
5276
5277               case PATH:
5278                 if (
5279                   char == EOF || char == '/' ||
5280                   (char == '\\' && isSpecial(url)) ||
5281                   (!stateOverride && (char == '?' || char == '#'))
5282                 ) {
5283                   if (isDoubleDot(buffer)) {
5284                     shortenURLsPath(url);
5285                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5286                       url.path.push('');
5287                     }
5288                   } else if (isSingleDot(buffer)) {
5289                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5290                       url.path.push('');
5291                     }
5292                   } else {
5293                     if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
5294                       if (url.host) url.host = '';
5295                       buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
5296                     }
5297                     url.path.push(buffer);
5298                   }
5299                   buffer = '';
5300                   if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
5301                     while (url.path.length > 1 && url.path[0] === '') {
5302                       url.path.shift();
5303                     }
5304                   }
5305                   if (char == '?') {
5306                     url.query = '';
5307                     state = QUERY;
5308                   } else if (char == '#') {
5309                     url.fragment = '';
5310                     state = FRAGMENT;
5311                   }
5312                 } else {
5313                   buffer += percentEncode(char, pathPercentEncodeSet);
5314                 } break;
5315
5316               case CANNOT_BE_A_BASE_URL_PATH:
5317                 if (char == '?') {
5318                   url.query = '';
5319                   state = QUERY;
5320                 } else if (char == '#') {
5321                   url.fragment = '';
5322                   state = FRAGMENT;
5323                 } else if (char != EOF) {
5324                   url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
5325                 } break;
5326
5327               case QUERY:
5328                 if (!stateOverride && char == '#') {
5329                   url.fragment = '';
5330                   state = FRAGMENT;
5331                 } else if (char != EOF) {
5332                   if (char == "'" && isSpecial(url)) url.query += '%27';
5333                   else if (char == '#') url.query += '%23';
5334                   else url.query += percentEncode(char, C0ControlPercentEncodeSet);
5335                 } break;
5336
5337               case FRAGMENT:
5338                 if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
5339                 break;
5340             }
5341
5342             pointer++;
5343           }
5344         };
5345
5346         // `URL` constructor
5347         // https://url.spec.whatwg.org/#url-class
5348         var URLConstructor = function URL(url /* , base */) {
5349           var that = anInstance(this, URLConstructor, 'URL');
5350           var base = arguments.length > 1 ? arguments[1] : undefined;
5351           var urlString = String(url);
5352           var state = setInternalState$6(that, { type: 'URL' });
5353           var baseState, failure;
5354           if (base !== undefined) {
5355             if (base instanceof URLConstructor) baseState = getInternalURLState(base);
5356             else {
5357               failure = parseURL(baseState = {}, String(base));
5358               if (failure) throw TypeError(failure);
5359             }
5360           }
5361           failure = parseURL(state, urlString, null, baseState);
5362           if (failure) throw TypeError(failure);
5363           var searchParams = state.searchParams = new URLSearchParams$1();
5364           var searchParamsState = getInternalSearchParamsState(searchParams);
5365           searchParamsState.updateSearchParams(state.query);
5366           searchParamsState.updateURL = function () {
5367             state.query = String(searchParams) || null;
5368           };
5369           if (!descriptors) {
5370             that.href = serializeURL.call(that);
5371             that.origin = getOrigin.call(that);
5372             that.protocol = getProtocol.call(that);
5373             that.username = getUsername.call(that);
5374             that.password = getPassword.call(that);
5375             that.host = getHost.call(that);
5376             that.hostname = getHostname.call(that);
5377             that.port = getPort.call(that);
5378             that.pathname = getPathname.call(that);
5379             that.search = getSearch.call(that);
5380             that.searchParams = getSearchParams.call(that);
5381             that.hash = getHash.call(that);
5382           }
5383         };
5384
5385         var URLPrototype = URLConstructor.prototype;
5386
5387         var serializeURL = function () {
5388           var url = getInternalURLState(this);
5389           var scheme = url.scheme;
5390           var username = url.username;
5391           var password = url.password;
5392           var host = url.host;
5393           var port = url.port;
5394           var path = url.path;
5395           var query = url.query;
5396           var fragment = url.fragment;
5397           var output = scheme + ':';
5398           if (host !== null) {
5399             output += '//';
5400             if (includesCredentials(url)) {
5401               output += username + (password ? ':' + password : '') + '@';
5402             }
5403             output += serializeHost(host);
5404             if (port !== null) output += ':' + port;
5405           } else if (scheme == 'file') output += '//';
5406           output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5407           if (query !== null) output += '?' + query;
5408           if (fragment !== null) output += '#' + fragment;
5409           return output;
5410         };
5411
5412         var getOrigin = function () {
5413           var url = getInternalURLState(this);
5414           var scheme = url.scheme;
5415           var port = url.port;
5416           if (scheme == 'blob') try {
5417             return new URL(scheme.path[0]).origin;
5418           } catch (error) {
5419             return 'null';
5420           }
5421           if (scheme == 'file' || !isSpecial(url)) return 'null';
5422           return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
5423         };
5424
5425         var getProtocol = function () {
5426           return getInternalURLState(this).scheme + ':';
5427         };
5428
5429         var getUsername = function () {
5430           return getInternalURLState(this).username;
5431         };
5432
5433         var getPassword = function () {
5434           return getInternalURLState(this).password;
5435         };
5436
5437         var getHost = function () {
5438           var url = getInternalURLState(this);
5439           var host = url.host;
5440           var port = url.port;
5441           return host === null ? ''
5442             : port === null ? serializeHost(host)
5443             : serializeHost(host) + ':' + port;
5444         };
5445
5446         var getHostname = function () {
5447           var host = getInternalURLState(this).host;
5448           return host === null ? '' : serializeHost(host);
5449         };
5450
5451         var getPort = function () {
5452           var port = getInternalURLState(this).port;
5453           return port === null ? '' : String(port);
5454         };
5455
5456         var getPathname = function () {
5457           var url = getInternalURLState(this);
5458           var path = url.path;
5459           return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5460         };
5461
5462         var getSearch = function () {
5463           var query = getInternalURLState(this).query;
5464           return query ? '?' + query : '';
5465         };
5466
5467         var getSearchParams = function () {
5468           return getInternalURLState(this).searchParams;
5469         };
5470
5471         var getHash = function () {
5472           var fragment = getInternalURLState(this).fragment;
5473           return fragment ? '#' + fragment : '';
5474         };
5475
5476         var accessorDescriptor = function (getter, setter) {
5477           return { get: getter, set: setter, configurable: true, enumerable: true };
5478         };
5479
5480         if (descriptors) {
5481           objectDefineProperties(URLPrototype, {
5482             // `URL.prototype.href` accessors pair
5483             // https://url.spec.whatwg.org/#dom-url-href
5484             href: accessorDescriptor(serializeURL, function (href) {
5485               var url = getInternalURLState(this);
5486               var urlString = String(href);
5487               var failure = parseURL(url, urlString);
5488               if (failure) throw TypeError(failure);
5489               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
5490             }),
5491             // `URL.prototype.origin` getter
5492             // https://url.spec.whatwg.org/#dom-url-origin
5493             origin: accessorDescriptor(getOrigin),
5494             // `URL.prototype.protocol` accessors pair
5495             // https://url.spec.whatwg.org/#dom-url-protocol
5496             protocol: accessorDescriptor(getProtocol, function (protocol) {
5497               var url = getInternalURLState(this);
5498               parseURL(url, String(protocol) + ':', SCHEME_START);
5499             }),
5500             // `URL.prototype.username` accessors pair
5501             // https://url.spec.whatwg.org/#dom-url-username
5502             username: accessorDescriptor(getUsername, function (username) {
5503               var url = getInternalURLState(this);
5504               var codePoints = arrayFrom(String(username));
5505               if (cannotHaveUsernamePasswordPort(url)) return;
5506               url.username = '';
5507               for (var i = 0; i < codePoints.length; i++) {
5508                 url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5509               }
5510             }),
5511             // `URL.prototype.password` accessors pair
5512             // https://url.spec.whatwg.org/#dom-url-password
5513             password: accessorDescriptor(getPassword, function (password) {
5514               var url = getInternalURLState(this);
5515               var codePoints = arrayFrom(String(password));
5516               if (cannotHaveUsernamePasswordPort(url)) return;
5517               url.password = '';
5518               for (var i = 0; i < codePoints.length; i++) {
5519                 url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5520               }
5521             }),
5522             // `URL.prototype.host` accessors pair
5523             // https://url.spec.whatwg.org/#dom-url-host
5524             host: accessorDescriptor(getHost, function (host) {
5525               var url = getInternalURLState(this);
5526               if (url.cannotBeABaseURL) return;
5527               parseURL(url, String(host), HOST);
5528             }),
5529             // `URL.prototype.hostname` accessors pair
5530             // https://url.spec.whatwg.org/#dom-url-hostname
5531             hostname: accessorDescriptor(getHostname, function (hostname) {
5532               var url = getInternalURLState(this);
5533               if (url.cannotBeABaseURL) return;
5534               parseURL(url, String(hostname), HOSTNAME);
5535             }),
5536             // `URL.prototype.port` accessors pair
5537             // https://url.spec.whatwg.org/#dom-url-port
5538             port: accessorDescriptor(getPort, function (port) {
5539               var url = getInternalURLState(this);
5540               if (cannotHaveUsernamePasswordPort(url)) return;
5541               port = String(port);
5542               if (port == '') url.port = null;
5543               else parseURL(url, port, PORT);
5544             }),
5545             // `URL.prototype.pathname` accessors pair
5546             // https://url.spec.whatwg.org/#dom-url-pathname
5547             pathname: accessorDescriptor(getPathname, function (pathname) {
5548               var url = getInternalURLState(this);
5549               if (url.cannotBeABaseURL) return;
5550               url.path = [];
5551               parseURL(url, pathname + '', PATH_START);
5552             }),
5553             // `URL.prototype.search` accessors pair
5554             // https://url.spec.whatwg.org/#dom-url-search
5555             search: accessorDescriptor(getSearch, function (search) {
5556               var url = getInternalURLState(this);
5557               search = String(search);
5558               if (search == '') {
5559                 url.query = null;
5560               } else {
5561                 if ('?' == search.charAt(0)) search = search.slice(1);
5562                 url.query = '';
5563                 parseURL(url, search, QUERY);
5564               }
5565               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
5566             }),
5567             // `URL.prototype.searchParams` getter
5568             // https://url.spec.whatwg.org/#dom-url-searchparams
5569             searchParams: accessorDescriptor(getSearchParams),
5570             // `URL.prototype.hash` accessors pair
5571             // https://url.spec.whatwg.org/#dom-url-hash
5572             hash: accessorDescriptor(getHash, function (hash) {
5573               var url = getInternalURLState(this);
5574               hash = String(hash);
5575               if (hash == '') {
5576                 url.fragment = null;
5577                 return;
5578               }
5579               if ('#' == hash.charAt(0)) hash = hash.slice(1);
5580               url.fragment = '';
5581               parseURL(url, hash, FRAGMENT);
5582             })
5583           });
5584         }
5585
5586         // `URL.prototype.toJSON` method
5587         // https://url.spec.whatwg.org/#dom-url-tojson
5588         redefine(URLPrototype, 'toJSON', function toJSON() {
5589           return serializeURL.call(this);
5590         }, { enumerable: true });
5591
5592         // `URL.prototype.toString` method
5593         // https://url.spec.whatwg.org/#URL-stringification-behavior
5594         redefine(URLPrototype, 'toString', function toString() {
5595           return serializeURL.call(this);
5596         }, { enumerable: true });
5597
5598         if (NativeURL) {
5599           var nativeCreateObjectURL = NativeURL.createObjectURL;
5600           var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
5601           // `URL.createObjectURL` method
5602           // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
5603           // eslint-disable-next-line no-unused-vars -- required for `.length`
5604           if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
5605             return nativeCreateObjectURL.apply(NativeURL, arguments);
5606           });
5607           // `URL.revokeObjectURL` method
5608           // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
5609           // eslint-disable-next-line no-unused-vars -- required for `.length`
5610           if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
5611             return nativeRevokeObjectURL.apply(NativeURL, arguments);
5612           });
5613         }
5614
5615         setToStringTag(URLConstructor, 'URL');
5616
5617         _export({ global: true, forced: !nativeUrl, sham: !descriptors }, {
5618           URL: URLConstructor
5619         });
5620
5621         // `RegExp.prototype.flags` getter implementation
5622         // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
5623         var regexpFlags = function () {
5624           var that = anObject(this);
5625           var result = '';
5626           if (that.global) result += 'g';
5627           if (that.ignoreCase) result += 'i';
5628           if (that.multiline) result += 'm';
5629           if (that.dotAll) result += 's';
5630           if (that.unicode) result += 'u';
5631           if (that.sticky) result += 'y';
5632           return result;
5633         };
5634
5635         var TO_STRING$1 = 'toString';
5636         var RegExpPrototype = RegExp.prototype;
5637         var nativeToString = RegExpPrototype[TO_STRING$1];
5638
5639         var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
5640         // FF44- RegExp#toString has a wrong name
5641         var INCORRECT_NAME = nativeToString.name != TO_STRING$1;
5642
5643         // `RegExp.prototype.toString` method
5644         // https://tc39.es/ecma262/#sec-regexp.prototype.tostring
5645         if (NOT_GENERIC || INCORRECT_NAME) {
5646           redefine(RegExp.prototype, TO_STRING$1, function toString() {
5647             var R = anObject(this);
5648             var p = String(R.source);
5649             var rf = R.flags;
5650             var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf);
5651             return '/' + p + '/' + f;
5652           }, { unsafe: true });
5653         }
5654
5655         // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
5656         // so we use an intermediate function.
5657         function RE(s, f) {
5658           return RegExp(s, f);
5659         }
5660
5661         var UNSUPPORTED_Y = fails(function () {
5662           // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError
5663           var re = RE('a', 'y');
5664           re.lastIndex = 2;
5665           return re.exec('abcd') != null;
5666         });
5667
5668         var BROKEN_CARET = fails(function () {
5669           // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
5670           var re = RE('^r', 'gy');
5671           re.lastIndex = 2;
5672           return re.exec('str') != null;
5673         });
5674
5675         var regexpStickyHelpers = {
5676                 UNSUPPORTED_Y: UNSUPPORTED_Y,
5677                 BROKEN_CARET: BROKEN_CARET
5678         };
5679
5680         var nativeExec = RegExp.prototype.exec;
5681         // This always refers to the native implementation, because the
5682         // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
5683         // which loads this file before patching the method.
5684         var nativeReplace = String.prototype.replace;
5685
5686         var patchedExec = nativeExec;
5687
5688         var UPDATES_LAST_INDEX_WRONG = (function () {
5689           var re1 = /a/;
5690           var re2 = /b*/g;
5691           nativeExec.call(re1, 'a');
5692           nativeExec.call(re2, 'a');
5693           return re1.lastIndex !== 0 || re2.lastIndex !== 0;
5694         })();
5695
5696         var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET;
5697
5698         // nonparticipating capturing group, copied from es5-shim's String#split patch.
5699         // eslint-disable-next-line regexp/no-assertion-capturing-group, regexp/no-empty-group -- required for testing
5700         var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
5701
5702         var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1;
5703
5704         if (PATCH) {
5705           patchedExec = function exec(str) {
5706             var re = this;
5707             var lastIndex, reCopy, match, i;
5708             var sticky = UNSUPPORTED_Y$1 && re.sticky;
5709             var flags = regexpFlags.call(re);
5710             var source = re.source;
5711             var charsAdded = 0;
5712             var strCopy = str;
5713
5714             if (sticky) {
5715               flags = flags.replace('y', '');
5716               if (flags.indexOf('g') === -1) {
5717                 flags += 'g';
5718               }
5719
5720               strCopy = String(str).slice(re.lastIndex);
5721               // Support anchored sticky behavior.
5722               if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
5723                 source = '(?: ' + source + ')';
5724                 strCopy = ' ' + strCopy;
5725                 charsAdded++;
5726               }
5727               // ^(? + rx + ) is needed, in combination with some str slicing, to
5728               // simulate the 'y' flag.
5729               reCopy = new RegExp('^(?:' + source + ')', flags);
5730             }
5731
5732             if (NPCG_INCLUDED) {
5733               reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
5734             }
5735             if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
5736
5737             match = nativeExec.call(sticky ? reCopy : re, strCopy);
5738
5739             if (sticky) {
5740               if (match) {
5741                 match.input = match.input.slice(charsAdded);
5742                 match[0] = match[0].slice(charsAdded);
5743                 match.index = re.lastIndex;
5744                 re.lastIndex += match[0].length;
5745               } else re.lastIndex = 0;
5746             } else if (UPDATES_LAST_INDEX_WRONG && match) {
5747               re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
5748             }
5749             if (NPCG_INCLUDED && match && match.length > 1) {
5750               // Fix browsers whose `exec` methods don't consistently return `undefined`
5751               // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
5752               nativeReplace.call(match[0], reCopy, function () {
5753                 for (i = 1; i < arguments.length - 2; i++) {
5754                   if (arguments[i] === undefined) match[i] = undefined;
5755                 }
5756               });
5757             }
5758
5759             return match;
5760           };
5761         }
5762
5763         var regexpExec = patchedExec;
5764
5765         // `RegExp.prototype.exec` method
5766         // https://tc39.es/ecma262/#sec-regexp.prototype.exec
5767         _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {
5768           exec: regexpExec
5769         });
5770
5771         // TODO: Remove from `core-js@4` since it's moved to entry points
5772
5773
5774
5775
5776
5777
5778
5779         var SPECIES$6 = wellKnownSymbol('species');
5780
5781         var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
5782           // #replace needs built-in support for named groups.
5783           // #match works fine because it just return the exec results, even if it has
5784           // a "grops" property.
5785           var re = /./;
5786           re.exec = function () {
5787             var result = [];
5788             result.groups = { a: '7' };
5789             return result;
5790           };
5791           return ''.replace(re, '$<a>') !== '7';
5792         });
5793
5794         // IE <= 11 replaces $0 with the whole match, as if it was $&
5795         // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
5796         var REPLACE_KEEPS_$0 = (function () {
5797           return 'a'.replace(/./, '$0') === '$0';
5798         })();
5799
5800         var REPLACE = wellKnownSymbol('replace');
5801         // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
5802         var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
5803           if (/./[REPLACE]) {
5804             return /./[REPLACE]('a', '$0') === '';
5805           }
5806           return false;
5807         })();
5808
5809         // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
5810         // Weex JS has frozen built-in prototypes, so use try / catch wrapper
5811         var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
5812           // eslint-disable-next-line regexp/no-empty-group -- required for testing
5813           var re = /(?:)/;
5814           var originalExec = re.exec;
5815           re.exec = function () { return originalExec.apply(this, arguments); };
5816           var result = 'ab'.split(re);
5817           return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
5818         });
5819
5820         var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
5821           var SYMBOL = wellKnownSymbol(KEY);
5822
5823           var DELEGATES_TO_SYMBOL = !fails(function () {
5824             // String methods call symbol-named RegEp methods
5825             var O = {};
5826             O[SYMBOL] = function () { return 7; };
5827             return ''[KEY](O) != 7;
5828           });
5829
5830           var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
5831             // Symbol-named RegExp methods call .exec
5832             var execCalled = false;
5833             var re = /a/;
5834
5835             if (KEY === 'split') {
5836               // We can't use real regex here since it causes deoptimization
5837               // and serious performance degradation in V8
5838               // https://github.com/zloirock/core-js/issues/306
5839               re = {};
5840               // RegExp[@@split] doesn't call the regex's exec method, but first creates
5841               // a new one. We need to return the patched regex when creating the new one.
5842               re.constructor = {};
5843               re.constructor[SPECIES$6] = function () { return re; };
5844               re.flags = '';
5845               re[SYMBOL] = /./[SYMBOL];
5846             }
5847
5848             re.exec = function () { execCalled = true; return null; };
5849
5850             re[SYMBOL]('');
5851             return !execCalled;
5852           });
5853
5854           if (
5855             !DELEGATES_TO_SYMBOL ||
5856             !DELEGATES_TO_EXEC ||
5857             (KEY === 'replace' && !(
5858               REPLACE_SUPPORTS_NAMED_GROUPS &&
5859               REPLACE_KEEPS_$0 &&
5860               !REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
5861             )) ||
5862             (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
5863           ) {
5864             var nativeRegExpMethod = /./[SYMBOL];
5865             var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
5866               if (regexp.exec === regexpExec) {
5867                 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
5868                   // The native String method already delegates to @@method (this
5869                   // polyfilled function), leasing to infinite recursion.
5870                   // We avoid it by directly calling the native @@method method.
5871                   return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
5872                 }
5873                 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
5874               }
5875               return { done: false };
5876             }, {
5877               REPLACE_KEEPS_$0: REPLACE_KEEPS_$0,
5878               REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
5879             });
5880             var stringMethod = methods[0];
5881             var regexMethod = methods[1];
5882
5883             redefine(String.prototype, KEY, stringMethod);
5884             redefine(RegExp.prototype, SYMBOL, length == 2
5885               // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
5886               // 21.2.5.11 RegExp.prototype[@@split](string, limit)
5887               ? function (string, arg) { return regexMethod.call(string, this, arg); }
5888               // 21.2.5.6 RegExp.prototype[@@match](string)
5889               // 21.2.5.9 RegExp.prototype[@@search](string)
5890               : function (string) { return regexMethod.call(string, this); }
5891             );
5892           }
5893
5894           if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
5895         };
5896
5897         var charAt$1 = stringMultibyte.charAt;
5898
5899         // `AdvanceStringIndex` abstract operation
5900         // https://tc39.es/ecma262/#sec-advancestringindex
5901         var advanceStringIndex = function (S, index, unicode) {
5902           return index + (unicode ? charAt$1(S, index).length : 1);
5903         };
5904
5905         var floor$5 = Math.floor;
5906         var replace$1 = ''.replace;
5907         var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g;
5908         var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g;
5909
5910         // https://tc39.es/ecma262/#sec-getsubstitution
5911         var getSubstitution = function (matched, str, position, captures, namedCaptures, replacement) {
5912           var tailPos = position + matched.length;
5913           var m = captures.length;
5914           var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
5915           if (namedCaptures !== undefined) {
5916             namedCaptures = toObject(namedCaptures);
5917             symbols = SUBSTITUTION_SYMBOLS;
5918           }
5919           return replace$1.call(replacement, symbols, function (match, ch) {
5920             var capture;
5921             switch (ch.charAt(0)) {
5922               case '$': return '$';
5923               case '&': return matched;
5924               case '`': return str.slice(0, position);
5925               case "'": return str.slice(tailPos);
5926               case '<':
5927                 capture = namedCaptures[ch.slice(1, -1)];
5928                 break;
5929               default: // \d\d?
5930                 var n = +ch;
5931                 if (n === 0) return match;
5932                 if (n > m) {
5933                   var f = floor$5(n / 10);
5934                   if (f === 0) return match;
5935                   if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
5936                   return match;
5937                 }
5938                 capture = captures[n - 1];
5939             }
5940             return capture === undefined ? '' : capture;
5941           });
5942         };
5943
5944         // `RegExpExec` abstract operation
5945         // https://tc39.es/ecma262/#sec-regexpexec
5946         var regexpExecAbstract = function (R, S) {
5947           var exec = R.exec;
5948           if (typeof exec === 'function') {
5949             var result = exec.call(R, S);
5950             if (typeof result !== 'object') {
5951               throw TypeError('RegExp exec method returned something other than an Object or null');
5952             }
5953             return result;
5954           }
5955
5956           if (classofRaw(R) !== 'RegExp') {
5957             throw TypeError('RegExp#exec called on incompatible receiver');
5958           }
5959
5960           return regexpExec.call(R, S);
5961         };
5962
5963         var max$2 = Math.max;
5964         var min$4 = Math.min;
5965
5966         var maybeToString = function (it) {
5967           return it === undefined ? it : String(it);
5968         };
5969
5970         // @@replace logic
5971         fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative, reason) {
5972           var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE;
5973           var REPLACE_KEEPS_$0 = reason.REPLACE_KEEPS_$0;
5974           var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
5975
5976           return [
5977             // `String.prototype.replace` method
5978             // https://tc39.es/ecma262/#sec-string.prototype.replace
5979             function replace(searchValue, replaceValue) {
5980               var O = requireObjectCoercible(this);
5981               var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
5982               return replacer !== undefined
5983                 ? replacer.call(searchValue, O, replaceValue)
5984                 : nativeReplace.call(String(O), searchValue, replaceValue);
5985             },
5986             // `RegExp.prototype[@@replace]` method
5987             // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
5988             function (regexp, replaceValue) {
5989               if (
5990                 (!REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && REPLACE_KEEPS_$0) ||
5991                 (typeof replaceValue === 'string' && replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1)
5992               ) {
5993                 var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
5994                 if (res.done) return res.value;
5995               }
5996
5997               var rx = anObject(regexp);
5998               var S = String(this);
5999
6000               var functionalReplace = typeof replaceValue === 'function';
6001               if (!functionalReplace) replaceValue = String(replaceValue);
6002
6003               var global = rx.global;
6004               if (global) {
6005                 var fullUnicode = rx.unicode;
6006                 rx.lastIndex = 0;
6007               }
6008               var results = [];
6009               while (true) {
6010                 var result = regexpExecAbstract(rx, S);
6011                 if (result === null) break;
6012
6013                 results.push(result);
6014                 if (!global) break;
6015
6016                 var matchStr = String(result[0]);
6017                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
6018               }
6019
6020               var accumulatedResult = '';
6021               var nextSourcePosition = 0;
6022               for (var i = 0; i < results.length; i++) {
6023                 result = results[i];
6024
6025                 var matched = String(result[0]);
6026                 var position = max$2(min$4(toInteger(result.index), S.length), 0);
6027                 var captures = [];
6028                 // NOTE: This is equivalent to
6029                 //   captures = result.slice(1).map(maybeToString)
6030                 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
6031                 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
6032                 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
6033                 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
6034                 var namedCaptures = result.groups;
6035                 if (functionalReplace) {
6036                   var replacerArgs = [matched].concat(captures, position, S);
6037                   if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
6038                   var replacement = String(replaceValue.apply(undefined, replacerArgs));
6039                 } else {
6040                   replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
6041                 }
6042                 if (position >= nextSourcePosition) {
6043                   accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
6044                   nextSourcePosition = position + matched.length;
6045                 }
6046               }
6047               return accumulatedResult + S.slice(nextSourcePosition);
6048             }
6049           ];
6050         });
6051
6052         var MATCH = wellKnownSymbol('match');
6053
6054         // `IsRegExp` abstract operation
6055         // https://tc39.es/ecma262/#sec-isregexp
6056         var isRegexp = function (it) {
6057           var isRegExp;
6058           return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
6059         };
6060
6061         var arrayPush = [].push;
6062         var min$5 = Math.min;
6063         var MAX_UINT32 = 0xFFFFFFFF;
6064
6065         // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError
6066         var SUPPORTS_Y = !fails(function () { return !RegExp(MAX_UINT32, 'y'); });
6067
6068         // @@split logic
6069         fixRegexpWellKnownSymbolLogic('split', 2, function (SPLIT, nativeSplit, maybeCallNative) {
6070           var internalSplit;
6071           if (
6072             'abbc'.split(/(b)*/)[1] == 'c' ||
6073             // eslint-disable-next-line regexp/no-empty-group -- required for testing
6074             'test'.split(/(?:)/, -1).length != 4 ||
6075             'ab'.split(/(?:ab)*/).length != 2 ||
6076             '.'.split(/(.?)(.?)/).length != 4 ||
6077             // eslint-disable-next-line regexp/no-assertion-capturing-group, regexp/no-empty-group -- required for testing
6078             '.'.split(/()()/).length > 1 ||
6079             ''.split(/.?/).length
6080           ) {
6081             // based on es5-shim implementation, need to rework it
6082             internalSplit = function (separator, limit) {
6083               var string = String(requireObjectCoercible(this));
6084               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6085               if (lim === 0) return [];
6086               if (separator === undefined) return [string];
6087               // If `separator` is not a regex, use native split
6088               if (!isRegexp(separator)) {
6089                 return nativeSplit.call(string, separator, lim);
6090               }
6091               var output = [];
6092               var flags = (separator.ignoreCase ? 'i' : '') +
6093                           (separator.multiline ? 'm' : '') +
6094                           (separator.unicode ? 'u' : '') +
6095                           (separator.sticky ? 'y' : '');
6096               var lastLastIndex = 0;
6097               // Make `global` and avoid `lastIndex` issues by working with a copy
6098               var separatorCopy = new RegExp(separator.source, flags + 'g');
6099               var match, lastIndex, lastLength;
6100               while (match = regexpExec.call(separatorCopy, string)) {
6101                 lastIndex = separatorCopy.lastIndex;
6102                 if (lastIndex > lastLastIndex) {
6103                   output.push(string.slice(lastLastIndex, match.index));
6104                   if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
6105                   lastLength = match[0].length;
6106                   lastLastIndex = lastIndex;
6107                   if (output.length >= lim) break;
6108                 }
6109                 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
6110               }
6111               if (lastLastIndex === string.length) {
6112                 if (lastLength || !separatorCopy.test('')) output.push('');
6113               } else output.push(string.slice(lastLastIndex));
6114               return output.length > lim ? output.slice(0, lim) : output;
6115             };
6116           // Chakra, V8
6117           } else if ('0'.split(undefined, 0).length) {
6118             internalSplit = function (separator, limit) {
6119               return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
6120             };
6121           } else internalSplit = nativeSplit;
6122
6123           return [
6124             // `String.prototype.split` method
6125             // https://tc39.es/ecma262/#sec-string.prototype.split
6126             function split(separator, limit) {
6127               var O = requireObjectCoercible(this);
6128               var splitter = separator == undefined ? undefined : separator[SPLIT];
6129               return splitter !== undefined
6130                 ? splitter.call(separator, O, limit)
6131                 : internalSplit.call(String(O), separator, limit);
6132             },
6133             // `RegExp.prototype[@@split]` method
6134             // https://tc39.es/ecma262/#sec-regexp.prototype-@@split
6135             //
6136             // NOTE: This cannot be properly polyfilled in engines that don't support
6137             // the 'y' flag.
6138             function (regexp, limit) {
6139               var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== nativeSplit);
6140               if (res.done) return res.value;
6141
6142               var rx = anObject(regexp);
6143               var S = String(this);
6144               var C = speciesConstructor(rx, RegExp);
6145
6146               var unicodeMatching = rx.unicode;
6147               var flags = (rx.ignoreCase ? 'i' : '') +
6148                           (rx.multiline ? 'm' : '') +
6149                           (rx.unicode ? 'u' : '') +
6150                           (SUPPORTS_Y ? 'y' : 'g');
6151
6152               // ^(? + rx + ) is needed, in combination with some S slicing, to
6153               // simulate the 'y' flag.
6154               var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags);
6155               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6156               if (lim === 0) return [];
6157               if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
6158               var p = 0;
6159               var q = 0;
6160               var A = [];
6161               while (q < S.length) {
6162                 splitter.lastIndex = SUPPORTS_Y ? q : 0;
6163                 var z = regexpExecAbstract(splitter, SUPPORTS_Y ? S : S.slice(q));
6164                 var e;
6165                 if (
6166                   z === null ||
6167                   (e = min$5(toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p
6168                 ) {
6169                   q = advanceStringIndex(S, q, unicodeMatching);
6170                 } else {
6171                   A.push(S.slice(p, q));
6172                   if (A.length === lim) return A;
6173                   for (var i = 1; i <= z.length - 1; i++) {
6174                     A.push(z[i]);
6175                     if (A.length === lim) return A;
6176                   }
6177                   q = p = e;
6178                 }
6179               }
6180               A.push(S.slice(p));
6181               return A;
6182             }
6183           ];
6184         }, !SUPPORTS_Y);
6185
6186         // a string of all valid unicode whitespaces
6187         var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' +
6188           '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
6189
6190         var whitespace = '[' + whitespaces + ']';
6191         var ltrim = RegExp('^' + whitespace + whitespace + '*');
6192         var rtrim = RegExp(whitespace + whitespace + '*$');
6193
6194         // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
6195         var createMethod$4 = function (TYPE) {
6196           return function ($this) {
6197             var string = String(requireObjectCoercible($this));
6198             if (TYPE & 1) string = string.replace(ltrim, '');
6199             if (TYPE & 2) string = string.replace(rtrim, '');
6200             return string;
6201           };
6202         };
6203
6204         var stringTrim = {
6205           // `String.prototype.{ trimLeft, trimStart }` methods
6206           // https://tc39.es/ecma262/#sec-string.prototype.trimstart
6207           start: createMethod$4(1),
6208           // `String.prototype.{ trimRight, trimEnd }` methods
6209           // https://tc39.es/ecma262/#sec-string.prototype.trimend
6210           end: createMethod$4(2),
6211           // `String.prototype.trim` method
6212           // https://tc39.es/ecma262/#sec-string.prototype.trim
6213           trim: createMethod$4(3)
6214         };
6215
6216         var non = '\u200B\u0085\u180E';
6217
6218         // check that a method works with the correct list
6219         // of whitespaces and has a correct name
6220         var stringTrimForced = function (METHOD_NAME) {
6221           return fails(function () {
6222             return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
6223           });
6224         };
6225
6226         var $trim = stringTrim.trim;
6227
6228
6229         // `String.prototype.trim` method
6230         // https://tc39.es/ecma262/#sec-string.prototype.trim
6231         _export({ target: 'String', proto: true, forced: stringTrimForced('trim') }, {
6232           trim: function trim() {
6233             return $trim(this);
6234           }
6235         });
6236
6237         var defineProperty$6 = objectDefineProperty.f;
6238
6239         var FunctionPrototype = Function.prototype;
6240         var FunctionPrototypeToString = FunctionPrototype.toString;
6241         var nameRE = /^\s*function ([^ (]*)/;
6242         var NAME$1 = 'name';
6243
6244         // Function instances `.name` property
6245         // https://tc39.es/ecma262/#sec-function-instances-name
6246         if (descriptors && !(NAME$1 in FunctionPrototype)) {
6247           defineProperty$6(FunctionPrototype, NAME$1, {
6248             configurable: true,
6249             get: function () {
6250               try {
6251                 return FunctionPrototypeToString.call(this).match(nameRE)[1];
6252               } catch (error) {
6253                 return '';
6254               }
6255             }
6256           });
6257         }
6258
6259         // `Object.create` method
6260         // https://tc39.es/ecma262/#sec-object.create
6261         _export({ target: 'Object', stat: true, sham: !descriptors }, {
6262           create: objectCreate
6263         });
6264
6265         var slice = [].slice;
6266         var MSIE = /MSIE .\./.test(engineUserAgent); // <- dirty ie9- check
6267
6268         var wrap$1 = function (scheduler) {
6269           return function (handler, timeout /* , ...arguments */) {
6270             var boundArgs = arguments.length > 2;
6271             var args = boundArgs ? slice.call(arguments, 2) : undefined;
6272             return scheduler(boundArgs ? function () {
6273               // eslint-disable-next-line no-new-func -- spec requirement
6274               (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
6275             } : handler, timeout);
6276           };
6277         };
6278
6279         // ie9- setTimeout & setInterval additional parameters fix
6280         // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
6281         _export({ global: true, bind: true, forced: MSIE }, {
6282           // `setTimeout` method
6283           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
6284           setTimeout: wrap$1(global_1.setTimeout),
6285           // `setInterval` method
6286           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
6287           setInterval: wrap$1(global_1.setInterval)
6288         });
6289
6290         var global$1 = typeof globalThis !== 'undefined' && globalThis || typeof self !== 'undefined' && self || typeof global$1 !== 'undefined' && global$1;
6291         var support = {
6292           searchParams: 'URLSearchParams' in global$1,
6293           iterable: 'Symbol' in global$1 && 'iterator' in Symbol,
6294           blob: 'FileReader' in global$1 && 'Blob' in global$1 && function () {
6295             try {
6296               new Blob();
6297               return true;
6298             } catch (e) {
6299               return false;
6300             }
6301           }(),
6302           formData: 'FormData' in global$1,
6303           arrayBuffer: 'ArrayBuffer' in global$1
6304         };
6305
6306         function isDataView(obj) {
6307           return obj && DataView.prototype.isPrototypeOf(obj);
6308         }
6309
6310         if (support.arrayBuffer) {
6311           var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
6312
6313           var isArrayBufferView = ArrayBuffer.isView || function (obj) {
6314             return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
6315           };
6316         }
6317
6318         function normalizeName(name) {
6319           if (typeof name !== 'string') {
6320             name = String(name);
6321           }
6322
6323           if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
6324             throw new TypeError('Invalid character in header field name: "' + name + '"');
6325           }
6326
6327           return name.toLowerCase();
6328         }
6329
6330         function normalizeValue(value) {
6331           if (typeof value !== 'string') {
6332             value = String(value);
6333           }
6334
6335           return value;
6336         } // Build a destructive iterator for the value list
6337
6338
6339         function iteratorFor(items) {
6340           var iterator = {
6341             next: function next() {
6342               var value = items.shift();
6343               return {
6344                 done: value === undefined,
6345                 value: value
6346               };
6347             }
6348           };
6349
6350           if (support.iterable) {
6351             iterator[Symbol.iterator] = function () {
6352               return iterator;
6353             };
6354           }
6355
6356           return iterator;
6357         }
6358
6359         function Headers$1(headers) {
6360           this.map = {};
6361
6362           if (headers instanceof Headers$1) {
6363             headers.forEach(function (value, name) {
6364               this.append(name, value);
6365             }, this);
6366           } else if (Array.isArray(headers)) {
6367             headers.forEach(function (header) {
6368               this.append(header[0], header[1]);
6369             }, this);
6370           } else if (headers) {
6371             Object.getOwnPropertyNames(headers).forEach(function (name) {
6372               this.append(name, headers[name]);
6373             }, this);
6374           }
6375         }
6376
6377         Headers$1.prototype.append = function (name, value) {
6378           name = normalizeName(name);
6379           value = normalizeValue(value);
6380           var oldValue = this.map[name];
6381           this.map[name] = oldValue ? oldValue + ', ' + value : value;
6382         };
6383
6384         Headers$1.prototype['delete'] = function (name) {
6385           delete this.map[normalizeName(name)];
6386         };
6387
6388         Headers$1.prototype.get = function (name) {
6389           name = normalizeName(name);
6390           return this.has(name) ? this.map[name] : null;
6391         };
6392
6393         Headers$1.prototype.has = function (name) {
6394           return this.map.hasOwnProperty(normalizeName(name));
6395         };
6396
6397         Headers$1.prototype.set = function (name, value) {
6398           this.map[normalizeName(name)] = normalizeValue(value);
6399         };
6400
6401         Headers$1.prototype.forEach = function (callback, thisArg) {
6402           for (var name in this.map) {
6403             if (this.map.hasOwnProperty(name)) {
6404               callback.call(thisArg, this.map[name], name, this);
6405             }
6406           }
6407         };
6408
6409         Headers$1.prototype.keys = function () {
6410           var items = [];
6411           this.forEach(function (value, name) {
6412             items.push(name);
6413           });
6414           return iteratorFor(items);
6415         };
6416
6417         Headers$1.prototype.values = function () {
6418           var items = [];
6419           this.forEach(function (value) {
6420             items.push(value);
6421           });
6422           return iteratorFor(items);
6423         };
6424
6425         Headers$1.prototype.entries = function () {
6426           var items = [];
6427           this.forEach(function (value, name) {
6428             items.push([name, value]);
6429           });
6430           return iteratorFor(items);
6431         };
6432
6433         if (support.iterable) {
6434           Headers$1.prototype[Symbol.iterator] = Headers$1.prototype.entries;
6435         }
6436
6437         function consumed(body) {
6438           if (body.bodyUsed) {
6439             return Promise.reject(new TypeError('Already read'));
6440           }
6441
6442           body.bodyUsed = true;
6443         }
6444
6445         function fileReaderReady(reader) {
6446           return new Promise(function (resolve, reject) {
6447             reader.onload = function () {
6448               resolve(reader.result);
6449             };
6450
6451             reader.onerror = function () {
6452               reject(reader.error);
6453             };
6454           });
6455         }
6456
6457         function readBlobAsArrayBuffer(blob) {
6458           var reader = new FileReader();
6459           var promise = fileReaderReady(reader);
6460           reader.readAsArrayBuffer(blob);
6461           return promise;
6462         }
6463
6464         function readBlobAsText(blob) {
6465           var reader = new FileReader();
6466           var promise = fileReaderReady(reader);
6467           reader.readAsText(blob);
6468           return promise;
6469         }
6470
6471         function readArrayBufferAsText(buf) {
6472           var view = new Uint8Array(buf);
6473           var chars = new Array(view.length);
6474
6475           for (var i = 0; i < view.length; i++) {
6476             chars[i] = String.fromCharCode(view[i]);
6477           }
6478
6479           return chars.join('');
6480         }
6481
6482         function bufferClone(buf) {
6483           if (buf.slice) {
6484             return buf.slice(0);
6485           } else {
6486             var view = new Uint8Array(buf.byteLength);
6487             view.set(new Uint8Array(buf));
6488             return view.buffer;
6489           }
6490         }
6491
6492         function Body() {
6493           this.bodyUsed = false;
6494
6495           this._initBody = function (body) {
6496             /*
6497               fetch-mock wraps the Response object in an ES6 Proxy to
6498               provide useful test harness features such as flush. However, on
6499               ES5 browsers without fetch or Proxy support pollyfills must be used;
6500               the proxy-pollyfill is unable to proxy an attribute unless it exists
6501               on the object before the Proxy is created. This change ensures
6502               Response.bodyUsed exists on the instance, while maintaining the
6503               semantic of setting Request.bodyUsed in the constructor before
6504               _initBody is called.
6505             */
6506             this.bodyUsed = this.bodyUsed;
6507             this._bodyInit = body;
6508
6509             if (!body) {
6510               this._bodyText = '';
6511             } else if (typeof body === 'string') {
6512               this._bodyText = body;
6513             } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
6514               this._bodyBlob = body;
6515             } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
6516               this._bodyFormData = body;
6517             } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6518               this._bodyText = body.toString();
6519             } else if (support.arrayBuffer && support.blob && isDataView(body)) {
6520               this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.
6521
6522               this._bodyInit = new Blob([this._bodyArrayBuffer]);
6523             } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
6524               this._bodyArrayBuffer = bufferClone(body);
6525             } else {
6526               this._bodyText = body = Object.prototype.toString.call(body);
6527             }
6528
6529             if (!this.headers.get('content-type')) {
6530               if (typeof body === 'string') {
6531                 this.headers.set('content-type', 'text/plain;charset=UTF-8');
6532               } else if (this._bodyBlob && this._bodyBlob.type) {
6533                 this.headers.set('content-type', this._bodyBlob.type);
6534               } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6535                 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
6536               }
6537             }
6538           };
6539
6540           if (support.blob) {
6541             this.blob = function () {
6542               var rejected = consumed(this);
6543
6544               if (rejected) {
6545                 return rejected;
6546               }
6547
6548               if (this._bodyBlob) {
6549                 return Promise.resolve(this._bodyBlob);
6550               } else if (this._bodyArrayBuffer) {
6551                 return Promise.resolve(new Blob([this._bodyArrayBuffer]));
6552               } else if (this._bodyFormData) {
6553                 throw new Error('could not read FormData body as blob');
6554               } else {
6555                 return Promise.resolve(new Blob([this._bodyText]));
6556               }
6557             };
6558
6559             this.arrayBuffer = function () {
6560               if (this._bodyArrayBuffer) {
6561                 var isConsumed = consumed(this);
6562
6563                 if (isConsumed) {
6564                   return isConsumed;
6565                 }
6566
6567                 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
6568                   return Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength));
6569                 } else {
6570                   return Promise.resolve(this._bodyArrayBuffer);
6571                 }
6572               } else {
6573                 return this.blob().then(readBlobAsArrayBuffer);
6574               }
6575             };
6576           }
6577
6578           this.text = function () {
6579             var rejected = consumed(this);
6580
6581             if (rejected) {
6582               return rejected;
6583             }
6584
6585             if (this._bodyBlob) {
6586               return readBlobAsText(this._bodyBlob);
6587             } else if (this._bodyArrayBuffer) {
6588               return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
6589             } else if (this._bodyFormData) {
6590               throw new Error('could not read FormData body as text');
6591             } else {
6592               return Promise.resolve(this._bodyText);
6593             }
6594           };
6595
6596           if (support.formData) {
6597             this.formData = function () {
6598               return this.text().then(decode);
6599             };
6600           }
6601
6602           this.json = function () {
6603             return this.text().then(JSON.parse);
6604           };
6605
6606           return this;
6607         } // HTTP methods whose capitalization should be normalized
6608
6609
6610         var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
6611
6612         function normalizeMethod(method) {
6613           var upcased = method.toUpperCase();
6614           return methods.indexOf(upcased) > -1 ? upcased : method;
6615         }
6616
6617         function Request(input, options) {
6618           if (!(this instanceof Request)) {
6619             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6620           }
6621
6622           options = options || {};
6623           var body = options.body;
6624
6625           if (input instanceof Request) {
6626             if (input.bodyUsed) {
6627               throw new TypeError('Already read');
6628             }
6629
6630             this.url = input.url;
6631             this.credentials = input.credentials;
6632
6633             if (!options.headers) {
6634               this.headers = new Headers$1(input.headers);
6635             }
6636
6637             this.method = input.method;
6638             this.mode = input.mode;
6639             this.signal = input.signal;
6640
6641             if (!body && input._bodyInit != null) {
6642               body = input._bodyInit;
6643               input.bodyUsed = true;
6644             }
6645           } else {
6646             this.url = String(input);
6647           }
6648
6649           this.credentials = options.credentials || this.credentials || 'same-origin';
6650
6651           if (options.headers || !this.headers) {
6652             this.headers = new Headers$1(options.headers);
6653           }
6654
6655           this.method = normalizeMethod(options.method || this.method || 'GET');
6656           this.mode = options.mode || this.mode || null;
6657           this.signal = options.signal || this.signal;
6658           this.referrer = null;
6659
6660           if ((this.method === 'GET' || this.method === 'HEAD') && body) {
6661             throw new TypeError('Body not allowed for GET or HEAD requests');
6662           }
6663
6664           this._initBody(body);
6665
6666           if (this.method === 'GET' || this.method === 'HEAD') {
6667             if (options.cache === 'no-store' || options.cache === 'no-cache') {
6668               // Search for a '_' parameter in the query string
6669               var reParamSearch = /([?&])_=[^&]*/;
6670
6671               if (reParamSearch.test(this.url)) {
6672                 // If it already exists then set the value with the current time
6673                 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
6674               } else {
6675                 // Otherwise add a new '_' parameter to the end with the current time
6676                 var reQueryString = /\?/;
6677                 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
6678               }
6679             }
6680           }
6681         }
6682
6683         Request.prototype.clone = function () {
6684           return new Request(this, {
6685             body: this._bodyInit
6686           });
6687         };
6688
6689         function decode(body) {
6690           var form = new FormData();
6691           body.trim().split('&').forEach(function (bytes) {
6692             if (bytes) {
6693               var split = bytes.split('=');
6694               var name = split.shift().replace(/\+/g, ' ');
6695               var value = split.join('=').replace(/\+/g, ' ');
6696               form.append(decodeURIComponent(name), decodeURIComponent(value));
6697             }
6698           });
6699           return form;
6700         }
6701
6702         function parseHeaders(rawHeaders) {
6703           var headers = new Headers$1(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
6704           // https://tools.ietf.org/html/rfc7230#section-3.2
6705
6706           var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' '); // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill
6707           // https://github.com/github/fetch/issues/748
6708           // https://github.com/zloirock/core-js/issues/751
6709
6710           preProcessedHeaders.split('\r').map(function (header) {
6711             return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header;
6712           }).forEach(function (line) {
6713             var parts = line.split(':');
6714             var key = parts.shift().trim();
6715
6716             if (key) {
6717               var value = parts.join(':').trim();
6718               headers.append(key, value);
6719             }
6720           });
6721           return headers;
6722         }
6723
6724         Body.call(Request.prototype);
6725         function Response(bodyInit, options) {
6726           if (!(this instanceof Response)) {
6727             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6728           }
6729
6730           if (!options) {
6731             options = {};
6732           }
6733
6734           this.type = 'default';
6735           this.status = options.status === undefined ? 200 : options.status;
6736           this.ok = this.status >= 200 && this.status < 300;
6737           this.statusText = options.statusText === undefined ? '' : '' + options.statusText;
6738           this.headers = new Headers$1(options.headers);
6739           this.url = options.url || '';
6740
6741           this._initBody(bodyInit);
6742         }
6743         Body.call(Response.prototype);
6744
6745         Response.prototype.clone = function () {
6746           return new Response(this._bodyInit, {
6747             status: this.status,
6748             statusText: this.statusText,
6749             headers: new Headers$1(this.headers),
6750             url: this.url
6751           });
6752         };
6753
6754         Response.error = function () {
6755           var response = new Response(null, {
6756             status: 0,
6757             statusText: ''
6758           });
6759           response.type = 'error';
6760           return response;
6761         };
6762
6763         var redirectStatuses = [301, 302, 303, 307, 308];
6764
6765         Response.redirect = function (url, status) {
6766           if (redirectStatuses.indexOf(status) === -1) {
6767             throw new RangeError('Invalid status code');
6768           }
6769
6770           return new Response(null, {
6771             status: status,
6772             headers: {
6773               location: url
6774             }
6775           });
6776         };
6777
6778         var DOMException$1 = global$1.DOMException;
6779
6780         try {
6781           new DOMException$1();
6782         } catch (err) {
6783           DOMException$1 = function DOMException(message, name) {
6784             this.message = message;
6785             this.name = name;
6786             var error = Error(message);
6787             this.stack = error.stack;
6788           };
6789
6790           DOMException$1.prototype = Object.create(Error.prototype);
6791           DOMException$1.prototype.constructor = DOMException$1;
6792         }
6793
6794         function fetch$1(input, init) {
6795           return new Promise(function (resolve, reject) {
6796             var request = new Request(input, init);
6797
6798             if (request.signal && request.signal.aborted) {
6799               return reject(new DOMException$1('Aborted', 'AbortError'));
6800             }
6801
6802             var xhr = new XMLHttpRequest();
6803
6804             function abortXhr() {
6805               xhr.abort();
6806             }
6807
6808             xhr.onload = function () {
6809               var options = {
6810                 status: xhr.status,
6811                 statusText: xhr.statusText,
6812                 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
6813               };
6814               options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
6815               var body = 'response' in xhr ? xhr.response : xhr.responseText;
6816               setTimeout(function () {
6817                 resolve(new Response(body, options));
6818               }, 0);
6819             };
6820
6821             xhr.onerror = function () {
6822               setTimeout(function () {
6823                 reject(new TypeError('Network request failed'));
6824               }, 0);
6825             };
6826
6827             xhr.ontimeout = function () {
6828               setTimeout(function () {
6829                 reject(new TypeError('Network request failed'));
6830               }, 0);
6831             };
6832
6833             xhr.onabort = function () {
6834               setTimeout(function () {
6835                 reject(new DOMException$1('Aborted', 'AbortError'));
6836               }, 0);
6837             };
6838
6839             function fixUrl(url) {
6840               try {
6841                 return url === '' && global$1.location.href ? global$1.location.href : url;
6842               } catch (e) {
6843                 return url;
6844               }
6845             }
6846
6847             xhr.open(request.method, fixUrl(request.url), true);
6848
6849             if (request.credentials === 'include') {
6850               xhr.withCredentials = true;
6851             } else if (request.credentials === 'omit') {
6852               xhr.withCredentials = false;
6853             }
6854
6855             if ('responseType' in xhr) {
6856               if (support.blob) {
6857                 xhr.responseType = 'blob';
6858               } else if (support.arrayBuffer && request.headers.get('Content-Type') && request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1) {
6859                 xhr.responseType = 'arraybuffer';
6860               }
6861             }
6862
6863             if (init && _typeof(init.headers) === 'object' && !(init.headers instanceof Headers$1)) {
6864               Object.getOwnPropertyNames(init.headers).forEach(function (name) {
6865                 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
6866               });
6867             } else {
6868               request.headers.forEach(function (value, name) {
6869                 xhr.setRequestHeader(name, value);
6870               });
6871             }
6872
6873             if (request.signal) {
6874               request.signal.addEventListener('abort', abortXhr);
6875
6876               xhr.onreadystatechange = function () {
6877                 // DONE (success or failure)
6878                 if (xhr.readyState === 4) {
6879                   request.signal.removeEventListener('abort', abortXhr);
6880                 }
6881               };
6882             }
6883
6884             xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
6885           });
6886         }
6887         fetch$1.polyfill = true;
6888
6889         if (!global$1.fetch) {
6890           global$1.fetch = fetch$1;
6891           global$1.Headers = Headers$1;
6892           global$1.Request = Request;
6893           global$1.Response = Response;
6894         }
6895
6896         // `Object.defineProperty` method
6897         // https://tc39.es/ecma262/#sec-object.defineproperty
6898         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
6899           defineProperty: objectDefineProperty.f
6900         });
6901
6902         // `Object.setPrototypeOf` method
6903         // https://tc39.es/ecma262/#sec-object.setprototypeof
6904         _export({ target: 'Object', stat: true }, {
6905           setPrototypeOf: objectSetPrototypeOf
6906         });
6907
6908         var FAILS_ON_PRIMITIVES$1 = fails(function () { objectGetPrototypeOf(1); });
6909
6910         // `Object.getPrototypeOf` method
6911         // https://tc39.es/ecma262/#sec-object.getprototypeof
6912         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$1, sham: !correctPrototypeGetter }, {
6913           getPrototypeOf: function getPrototypeOf(it) {
6914             return objectGetPrototypeOf(toObject(it));
6915           }
6916         });
6917
6918         var slice$1 = [].slice;
6919         var factories = {};
6920
6921         var construct = function (C, argsLength, args) {
6922           if (!(argsLength in factories)) {
6923             for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
6924             // eslint-disable-next-line no-new-func -- we have no proper alternatives, IE8- only
6925             factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
6926           } return factories[argsLength](C, args);
6927         };
6928
6929         // `Function.prototype.bind` method implementation
6930         // https://tc39.es/ecma262/#sec-function.prototype.bind
6931         var functionBind = Function.bind || function bind(that /* , ...args */) {
6932           var fn = aFunction$1(this);
6933           var partArgs = slice$1.call(arguments, 1);
6934           var boundFunction = function bound(/* args... */) {
6935             var args = partArgs.concat(slice$1.call(arguments));
6936             return this instanceof boundFunction ? construct(fn, args.length, args) : fn.apply(that, args);
6937           };
6938           if (isObject(fn.prototype)) boundFunction.prototype = fn.prototype;
6939           return boundFunction;
6940         };
6941
6942         var nativeConstruct = getBuiltIn('Reflect', 'construct');
6943
6944         // `Reflect.construct` method
6945         // https://tc39.es/ecma262/#sec-reflect.construct
6946         // MS Edge supports only 2 arguments and argumentsList argument is optional
6947         // FF Nightly sets third argument as `new.target`, but does not create `this` from it
6948         var NEW_TARGET_BUG = fails(function () {
6949           function F() { /* empty */ }
6950           return !(nativeConstruct(function () { /* empty */ }, [], F) instanceof F);
6951         });
6952         var ARGS_BUG = !fails(function () {
6953           nativeConstruct(function () { /* empty */ });
6954         });
6955         var FORCED$5 = NEW_TARGET_BUG || ARGS_BUG;
6956
6957         _export({ target: 'Reflect', stat: true, forced: FORCED$5, sham: FORCED$5 }, {
6958           construct: function construct(Target, args /* , newTarget */) {
6959             aFunction$1(Target);
6960             anObject(args);
6961             var newTarget = arguments.length < 3 ? Target : aFunction$1(arguments[2]);
6962             if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
6963             if (Target == newTarget) {
6964               // w/o altered newTarget, optimization for 0-4 arguments
6965               switch (args.length) {
6966                 case 0: return new Target();
6967                 case 1: return new Target(args[0]);
6968                 case 2: return new Target(args[0], args[1]);
6969                 case 3: return new Target(args[0], args[1], args[2]);
6970                 case 4: return new Target(args[0], args[1], args[2], args[3]);
6971               }
6972               // w/o altered newTarget, lot of arguments case
6973               var $args = [null];
6974               $args.push.apply($args, args);
6975               return new (functionBind.apply(Target, $args))();
6976             }
6977             // with altered newTarget, not support built-in constructors
6978             var proto = newTarget.prototype;
6979             var instance = objectCreate(isObject(proto) ? proto : Object.prototype);
6980             var result = Function.apply.call(Target, instance, args);
6981             return isObject(result) ? result : instance;
6982           }
6983         });
6984
6985         // `Reflect.get` method
6986         // https://tc39.es/ecma262/#sec-reflect.get
6987         function get$2(target, propertyKey /* , receiver */) {
6988           var receiver = arguments.length < 3 ? target : arguments[2];
6989           var descriptor, prototype;
6990           if (anObject(target) === receiver) return target[propertyKey];
6991           if (descriptor = objectGetOwnPropertyDescriptor.f(target, propertyKey)) return has(descriptor, 'value')
6992             ? descriptor.value
6993             : descriptor.get === undefined
6994               ? undefined
6995               : descriptor.get.call(receiver);
6996           if (isObject(prototype = objectGetPrototypeOf(target))) return get$2(prototype, propertyKey, receiver);
6997         }
6998
6999         _export({ target: 'Reflect', stat: true }, {
7000           get: get$2
7001         });
7002
7003         var nativeGetOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
7004
7005
7006         var FAILS_ON_PRIMITIVES$2 = fails(function () { nativeGetOwnPropertyDescriptor$2(1); });
7007         var FORCED$6 = !descriptors || FAILS_ON_PRIMITIVES$2;
7008
7009         // `Object.getOwnPropertyDescriptor` method
7010         // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
7011         _export({ target: 'Object', stat: true, forced: FORCED$6, sham: !descriptors }, {
7012           getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
7013             return nativeGetOwnPropertyDescriptor$2(toIndexedObject(it), key);
7014           }
7015         });
7016
7017         var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('splice');
7018
7019         var max$3 = Math.max;
7020         var min$6 = Math.min;
7021         var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
7022         var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
7023
7024         // `Array.prototype.splice` method
7025         // https://tc39.es/ecma262/#sec-array.prototype.splice
7026         // with adding support of @@species
7027         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 }, {
7028           splice: function splice(start, deleteCount /* , ...items */) {
7029             var O = toObject(this);
7030             var len = toLength(O.length);
7031             var actualStart = toAbsoluteIndex(start, len);
7032             var argumentsLength = arguments.length;
7033             var insertCount, actualDeleteCount, A, k, from, to;
7034             if (argumentsLength === 0) {
7035               insertCount = actualDeleteCount = 0;
7036             } else if (argumentsLength === 1) {
7037               insertCount = 0;
7038               actualDeleteCount = len - actualStart;
7039             } else {
7040               insertCount = argumentsLength - 2;
7041               actualDeleteCount = min$6(max$3(toInteger(deleteCount), 0), len - actualStart);
7042             }
7043             if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
7044               throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
7045             }
7046             A = arraySpeciesCreate(O, actualDeleteCount);
7047             for (k = 0; k < actualDeleteCount; k++) {
7048               from = actualStart + k;
7049               if (from in O) createProperty(A, k, O[from]);
7050             }
7051             A.length = actualDeleteCount;
7052             if (insertCount < actualDeleteCount) {
7053               for (k = actualStart; k < len - actualDeleteCount; k++) {
7054                 from = k + actualDeleteCount;
7055                 to = k + insertCount;
7056                 if (from in O) O[to] = O[from];
7057                 else delete O[to];
7058               }
7059               for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
7060             } else if (insertCount > actualDeleteCount) {
7061               for (k = len - actualDeleteCount; k > actualStart; k--) {
7062                 from = k + actualDeleteCount - 1;
7063                 to = k + insertCount - 1;
7064                 if (from in O) O[to] = O[from];
7065                 else delete O[to];
7066               }
7067             }
7068             for (k = 0; k < insertCount; k++) {
7069               O[k + actualStart] = arguments[k + 2];
7070             }
7071             O.length = len - actualDeleteCount + insertCount;
7072             return A;
7073           }
7074         });
7075
7076         // `Symbol.toStringTag` well-known symbol
7077         // https://tc39.es/ecma262/#sec-symbol.tostringtag
7078         defineWellKnownSymbol('toStringTag');
7079
7080         // Math[@@toStringTag] property
7081         // https://tc39.es/ecma262/#sec-math-@@tostringtag
7082         setToStringTag(Math, 'Math', true);
7083
7084         // JSON[@@toStringTag] property
7085         // https://tc39.es/ecma262/#sec-json-@@tostringtag
7086         setToStringTag(global_1.JSON, 'JSON', true);
7087
7088         (function (factory) {
7089            factory();
7090         })(function () {
7091
7092           function _classCallCheck(instance, Constructor) {
7093             if (!(instance instanceof Constructor)) {
7094               throw new TypeError("Cannot call a class as a function");
7095             }
7096           }
7097
7098           function _defineProperties(target, props) {
7099             for (var i = 0; i < props.length; i++) {
7100               var descriptor = props[i];
7101               descriptor.enumerable = descriptor.enumerable || false;
7102               descriptor.configurable = true;
7103               if ("value" in descriptor) descriptor.writable = true;
7104               Object.defineProperty(target, descriptor.key, descriptor);
7105             }
7106           }
7107
7108           function _createClass(Constructor, protoProps, staticProps) {
7109             if (protoProps) _defineProperties(Constructor.prototype, protoProps);
7110             if (staticProps) _defineProperties(Constructor, staticProps);
7111             return Constructor;
7112           }
7113
7114           function _inherits(subClass, superClass) {
7115             if (typeof superClass !== "function" && superClass !== null) {
7116               throw new TypeError("Super expression must either be null or a function");
7117             }
7118
7119             subClass.prototype = Object.create(superClass && superClass.prototype, {
7120               constructor: {
7121                 value: subClass,
7122                 writable: true,
7123                 configurable: true
7124               }
7125             });
7126             if (superClass) _setPrototypeOf(subClass, superClass);
7127           }
7128
7129           function _getPrototypeOf(o) {
7130             _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
7131               return o.__proto__ || Object.getPrototypeOf(o);
7132             };
7133             return _getPrototypeOf(o);
7134           }
7135
7136           function _setPrototypeOf(o, p) {
7137             _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
7138               o.__proto__ = p;
7139               return o;
7140             };
7141
7142             return _setPrototypeOf(o, p);
7143           }
7144
7145           function _isNativeReflectConstruct() {
7146             if (typeof Reflect === "undefined" || !Reflect.construct) return false;
7147             if (Reflect.construct.sham) return false;
7148             if (typeof Proxy === "function") return true;
7149
7150             try {
7151               Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
7152               return true;
7153             } catch (e) {
7154               return false;
7155             }
7156           }
7157
7158           function _assertThisInitialized(self) {
7159             if (self === void 0) {
7160               throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
7161             }
7162
7163             return self;
7164           }
7165
7166           function _possibleConstructorReturn(self, call) {
7167             if (call && (_typeof(call) === "object" || typeof call === "function")) {
7168               return call;
7169             }
7170
7171             return _assertThisInitialized(self);
7172           }
7173
7174           function _createSuper(Derived) {
7175             var hasNativeReflectConstruct = _isNativeReflectConstruct();
7176
7177             return function _createSuperInternal() {
7178               var Super = _getPrototypeOf(Derived),
7179                   result;
7180
7181               if (hasNativeReflectConstruct) {
7182                 var NewTarget = _getPrototypeOf(this).constructor;
7183
7184                 result = Reflect.construct(Super, arguments, NewTarget);
7185               } else {
7186                 result = Super.apply(this, arguments);
7187               }
7188
7189               return _possibleConstructorReturn(this, result);
7190             };
7191           }
7192
7193           function _superPropBase(object, property) {
7194             while (!Object.prototype.hasOwnProperty.call(object, property)) {
7195               object = _getPrototypeOf(object);
7196               if (object === null) break;
7197             }
7198
7199             return object;
7200           }
7201
7202           function _get(target, property, receiver) {
7203             if (typeof Reflect !== "undefined" && Reflect.get) {
7204               _get = Reflect.get;
7205             } else {
7206               _get = function _get(target, property, receiver) {
7207                 var base = _superPropBase(target, property);
7208
7209                 if (!base) return;
7210                 var desc = Object.getOwnPropertyDescriptor(base, property);
7211
7212                 if (desc.get) {
7213                   return desc.get.call(receiver);
7214                 }
7215
7216                 return desc.value;
7217               };
7218             }
7219
7220             return _get(target, property, receiver || target);
7221           }
7222
7223           var Emitter = /*#__PURE__*/function () {
7224             function Emitter() {
7225               _classCallCheck(this, Emitter);
7226
7227               Object.defineProperty(this, 'listeners', {
7228                 value: {},
7229                 writable: true,
7230                 configurable: true
7231               });
7232             }
7233
7234             _createClass(Emitter, [{
7235               key: "addEventListener",
7236               value: function addEventListener(type, callback, options) {
7237                 if (!(type in this.listeners)) {
7238                   this.listeners[type] = [];
7239                 }
7240
7241                 this.listeners[type].push({
7242                   callback: callback,
7243                   options: options
7244                 });
7245               }
7246             }, {
7247               key: "removeEventListener",
7248               value: function removeEventListener(type, callback) {
7249                 if (!(type in this.listeners)) {
7250                   return;
7251                 }
7252
7253                 var stack = this.listeners[type];
7254
7255                 for (var i = 0, l = stack.length; i < l; i++) {
7256                   if (stack[i].callback === callback) {
7257                     stack.splice(i, 1);
7258                     return;
7259                   }
7260                 }
7261               }
7262             }, {
7263               key: "dispatchEvent",
7264               value: function dispatchEvent(event) {
7265                 if (!(event.type in this.listeners)) {
7266                   return;
7267                 }
7268
7269                 var stack = this.listeners[event.type];
7270                 var stackToCall = stack.slice();
7271
7272                 for (var i = 0, l = stackToCall.length; i < l; i++) {
7273                   var listener = stackToCall[i];
7274
7275                   try {
7276                     listener.callback.call(this, event);
7277                   } catch (e) {
7278                     Promise.resolve().then(function () {
7279                       throw e;
7280                     });
7281                   }
7282
7283                   if (listener.options && listener.options.once) {
7284                     this.removeEventListener(event.type, listener.callback);
7285                   }
7286                 }
7287
7288                 return !event.defaultPrevented;
7289               }
7290             }]);
7291
7292             return Emitter;
7293           }();
7294
7295           var AbortSignal = /*#__PURE__*/function (_Emitter) {
7296             _inherits(AbortSignal, _Emitter);
7297
7298             var _super = _createSuper(AbortSignal);
7299
7300             function AbortSignal() {
7301               var _this;
7302
7303               _classCallCheck(this, AbortSignal);
7304
7305               _this = _super.call(this); // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
7306               // constructor has failed to run, then "this.listeners" will still be undefined and then we call
7307               // the parent constructor directly instead as a workaround. For general details, see babel bug:
7308               // https://github.com/babel/babel/issues/3041
7309               // This hack was added as a fix for the issue described here:
7310               // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
7311
7312               if (!_this.listeners) {
7313                 Emitter.call(_assertThisInitialized(_this));
7314               } // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7315               // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
7316
7317
7318               Object.defineProperty(_assertThisInitialized(_this), 'aborted', {
7319                 value: false,
7320                 writable: true,
7321                 configurable: true
7322               });
7323               Object.defineProperty(_assertThisInitialized(_this), 'onabort', {
7324                 value: null,
7325                 writable: true,
7326                 configurable: true
7327               });
7328               return _this;
7329             }
7330
7331             _createClass(AbortSignal, [{
7332               key: "toString",
7333               value: function toString() {
7334                 return '[object AbortSignal]';
7335               }
7336             }, {
7337               key: "dispatchEvent",
7338               value: function dispatchEvent(event) {
7339                 if (event.type === 'abort') {
7340                   this.aborted = true;
7341
7342                   if (typeof this.onabort === 'function') {
7343                     this.onabort.call(this, event);
7344                   }
7345                 }
7346
7347                 _get(_getPrototypeOf(AbortSignal.prototype), "dispatchEvent", this).call(this, event);
7348               }
7349             }]);
7350
7351             return AbortSignal;
7352           }(Emitter);
7353
7354           var AbortController = /*#__PURE__*/function () {
7355             function AbortController() {
7356               _classCallCheck(this, AbortController); // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7357               // we want Object.keys(new AbortController()) to be [] for compat with the native impl
7358
7359
7360               Object.defineProperty(this, 'signal', {
7361                 value: new AbortSignal(),
7362                 writable: true,
7363                 configurable: true
7364               });
7365             }
7366
7367             _createClass(AbortController, [{
7368               key: "abort",
7369               value: function abort() {
7370                 var event;
7371
7372                 try {
7373                   event = new Event('abort');
7374                 } catch (e) {
7375                   if (typeof document !== 'undefined') {
7376                     if (!document.createEvent) {
7377                       // For Internet Explorer 8:
7378                       event = document.createEventObject();
7379                       event.type = 'abort';
7380                     } else {
7381                       // For Internet Explorer 11:
7382                       event = document.createEvent('Event');
7383                       event.initEvent('abort', false, false);
7384                     }
7385                   } else {
7386                     // Fallback where document isn't available:
7387                     event = {
7388                       type: 'abort',
7389                       bubbles: false,
7390                       cancelable: false
7391                     };
7392                   }
7393                 }
7394
7395                 this.signal.dispatchEvent(event);
7396               }
7397             }, {
7398               key: "toString",
7399               value: function toString() {
7400                 return '[object AbortController]';
7401               }
7402             }]);
7403
7404             return AbortController;
7405           }();
7406
7407           if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
7408             // These are necessary to make sure that we get correct output for:
7409             // Object.prototype.toString.call(new AbortController())
7410             AbortController.prototype[Symbol.toStringTag] = 'AbortController';
7411             AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
7412           }
7413
7414           function polyfillNeeded(self) {
7415             if (self.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7416               console.log('__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill');
7417               return true;
7418             } // 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             // so the below feature detection needs the !self.AbortController part.
7421             // The Request.prototype check is also needed because Safari versions 11.1.2
7422             // up to and including 12.1.x has a window.AbortController present but still
7423             // does NOT correctly implement abortable fetch:
7424             // https://bugs.webkit.org/show_bug.cgi?id=174980#c2
7425
7426
7427             return typeof self.Request === 'function' && !self.Request.prototype.hasOwnProperty('signal') || !self.AbortController;
7428           }
7429           /**
7430            * Note: the "fetch.Request" default value is available for fetch imported from
7431            * the "node-fetch" package and not in browsers. This is OK since browsers
7432            * will be importing umd-polyfill.js from that path "self" is passed the
7433            * decorator so the default value will not be used (because browsers that define
7434            * fetch also has Request). One quirky setup where self.fetch exists but
7435            * self.Request does not is when the "unfetch" minimal fetch polyfill is used
7436            * on top of IE11; for this case the browser will try to use the fetch.Request
7437            * default value which in turn will be undefined but then then "if (Request)"
7438            * will ensure that you get a patched fetch but still no Request (as expected).
7439            * @param {fetch, Request = fetch.Request}
7440            * @returns {fetch: abortableFetch, Request: AbortableRequest}
7441            */
7442
7443
7444           function abortableFetchDecorator(patchTargets) {
7445             if ('function' === typeof patchTargets) {
7446               patchTargets = {
7447                 fetch: patchTargets
7448               };
7449             }
7450
7451             var _patchTargets = patchTargets,
7452                 fetch = _patchTargets.fetch,
7453                 _patchTargets$Request = _patchTargets.Request,
7454                 NativeRequest = _patchTargets$Request === void 0 ? fetch.Request : _patchTargets$Request,
7455                 NativeAbortController = _patchTargets.AbortController,
7456                 _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL,
7457                 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
7458
7459             if (!polyfillNeeded({
7460               fetch: fetch,
7461               Request: NativeRequest,
7462               AbortController: NativeAbortController,
7463               __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL: __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
7464             })) {
7465               return {
7466                 fetch: fetch,
7467                 Request: Request
7468               };
7469             }
7470
7471             var Request = NativeRequest; // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7472             // defining window.Request, and this polyfill need to work on top of unfetch
7473             // hence we only patch it if it's available. Also we don't patch it if signal
7474             // is already available on the Request prototype because in this case support
7475             // is present and the patching below can cause a crash since it assigns to
7476             // request.signal which is technically a read-only property. This latter error
7477             // happens when you run the main5.js node-fetch example in the repo
7478             // "abortcontroller-polyfill-examples". The exact error is:
7479             //   request.signal = init.signal;
7480             //   ^
7481             // TypeError: Cannot set property signal of #<Request> which has only a getter
7482
7483             if (Request && !Request.prototype.hasOwnProperty('signal') || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7484               Request = function Request(input, init) {
7485                 var signal;
7486
7487                 if (init && init.signal) {
7488                   signal = init.signal; // Never pass init.signal to the native Request implementation when the polyfill has
7489                   // been installed because if we're running on top of a browser with a
7490                   // working native AbortController (i.e. the polyfill was installed due to
7491                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7492                   // fake AbortSignal to the native fetch will trigger:
7493                   // TypeError: Failed to construct 'Request': member signal is not of type AbortSignal.
7494
7495                   delete init.signal;
7496                 }
7497
7498                 var request = new NativeRequest(input, init);
7499
7500                 if (signal) {
7501                   Object.defineProperty(request, 'signal', {
7502                     writable: false,
7503                     enumerable: false,
7504                     configurable: true,
7505                     value: signal
7506                   });
7507                 }
7508
7509                 return request;
7510               };
7511
7512               Request.prototype = NativeRequest.prototype;
7513             }
7514
7515             var realFetch = fetch;
7516
7517             var abortableFetch = function abortableFetch(input, init) {
7518               var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : undefined;
7519
7520               if (signal) {
7521                 var abortError;
7522
7523                 try {
7524                   abortError = new DOMException('Aborted', 'AbortError');
7525                 } catch (err) {
7526                   // IE 11 does not support calling the DOMException constructor, use a
7527                   // regular error object on it instead.
7528                   abortError = new Error('Aborted');
7529                   abortError.name = 'AbortError';
7530                 } // Return early if already aborted, thus avoiding making an HTTP request
7531
7532
7533                 if (signal.aborted) {
7534                   return Promise.reject(abortError);
7535                 } // Turn an event into a promise, reject it once `abort` is dispatched
7536
7537
7538                 var cancellation = new Promise(function (_, reject) {
7539                   signal.addEventListener('abort', function () {
7540                     return reject(abortError);
7541                   }, {
7542                     once: true
7543                   });
7544                 });
7545
7546                 if (init && init.signal) {
7547                   // Never pass .signal to the native implementation when the polyfill has
7548                   // been installed because if we're running on top of a browser with a
7549                   // working native AbortController (i.e. the polyfill was installed due to
7550                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7551                   // fake AbortSignal to the native fetch will trigger:
7552                   // TypeError: Failed to execute 'fetch' on 'Window': member signal is not of type AbortSignal.
7553                   delete init.signal;
7554                 } // Return the fastest promise (don't need to wait for request to finish)
7555
7556
7557                 return Promise.race([cancellation, realFetch(input, init)]);
7558               }
7559
7560               return realFetch(input, init);
7561             };
7562
7563             return {
7564               fetch: abortableFetch,
7565               Request: Request
7566             };
7567           }
7568
7569           (function (self) {
7570             if (!polyfillNeeded(self)) {
7571               return;
7572             }
7573
7574             if (!self.fetch) {
7575               console.warn('fetch() is not available, cannot install abortcontroller-polyfill');
7576               return;
7577             }
7578
7579             var _abortableFetch = abortableFetchDecorator(self),
7580                 fetch = _abortableFetch.fetch,
7581                 Request = _abortableFetch.Request;
7582
7583             self.fetch = fetch;
7584             self.Request = Request;
7585             Object.defineProperty(self, 'AbortController', {
7586               writable: true,
7587               enumerable: false,
7588               configurable: true,
7589               value: AbortController
7590             });
7591             Object.defineProperty(self, 'AbortSignal', {
7592               writable: true,
7593               enumerable: false,
7594               configurable: true,
7595               value: AbortSignal
7596             });
7597           })(typeof self !== 'undefined' ? self : commonjsGlobal);
7598         });
7599
7600         function actionAddEntity(way) {
7601           return function (graph) {
7602             return graph.replace(way);
7603           };
7604         }
7605
7606         var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
7607         var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
7608         var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
7609
7610         // We can't use this feature detection in V8 since it causes
7611         // deoptimization and serious performance degradation
7612         // https://github.com/zloirock/core-js/issues/679
7613         var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
7614           var array = [];
7615           array[IS_CONCAT_SPREADABLE] = false;
7616           return array.concat()[0] !== array;
7617         });
7618
7619         var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
7620
7621         var isConcatSpreadable = function (O) {
7622           if (!isObject(O)) return false;
7623           var spreadable = O[IS_CONCAT_SPREADABLE];
7624           return spreadable !== undefined ? !!spreadable : isArray(O);
7625         };
7626
7627         var FORCED$7 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
7628
7629         // `Array.prototype.concat` method
7630         // https://tc39.es/ecma262/#sec-array.prototype.concat
7631         // with adding support of @@isConcatSpreadable and @@species
7632         _export({ target: 'Array', proto: true, forced: FORCED$7 }, {
7633           // eslint-disable-next-line no-unused-vars -- required for `.length`
7634           concat: function concat(arg) {
7635             var O = toObject(this);
7636             var A = arraySpeciesCreate(O, 0);
7637             var n = 0;
7638             var i, k, length, len, E;
7639             for (i = -1, length = arguments.length; i < length; i++) {
7640               E = i === -1 ? O : arguments[i];
7641               if (isConcatSpreadable(E)) {
7642                 len = toLength(E.length);
7643                 if (n + len > MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7644                 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
7645               } else {
7646                 if (n >= MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7647                 createProperty(A, n++, E);
7648               }
7649             }
7650             A.length = n;
7651             return A;
7652           }
7653         });
7654
7655         // `Object.assign` method
7656         // https://tc39.es/ecma262/#sec-object.assign
7657         _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {
7658           assign: objectAssign
7659         });
7660
7661         var $filter$1 = arrayIteration.filter;
7662
7663
7664         var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport('filter');
7665
7666         // `Array.prototype.filter` method
7667         // https://tc39.es/ecma262/#sec-array.prototype.filter
7668         // with adding support of @@species
7669         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 }, {
7670           filter: function filter(callbackfn /* , thisArg */) {
7671             return $filter$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
7672           }
7673         });
7674
7675         var FAILS_ON_PRIMITIVES$3 = fails(function () { objectKeys(1); });
7676
7677         // `Object.keys` method
7678         // https://tc39.es/ecma262/#sec-object.keys
7679         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3 }, {
7680           keys: function keys(it) {
7681             return objectKeys(toObject(it));
7682           }
7683         });
7684
7685         var nativeReverse = [].reverse;
7686         var test$1 = [1, 2];
7687
7688         // `Array.prototype.reverse` method
7689         // https://tc39.es/ecma262/#sec-array.prototype.reverse
7690         // fix for Safari 12.0 bug
7691         // https://bugs.webkit.org/show_bug.cgi?id=188794
7692         _export({ target: 'Array', proto: true, forced: String(test$1) === String(test$1.reverse()) }, {
7693           reverse: function reverse() {
7694             // eslint-disable-next-line no-self-assign -- dirty hack
7695             if (isArray(this)) this.length = this.length;
7696             return nativeReverse.call(this);
7697           }
7698         });
7699
7700         var trim = stringTrim.trim;
7701
7702
7703         var $parseFloat = global_1.parseFloat;
7704         var FORCED$8 = 1 / $parseFloat(whitespaces + '-0') !== -Infinity;
7705
7706         // `parseFloat` method
7707         // https://tc39.es/ecma262/#sec-parsefloat-string
7708         var numberParseFloat = FORCED$8 ? function parseFloat(string) {
7709           var trimmedString = trim(String(string));
7710           var result = $parseFloat(trimmedString);
7711           return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
7712         } : $parseFloat;
7713
7714         // `parseFloat` method
7715         // https://tc39.es/ecma262/#sec-parsefloat-string
7716         _export({ global: true, forced: parseFloat != numberParseFloat }, {
7717           parseFloat: numberParseFloat
7718         });
7719
7720         /*
7721         Order the nodes of a way in reverse order and reverse any direction dependent tags
7722         other than `oneway`. (We assume that correcting a backwards oneway is the primary
7723         reason for reversing a way.)
7724
7725         In addition, numeric-valued `incline` tags are negated.
7726
7727         The JOSM implementation was used as a guide, but transformations that were of unclear benefit
7728         or adjusted tags that don't seem to be used in practice were omitted.
7729
7730         References:
7731             http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
7732             http://wiki.openstreetmap.org/wiki/Key:direction#Steps
7733             http://wiki.openstreetmap.org/wiki/Key:incline
7734             http://wiki.openstreetmap.org/wiki/Route#Members
7735             http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
7736             http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
7737             http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
7738         */
7739         function actionReverse(entityID, options) {
7740           var ignoreKey = /^.*(_|:)?(description|name|note|website|ref|source|comment|watch|attribution)(_|:)?/;
7741           var numeric = /^([+\-]?)(?=[\d.])/;
7742           var directionKey = /direction$/;
7743           var turn_lanes = /^turn:lanes:?/;
7744           var keyReplacements = [[/:right$/, ':left'], [/:left$/, ':right'], [/:forward$/, ':backward'], [/:backward$/, ':forward'], [/:right:/, ':left:'], [/:left:/, ':right:'], [/:forward:/, ':backward:'], [/:backward:/, ':forward:']];
7745           var valueReplacements = {
7746             left: 'right',
7747             right: 'left',
7748             up: 'down',
7749             down: 'up',
7750             forward: 'backward',
7751             backward: 'forward',
7752             forwards: 'backward',
7753             backwards: 'forward'
7754           };
7755           var roleReplacements = {
7756             forward: 'backward',
7757             backward: 'forward',
7758             forwards: 'backward',
7759             backwards: 'forward'
7760           };
7761           var onewayReplacements = {
7762             yes: '-1',
7763             '1': '-1',
7764             '-1': 'yes'
7765           };
7766           var compassReplacements = {
7767             N: 'S',
7768             NNE: 'SSW',
7769             NE: 'SW',
7770             ENE: 'WSW',
7771             E: 'W',
7772             ESE: 'WNW',
7773             SE: 'NW',
7774             SSE: 'NNW',
7775             S: 'N',
7776             SSW: 'NNE',
7777             SW: 'NE',
7778             WSW: 'ENE',
7779             W: 'E',
7780             WNW: 'ESE',
7781             NW: 'SE',
7782             NNW: 'SSE'
7783           };
7784
7785           function reverseKey(key) {
7786             for (var i = 0; i < keyReplacements.length; ++i) {
7787               var replacement = keyReplacements[i];
7788
7789               if (replacement[0].test(key)) {
7790                 return key.replace(replacement[0], replacement[1]);
7791               }
7792             }
7793
7794             return key;
7795           }
7796
7797           function reverseValue(key, value, includeAbsolute) {
7798             if (ignoreKey.test(key)) return value; // Turn lanes are left/right to key (not way) direction - #5674
7799
7800             if (turn_lanes.test(key)) {
7801               return value;
7802             } else if (key === 'incline' && numeric.test(value)) {
7803               return value.replace(numeric, function (_, sign) {
7804                 return sign === '-' ? '' : '-';
7805               });
7806             } else if (options && options.reverseOneway && key === 'oneway') {
7807               return onewayReplacements[value] || value;
7808             } else if (includeAbsolute && directionKey.test(key)) {
7809               if (compassReplacements[value]) return compassReplacements[value];
7810               var degrees = parseFloat(value);
7811
7812               if (typeof degrees === 'number' && !isNaN(degrees)) {
7813                 if (degrees < 180) {
7814                   degrees += 180;
7815                 } else {
7816                   degrees -= 180;
7817                 }
7818
7819                 return degrees.toString();
7820               }
7821             }
7822
7823             return valueReplacements[value] || value;
7824           } // Reverse the direction of tags attached to the nodes - #3076
7825
7826
7827           function reverseNodeTags(graph, nodeIDs) {
7828             for (var i = 0; i < nodeIDs.length; i++) {
7829               var node = graph.hasEntity(nodeIDs[i]);
7830               if (!node || !Object.keys(node.tags).length) continue;
7831               var tags = {};
7832
7833               for (var key in node.tags) {
7834                 tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
7835               }
7836
7837               graph = graph.replace(node.update({
7838                 tags: tags
7839               }));
7840             }
7841
7842             return graph;
7843           }
7844
7845           function reverseWay(graph, way) {
7846             var nodes = way.nodes.slice().reverse();
7847             var tags = {};
7848             var role;
7849
7850             for (var key in way.tags) {
7851               tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
7852             }
7853
7854             graph.parentRelations(way).forEach(function (relation) {
7855               relation.members.forEach(function (member, index) {
7856                 if (member.id === way.id && (role = roleReplacements[member.role])) {
7857                   relation = relation.updateMember({
7858                     role: role
7859                   }, index);
7860                   graph = graph.replace(relation);
7861                 }
7862               });
7863             }); // Reverse any associated directions on nodes on the way and then replace
7864             // the way itself with the reversed node ids and updated way tags
7865
7866             return reverseNodeTags(graph, nodes).replace(way.update({
7867               nodes: nodes,
7868               tags: tags
7869             }));
7870           }
7871
7872           var action = function action(graph) {
7873             var entity = graph.entity(entityID);
7874
7875             if (entity.type === 'way') {
7876               return reverseWay(graph, entity);
7877             }
7878
7879             return reverseNodeTags(graph, [entityID]);
7880           };
7881
7882           action.disabled = function (graph) {
7883             var entity = graph.hasEntity(entityID);
7884             if (!entity || entity.type === 'way') return false;
7885
7886             for (var key in entity.tags) {
7887               var value = entity.tags[key];
7888
7889               if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
7890                 return false;
7891               }
7892             }
7893
7894             return 'nondirectional_node';
7895           };
7896
7897           action.entityID = function () {
7898             return entityID;
7899           };
7900
7901           return action;
7902         }
7903
7904         function osmIsInterestingTag(key) {
7905           return key !== 'attribution' && key !== 'created_by' && key !== 'source' && key !== 'odbl' && key.indexOf('source:') !== 0 && key.indexOf('source_ref') !== 0 && // purposely exclude colon
7906           key.indexOf('tiger:') !== 0;
7907         }
7908         var osmAreaKeys = {};
7909         function osmSetAreaKeys(value) {
7910           osmAreaKeys = value;
7911         } // returns an object with the tag from `tags` that implies an area geometry, if any
7912
7913         function osmTagSuggestingArea(tags) {
7914           if (tags.area === 'yes') return {
7915             area: 'yes'
7916           };
7917           if (tags.area === 'no') return null; // `highway` and `railway` are typically linear features, but there
7918           // are a few exceptions that should be treated as areas, even in the
7919           // absence of a proper `area=yes` or `areaKeys` tag.. see #4194
7920
7921           var lineKeys = {
7922             highway: {
7923               rest_area: true,
7924               services: true
7925             },
7926             railway: {
7927               roundhouse: true,
7928               station: true,
7929               traverser: true,
7930               turntable: true,
7931               wash: true
7932             }
7933           };
7934           var returnTags = {};
7935
7936           for (var key in tags) {
7937             if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
7938               returnTags[key] = tags[key];
7939               return returnTags;
7940             }
7941
7942             if (key in lineKeys && tags[key] in lineKeys[key]) {
7943               returnTags[key] = tags[key];
7944               return returnTags;
7945             }
7946           }
7947
7948           return null;
7949         } // Tags that indicate a node can be a standalone point
7950         // e.g. { amenity: { bar: true, parking: true, ... } ... }
7951
7952         var osmPointTags = {};
7953         function osmSetPointTags(value) {
7954           osmPointTags = value;
7955         } // Tags that indicate a node can be part of a way
7956         // e.g. { amenity: { parking: true, ... }, highway: { stop: true ... } ... }
7957
7958         var osmVertexTags = {};
7959         function osmSetVertexTags(value) {
7960           osmVertexTags = value;
7961         }
7962         function osmNodeGeometriesForTags(nodeTags) {
7963           var geometries = {};
7964
7965           for (var key in nodeTags) {
7966             if (osmPointTags[key] && (osmPointTags[key]['*'] || osmPointTags[key][nodeTags[key]])) {
7967               geometries.point = true;
7968             }
7969
7970             if (osmVertexTags[key] && (osmVertexTags[key]['*'] || osmVertexTags[key][nodeTags[key]])) {
7971               geometries.vertex = true;
7972             } // break early if both are already supported
7973
7974
7975             if (geometries.point && geometries.vertex) break;
7976           }
7977
7978           return geometries;
7979         }
7980         var osmOneWayTags = {
7981           'aerialway': {
7982             'chair_lift': true,
7983             'drag_lift': true,
7984             'j-bar': true,
7985             'magic_carpet': true,
7986             'mixed_lift': true,
7987             'platter': true,
7988             'rope_tow': true,
7989             't-bar': true,
7990             'zip_line': true
7991           },
7992           'highway': {
7993             'motorway': true
7994           },
7995           'junction': {
7996             'circular': true,
7997             'roundabout': true
7998           },
7999           'man_made': {
8000             'goods_conveyor': true,
8001             'piste:halfpipe': true
8002           },
8003           'piste:type': {
8004             'downhill': true,
8005             'sled': true,
8006             'yes': true
8007           },
8008           'waterway': {
8009             'canal': true,
8010             'ditch': true,
8011             'drain': true,
8012             'fish_pass': true,
8013             'river': true,
8014             'stream': true,
8015             'tidal_channel': true
8016           }
8017         }; // solid and smooth surfaces akin to the assumed default road surface in OSM
8018
8019         var osmPavedTags = {
8020           'surface': {
8021             'paved': true,
8022             'asphalt': true,
8023             'concrete': true,
8024             'concrete:lanes': true,
8025             'concrete:plates': true
8026           },
8027           'tracktype': {
8028             'grade1': true
8029           }
8030         }; // solid, if somewhat uncommon surfaces with a high range of smoothness
8031
8032         var osmSemipavedTags = {
8033           'surface': {
8034             'cobblestone': true,
8035             'cobblestone:flattened': true,
8036             'unhewn_cobblestone': true,
8037             'sett': true,
8038             'paving_stones': true,
8039             'metal': true,
8040             'wood': true
8041           }
8042         };
8043         var osmRightSideIsInsideTags = {
8044           'natural': {
8045             'cliff': true,
8046             'coastline': 'coastline'
8047           },
8048           'barrier': {
8049             'retaining_wall': true,
8050             'kerb': true,
8051             'guard_rail': true,
8052             'city_wall': true
8053           },
8054           'man_made': {
8055             'embankment': true
8056           },
8057           'waterway': {
8058             'weir': true
8059           }
8060         }; // "highway" tag values for pedestrian or vehicle right-of-ways that make up the routable network
8061         // (does not include `raceway`)
8062
8063         var osmRoutableHighwayTagValues = {
8064           motorway: true,
8065           trunk: true,
8066           primary: true,
8067           secondary: true,
8068           tertiary: true,
8069           residential: true,
8070           motorway_link: true,
8071           trunk_link: true,
8072           primary_link: true,
8073           secondary_link: true,
8074           tertiary_link: true,
8075           unclassified: true,
8076           road: true,
8077           service: true,
8078           track: true,
8079           living_street: true,
8080           bus_guideway: true,
8081           path: true,
8082           footway: true,
8083           cycleway: true,
8084           bridleway: true,
8085           pedestrian: true,
8086           corridor: true,
8087           steps: true
8088         }; // "highway" tag values that generally do not allow motor vehicles
8089
8090         var osmPathHighwayTagValues = {
8091           path: true,
8092           footway: true,
8093           cycleway: true,
8094           bridleway: true,
8095           pedestrian: true,
8096           corridor: true,
8097           steps: true
8098         }; // "railway" tag values representing existing railroad tracks (purposely does not include 'abandoned')
8099
8100         var osmRailwayTrackTagValues = {
8101           rail: true,
8102           light_rail: true,
8103           tram: true,
8104           subway: true,
8105           monorail: true,
8106           funicular: true,
8107           miniature: true,
8108           narrow_gauge: true,
8109           disused: true,
8110           preserved: true
8111         }; // "waterway" tag values for line features representing water flow
8112
8113         var osmFlowingWaterwayTagValues = {
8114           canal: true,
8115           ditch: true,
8116           drain: true,
8117           fish_pass: true,
8118           river: true,
8119           stream: true,
8120           tidal_channel: true
8121         };
8122
8123         var trim$1 = stringTrim.trim;
8124
8125
8126         var $parseInt = global_1.parseInt;
8127         var hex$1 = /^[+-]?0[Xx]/;
8128         var FORCED$9 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22;
8129
8130         // `parseInt` method
8131         // https://tc39.es/ecma262/#sec-parseint-string-radix
8132         var numberParseInt = FORCED$9 ? function parseInt(string, radix) {
8133           var S = trim$1(String(string));
8134           return $parseInt(S, (radix >>> 0) || (hex$1.test(S) ? 16 : 10));
8135         } : $parseInt;
8136
8137         // `parseInt` method
8138         // https://tc39.es/ecma262/#sec-parseint-string-radix
8139         _export({ global: true, forced: parseInt != numberParseInt }, {
8140           parseInt: numberParseInt
8141         });
8142
8143         var freezing = !fails(function () {
8144           return Object.isExtensible(Object.preventExtensions({}));
8145         });
8146
8147         var internalMetadata = createCommonjsModule(function (module) {
8148         var defineProperty = objectDefineProperty.f;
8149
8150
8151
8152         var METADATA = uid('meta');
8153         var id = 0;
8154
8155         var isExtensible = Object.isExtensible || function () {
8156           return true;
8157         };
8158
8159         var setMetadata = function (it) {
8160           defineProperty(it, METADATA, { value: {
8161             objectID: 'O' + ++id, // object ID
8162             weakData: {}          // weak collections IDs
8163           } });
8164         };
8165
8166         var fastKey = function (it, create) {
8167           // return a primitive with prefix
8168           if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
8169           if (!has(it, METADATA)) {
8170             // can't set metadata to uncaught frozen object
8171             if (!isExtensible(it)) return 'F';
8172             // not necessary to add metadata
8173             if (!create) return 'E';
8174             // add missing metadata
8175             setMetadata(it);
8176           // return object ID
8177           } return it[METADATA].objectID;
8178         };
8179
8180         var getWeakData = function (it, create) {
8181           if (!has(it, METADATA)) {
8182             // can't set metadata to uncaught frozen object
8183             if (!isExtensible(it)) return true;
8184             // not necessary to add metadata
8185             if (!create) return false;
8186             // add missing metadata
8187             setMetadata(it);
8188           // return the store of weak collections IDs
8189           } return it[METADATA].weakData;
8190         };
8191
8192         // add metadata on freeze-family methods calling
8193         var onFreeze = function (it) {
8194           if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
8195           return it;
8196         };
8197
8198         var meta = module.exports = {
8199           REQUIRED: false,
8200           fastKey: fastKey,
8201           getWeakData: getWeakData,
8202           onFreeze: onFreeze
8203         };
8204
8205         hiddenKeys[METADATA] = true;
8206         });
8207
8208         var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
8209           var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
8210           var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
8211           var ADDER = IS_MAP ? 'set' : 'add';
8212           var NativeConstructor = global_1[CONSTRUCTOR_NAME];
8213           var NativePrototype = NativeConstructor && NativeConstructor.prototype;
8214           var Constructor = NativeConstructor;
8215           var exported = {};
8216
8217           var fixMethod = function (KEY) {
8218             var nativeMethod = NativePrototype[KEY];
8219             redefine(NativePrototype, KEY,
8220               KEY == 'add' ? function add(value) {
8221                 nativeMethod.call(this, value === 0 ? 0 : value);
8222                 return this;
8223               } : KEY == 'delete' ? function (key) {
8224                 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8225               } : KEY == 'get' ? function get(key) {
8226                 return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
8227               } : KEY == 'has' ? function has(key) {
8228                 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8229               } : function set(key, value) {
8230                 nativeMethod.call(this, key === 0 ? 0 : key, value);
8231                 return this;
8232               }
8233             );
8234           };
8235
8236           var REPLACE = isForced_1(
8237             CONSTRUCTOR_NAME,
8238             typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
8239               new NativeConstructor().entries().next();
8240             }))
8241           );
8242
8243           if (REPLACE) {
8244             // create collection constructor
8245             Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
8246             internalMetadata.REQUIRED = true;
8247           } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
8248             var instance = new Constructor();
8249             // early implementations not supports chaining
8250             var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
8251             // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
8252             var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });
8253             // most early implementations doesn't supports iterables, most modern - not close it correctly
8254             // eslint-disable-next-line no-new -- required for testing
8255             var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });
8256             // for early implementations -0 and +0 not the same
8257             var BUGGY_ZERO = !IS_WEAK && fails(function () {
8258               // V8 ~ Chromium 42- fails only with 5+ elements
8259               var $instance = new NativeConstructor();
8260               var index = 5;
8261               while (index--) $instance[ADDER](index, index);
8262               return !$instance.has(-0);
8263             });
8264
8265             if (!ACCEPT_ITERABLES) {
8266               Constructor = wrapper(function (dummy, iterable) {
8267                 anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
8268                 var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
8269                 if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
8270                 return that;
8271               });
8272               Constructor.prototype = NativePrototype;
8273               NativePrototype.constructor = Constructor;
8274             }
8275
8276             if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
8277               fixMethod('delete');
8278               fixMethod('has');
8279               IS_MAP && fixMethod('get');
8280             }
8281
8282             if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);
8283
8284             // weak collections should not contains .clear method
8285             if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
8286           }
8287
8288           exported[CONSTRUCTOR_NAME] = Constructor;
8289           _export({ global: true, forced: Constructor != NativeConstructor }, exported);
8290
8291           setToStringTag(Constructor, CONSTRUCTOR_NAME);
8292
8293           if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
8294
8295           return Constructor;
8296         };
8297
8298         var defineProperty$7 = objectDefineProperty.f;
8299
8300
8301
8302
8303
8304
8305
8306
8307         var fastKey = internalMetadata.fastKey;
8308
8309
8310         var setInternalState$7 = internalState.set;
8311         var internalStateGetterFor = internalState.getterFor;
8312
8313         var collectionStrong = {
8314           getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
8315             var C = wrapper(function (that, iterable) {
8316               anInstance(that, C, CONSTRUCTOR_NAME);
8317               setInternalState$7(that, {
8318                 type: CONSTRUCTOR_NAME,
8319                 index: objectCreate(null),
8320                 first: undefined,
8321                 last: undefined,
8322                 size: 0
8323               });
8324               if (!descriptors) that.size = 0;
8325               if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
8326             });
8327
8328             var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
8329
8330             var define = function (that, key, value) {
8331               var state = getInternalState(that);
8332               var entry = getEntry(that, key);
8333               var previous, index;
8334               // change existing entry
8335               if (entry) {
8336                 entry.value = value;
8337               // create new entry
8338               } else {
8339                 state.last = entry = {
8340                   index: index = fastKey(key, true),
8341                   key: key,
8342                   value: value,
8343                   previous: previous = state.last,
8344                   next: undefined,
8345                   removed: false
8346                 };
8347                 if (!state.first) state.first = entry;
8348                 if (previous) previous.next = entry;
8349                 if (descriptors) state.size++;
8350                 else that.size++;
8351                 // add to index
8352                 if (index !== 'F') state.index[index] = entry;
8353               } return that;
8354             };
8355
8356             var getEntry = function (that, key) {
8357               var state = getInternalState(that);
8358               // fast case
8359               var index = fastKey(key);
8360               var entry;
8361               if (index !== 'F') return state.index[index];
8362               // frozen object case
8363               for (entry = state.first; entry; entry = entry.next) {
8364                 if (entry.key == key) return entry;
8365               }
8366             };
8367
8368             redefineAll(C.prototype, {
8369               // 23.1.3.1 Map.prototype.clear()
8370               // 23.2.3.2 Set.prototype.clear()
8371               clear: function clear() {
8372                 var that = this;
8373                 var state = getInternalState(that);
8374                 var data = state.index;
8375                 var entry = state.first;
8376                 while (entry) {
8377                   entry.removed = true;
8378                   if (entry.previous) entry.previous = entry.previous.next = undefined;
8379                   delete data[entry.index];
8380                   entry = entry.next;
8381                 }
8382                 state.first = state.last = undefined;
8383                 if (descriptors) state.size = 0;
8384                 else that.size = 0;
8385               },
8386               // 23.1.3.3 Map.prototype.delete(key)
8387               // 23.2.3.4 Set.prototype.delete(value)
8388               'delete': function (key) {
8389                 var that = this;
8390                 var state = getInternalState(that);
8391                 var entry = getEntry(that, key);
8392                 if (entry) {
8393                   var next = entry.next;
8394                   var prev = entry.previous;
8395                   delete state.index[entry.index];
8396                   entry.removed = true;
8397                   if (prev) prev.next = next;
8398                   if (next) next.previous = prev;
8399                   if (state.first == entry) state.first = next;
8400                   if (state.last == entry) state.last = prev;
8401                   if (descriptors) state.size--;
8402                   else that.size--;
8403                 } return !!entry;
8404               },
8405               // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
8406               // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
8407               forEach: function forEach(callbackfn /* , that = undefined */) {
8408                 var state = getInternalState(this);
8409                 var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
8410                 var entry;
8411                 while (entry = entry ? entry.next : state.first) {
8412                   boundFunction(entry.value, entry.key, this);
8413                   // revert to the last existing entry
8414                   while (entry && entry.removed) entry = entry.previous;
8415                 }
8416               },
8417               // 23.1.3.7 Map.prototype.has(key)
8418               // 23.2.3.7 Set.prototype.has(value)
8419               has: function has(key) {
8420                 return !!getEntry(this, key);
8421               }
8422             });
8423
8424             redefineAll(C.prototype, IS_MAP ? {
8425               // 23.1.3.6 Map.prototype.get(key)
8426               get: function get(key) {
8427                 var entry = getEntry(this, key);
8428                 return entry && entry.value;
8429               },
8430               // 23.1.3.9 Map.prototype.set(key, value)
8431               set: function set(key, value) {
8432                 return define(this, key === 0 ? 0 : key, value);
8433               }
8434             } : {
8435               // 23.2.3.1 Set.prototype.add(value)
8436               add: function add(value) {
8437                 return define(this, value = value === 0 ? 0 : value, value);
8438               }
8439             });
8440             if (descriptors) defineProperty$7(C.prototype, 'size', {
8441               get: function () {
8442                 return getInternalState(this).size;
8443               }
8444             });
8445             return C;
8446           },
8447           setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
8448             var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
8449             var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
8450             var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
8451             // add .keys, .values, .entries, [@@iterator]
8452             // 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
8453             defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
8454               setInternalState$7(this, {
8455                 type: ITERATOR_NAME,
8456                 target: iterated,
8457                 state: getInternalCollectionState(iterated),
8458                 kind: kind,
8459                 last: undefined
8460               });
8461             }, function () {
8462               var state = getInternalIteratorState(this);
8463               var kind = state.kind;
8464               var entry = state.last;
8465               // revert to the last existing entry
8466               while (entry && entry.removed) entry = entry.previous;
8467               // get next entry
8468               if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
8469                 // or finish the iteration
8470                 state.target = undefined;
8471                 return { value: undefined, done: true };
8472               }
8473               // return step by kind
8474               if (kind == 'keys') return { value: entry.key, done: false };
8475               if (kind == 'values') return { value: entry.value, done: false };
8476               return { value: [entry.key, entry.value], done: false };
8477             }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
8478
8479             // add [@@species], 23.1.2.2, 23.2.2.2
8480             setSpecies(CONSTRUCTOR_NAME);
8481           }
8482         };
8483
8484         // `Set` constructor
8485         // https://tc39.es/ecma262/#sec-set-objects
8486         var es_set = collection('Set', function (init) {
8487           return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
8488         }, collectionStrong);
8489
8490         function d3_ascending (a, b) {
8491           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
8492         }
8493
8494         function d3_bisector (f) {
8495           var delta = f;
8496           var compare = f;
8497
8498           if (f.length === 1) {
8499             delta = function delta(d, x) {
8500               return f(d) - x;
8501             };
8502
8503             compare = ascendingComparator(f);
8504           }
8505
8506           function left(a, x, lo, hi) {
8507             if (lo == null) lo = 0;
8508             if (hi == null) hi = a.length;
8509
8510             while (lo < hi) {
8511               var mid = lo + hi >>> 1;
8512               if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
8513             }
8514
8515             return lo;
8516           }
8517
8518           function right(a, x, lo, hi) {
8519             if (lo == null) lo = 0;
8520             if (hi == null) hi = a.length;
8521
8522             while (lo < hi) {
8523               var mid = lo + hi >>> 1;
8524               if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
8525             }
8526
8527             return lo;
8528           }
8529
8530           function center(a, x, lo, hi) {
8531             if (lo == null) lo = 0;
8532             if (hi == null) hi = a.length;
8533             var i = left(a, x, lo, hi - 1);
8534             return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
8535           }
8536
8537           return {
8538             left: left,
8539             center: center,
8540             right: right
8541           };
8542         }
8543
8544         function ascendingComparator(f) {
8545           return function (d, x) {
8546             return d3_ascending(f(d), x);
8547           };
8548         }
8549
8550         // `Symbol.asyncIterator` well-known symbol
8551         // https://tc39.es/ecma262/#sec-symbol.asynciterator
8552         defineWellKnownSymbol('asyncIterator');
8553
8554         var runtime_1 = createCommonjsModule(function (module) {
8555           /**
8556            * Copyright (c) 2014-present, Facebook, Inc.
8557            *
8558            * This source code is licensed under the MIT license found in the
8559            * LICENSE file in the root directory of this source tree.
8560            */
8561           var runtime = function (exports) {
8562
8563             var Op = Object.prototype;
8564             var hasOwn = Op.hasOwnProperty;
8565             var undefined$1; // More compressible than void 0.
8566
8567             var $Symbol = typeof Symbol === "function" ? Symbol : {};
8568             var iteratorSymbol = $Symbol.iterator || "@@iterator";
8569             var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
8570             var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
8571
8572             function define(obj, key, value) {
8573               Object.defineProperty(obj, key, {
8574                 value: value,
8575                 enumerable: true,
8576                 configurable: true,
8577                 writable: true
8578               });
8579               return obj[key];
8580             }
8581
8582             try {
8583               // IE 8 has a broken Object.defineProperty that only works on DOM objects.
8584               define({}, "");
8585             } catch (err) {
8586               define = function define(obj, key, value) {
8587                 return obj[key] = value;
8588               };
8589             }
8590
8591             function wrap(innerFn, outerFn, self, tryLocsList) {
8592               // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
8593               var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
8594               var generator = Object.create(protoGenerator.prototype);
8595               var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
8596               // .throw, and .return methods.
8597
8598               generator._invoke = makeInvokeMethod(innerFn, self, context);
8599               return generator;
8600             }
8601
8602             exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
8603             // record like context.tryEntries[i].completion. This interface could
8604             // have been (and was previously) designed to take a closure to be
8605             // invoked without arguments, but in all the cases we care about we
8606             // already have an existing method we want to call, so there's no need
8607             // to create a new function object. We can even get away with assuming
8608             // the method takes exactly one argument, since that happens to be true
8609             // in every case, so we don't have to touch the arguments object. The
8610             // only additional allocation required is the completion record, which
8611             // has a stable shape and so hopefully should be cheap to allocate.
8612
8613             function tryCatch(fn, obj, arg) {
8614               try {
8615                 return {
8616                   type: "normal",
8617                   arg: fn.call(obj, arg)
8618                 };
8619               } catch (err) {
8620                 return {
8621                   type: "throw",
8622                   arg: err
8623                 };
8624               }
8625             }
8626
8627             var GenStateSuspendedStart = "suspendedStart";
8628             var GenStateSuspendedYield = "suspendedYield";
8629             var GenStateExecuting = "executing";
8630             var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
8631             // breaking out of the dispatch switch statement.
8632
8633             var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
8634             // .constructor.prototype properties for functions that return Generator
8635             // objects. For full spec compliance, you may wish to configure your
8636             // minifier not to mangle the names of these two functions.
8637
8638             function Generator() {}
8639
8640             function GeneratorFunction() {}
8641
8642             function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
8643             // don't natively support it.
8644
8645
8646             var IteratorPrototype = {};
8647
8648             IteratorPrototype[iteratorSymbol] = function () {
8649               return this;
8650             };
8651
8652             var getProto = Object.getPrototypeOf;
8653             var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
8654
8655             if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
8656               // This environment has a native %IteratorPrototype%; use it instead
8657               // of the polyfill.
8658               IteratorPrototype = NativeIteratorPrototype;
8659             }
8660
8661             var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
8662             GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
8663             GeneratorFunctionPrototype.constructor = GeneratorFunction;
8664             GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
8665             // Iterator interface in terms of a single ._invoke method.
8666
8667             function defineIteratorMethods(prototype) {
8668               ["next", "throw", "return"].forEach(function (method) {
8669                 define(prototype, method, function (arg) {
8670                   return this._invoke(method, arg);
8671                 });
8672               });
8673             }
8674
8675             exports.isGeneratorFunction = function (genFun) {
8676               var ctor = typeof genFun === "function" && genFun.constructor;
8677               return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
8678               // do is to check its .name property.
8679               (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
8680             };
8681
8682             exports.mark = function (genFun) {
8683               if (Object.setPrototypeOf) {
8684                 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
8685               } else {
8686                 genFun.__proto__ = GeneratorFunctionPrototype;
8687                 define(genFun, toStringTagSymbol, "GeneratorFunction");
8688               }
8689
8690               genFun.prototype = Object.create(Gp);
8691               return genFun;
8692             }; // Within the body of any async function, `await x` is transformed to
8693             // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
8694             // `hasOwn.call(value, "__await")` to determine if the yielded value is
8695             // meant to be awaited.
8696
8697
8698             exports.awrap = function (arg) {
8699               return {
8700                 __await: arg
8701               };
8702             };
8703
8704             function AsyncIterator(generator, PromiseImpl) {
8705               function invoke(method, arg, resolve, reject) {
8706                 var record = tryCatch(generator[method], generator, arg);
8707
8708                 if (record.type === "throw") {
8709                   reject(record.arg);
8710                 } else {
8711                   var result = record.arg;
8712                   var value = result.value;
8713
8714                   if (value && _typeof(value) === "object" && hasOwn.call(value, "__await")) {
8715                     return PromiseImpl.resolve(value.__await).then(function (value) {
8716                       invoke("next", value, resolve, reject);
8717                     }, function (err) {
8718                       invoke("throw", err, resolve, reject);
8719                     });
8720                   }
8721
8722                   return PromiseImpl.resolve(value).then(function (unwrapped) {
8723                     // When a yielded Promise is resolved, its final value becomes
8724                     // the .value of the Promise<{value,done}> result for the
8725                     // current iteration.
8726                     result.value = unwrapped;
8727                     resolve(result);
8728                   }, function (error) {
8729                     // If a rejected Promise was yielded, throw the rejection back
8730                     // into the async generator function so it can be handled there.
8731                     return invoke("throw", error, resolve, reject);
8732                   });
8733                 }
8734               }
8735
8736               var previousPromise;
8737
8738               function enqueue(method, arg) {
8739                 function callInvokeWithMethodAndArg() {
8740                   return new PromiseImpl(function (resolve, reject) {
8741                     invoke(method, arg, resolve, reject);
8742                   });
8743                 }
8744
8745                 return previousPromise = // If enqueue has been called before, then we want to wait until
8746                 // all previous Promises have been resolved before calling invoke,
8747                 // so that results are always delivered in the correct order. If
8748                 // enqueue has not been called before, then it is important to
8749                 // call invoke immediately, without waiting on a callback to fire,
8750                 // so that the async generator function has the opportunity to do
8751                 // any necessary setup in a predictable way. This predictability
8752                 // is why the Promise constructor synchronously invokes its
8753                 // executor callback, and why async functions synchronously
8754                 // execute code before the first await. Since we implement simple
8755                 // async functions in terms of async generators, it is especially
8756                 // important to get this right, even though it requires care.
8757                 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
8758                 // invocations of the iterator.
8759                 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
8760               } // Define the unified helper method that is used to implement .next,
8761               // .throw, and .return (see defineIteratorMethods).
8762
8763
8764               this._invoke = enqueue;
8765             }
8766
8767             defineIteratorMethods(AsyncIterator.prototype);
8768
8769             AsyncIterator.prototype[asyncIteratorSymbol] = function () {
8770               return this;
8771             };
8772
8773             exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
8774             // AsyncIterator objects; they just return a Promise for the value of
8775             // the final result produced by the iterator.
8776
8777             exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
8778               if (PromiseImpl === void 0) PromiseImpl = Promise;
8779               var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
8780               return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
8781               : iter.next().then(function (result) {
8782                 return result.done ? result.value : iter.next();
8783               });
8784             };
8785
8786             function makeInvokeMethod(innerFn, self, context) {
8787               var state = GenStateSuspendedStart;
8788               return function invoke(method, arg) {
8789                 if (state === GenStateExecuting) {
8790                   throw new Error("Generator is already running");
8791                 }
8792
8793                 if (state === GenStateCompleted) {
8794                   if (method === "throw") {
8795                     throw arg;
8796                   } // Be forgiving, per 25.3.3.3.3 of the spec:
8797                   // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
8798
8799
8800                   return doneResult();
8801                 }
8802
8803                 context.method = method;
8804                 context.arg = arg;
8805
8806                 while (true) {
8807                   var delegate = context.delegate;
8808
8809                   if (delegate) {
8810                     var delegateResult = maybeInvokeDelegate(delegate, context);
8811
8812                     if (delegateResult) {
8813                       if (delegateResult === ContinueSentinel) continue;
8814                       return delegateResult;
8815                     }
8816                   }
8817
8818                   if (context.method === "next") {
8819                     // Setting context._sent for legacy support of Babel's
8820                     // function.sent implementation.
8821                     context.sent = context._sent = context.arg;
8822                   } else if (context.method === "throw") {
8823                     if (state === GenStateSuspendedStart) {
8824                       state = GenStateCompleted;
8825                       throw context.arg;
8826                     }
8827
8828                     context.dispatchException(context.arg);
8829                   } else if (context.method === "return") {
8830                     context.abrupt("return", context.arg);
8831                   }
8832
8833                   state = GenStateExecuting;
8834                   var record = tryCatch(innerFn, self, context);
8835
8836                   if (record.type === "normal") {
8837                     // If an exception is thrown from innerFn, we leave state ===
8838                     // GenStateExecuting and loop back for another invocation.
8839                     state = context.done ? GenStateCompleted : GenStateSuspendedYield;
8840
8841                     if (record.arg === ContinueSentinel) {
8842                       continue;
8843                     }
8844
8845                     return {
8846                       value: record.arg,
8847                       done: context.done
8848                     };
8849                   } else if (record.type === "throw") {
8850                     state = GenStateCompleted; // Dispatch the exception by looping back around to the
8851                     // context.dispatchException(context.arg) call above.
8852
8853                     context.method = "throw";
8854                     context.arg = record.arg;
8855                   }
8856                 }
8857               };
8858             } // Call delegate.iterator[context.method](context.arg) and handle the
8859             // result, either by returning a { value, done } result from the
8860             // delegate iterator, or by modifying context.method and context.arg,
8861             // setting context.delegate to null, and returning the ContinueSentinel.
8862
8863
8864             function maybeInvokeDelegate(delegate, context) {
8865               var method = delegate.iterator[context.method];
8866
8867               if (method === undefined$1) {
8868                 // A .throw or .return when the delegate iterator has no .throw
8869                 // method always terminates the yield* loop.
8870                 context.delegate = null;
8871
8872                 if (context.method === "throw") {
8873                   // Note: ["return"] must be used for ES3 parsing compatibility.
8874                   if (delegate.iterator["return"]) {
8875                     // If the delegate iterator has a return method, give it a
8876                     // chance to clean up.
8877                     context.method = "return";
8878                     context.arg = undefined$1;
8879                     maybeInvokeDelegate(delegate, context);
8880
8881                     if (context.method === "throw") {
8882                       // If maybeInvokeDelegate(context) changed context.method from
8883                       // "return" to "throw", let that override the TypeError below.
8884                       return ContinueSentinel;
8885                     }
8886                   }
8887
8888                   context.method = "throw";
8889                   context.arg = new TypeError("The iterator does not provide a 'throw' method");
8890                 }
8891
8892                 return ContinueSentinel;
8893               }
8894
8895               var record = tryCatch(method, delegate.iterator, context.arg);
8896
8897               if (record.type === "throw") {
8898                 context.method = "throw";
8899                 context.arg = record.arg;
8900                 context.delegate = null;
8901                 return ContinueSentinel;
8902               }
8903
8904               var info = record.arg;
8905
8906               if (!info) {
8907                 context.method = "throw";
8908                 context.arg = new TypeError("iterator result is not an object");
8909                 context.delegate = null;
8910                 return ContinueSentinel;
8911               }
8912
8913               if (info.done) {
8914                 // Assign the result of the finished delegate to the temporary
8915                 // variable specified by delegate.resultName (see delegateYield).
8916                 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
8917
8918                 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
8919                 // exception, let the outer generator proceed normally. If
8920                 // context.method was "next", forget context.arg since it has been
8921                 // "consumed" by the delegate iterator. If context.method was
8922                 // "return", allow the original .return call to continue in the
8923                 // outer generator.
8924
8925                 if (context.method !== "return") {
8926                   context.method = "next";
8927                   context.arg = undefined$1;
8928                 }
8929               } else {
8930                 // Re-yield the result returned by the delegate method.
8931                 return info;
8932               } // The delegate iterator is finished, so forget it and continue with
8933               // the outer generator.
8934
8935
8936               context.delegate = null;
8937               return ContinueSentinel;
8938             } // Define Generator.prototype.{next,throw,return} in terms of the
8939             // unified ._invoke helper method.
8940
8941
8942             defineIteratorMethods(Gp);
8943             define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
8944             // @@iterator function is called on it. Some browsers' implementations of the
8945             // iterator prototype chain incorrectly implement this, causing the Generator
8946             // object to not be returned from this call. This ensures that doesn't happen.
8947             // See https://github.com/facebook/regenerator/issues/274 for more details.
8948
8949             Gp[iteratorSymbol] = function () {
8950               return this;
8951             };
8952
8953             Gp.toString = function () {
8954               return "[object Generator]";
8955             };
8956
8957             function pushTryEntry(locs) {
8958               var entry = {
8959                 tryLoc: locs[0]
8960               };
8961
8962               if (1 in locs) {
8963                 entry.catchLoc = locs[1];
8964               }
8965
8966               if (2 in locs) {
8967                 entry.finallyLoc = locs[2];
8968                 entry.afterLoc = locs[3];
8969               }
8970
8971               this.tryEntries.push(entry);
8972             }
8973
8974             function resetTryEntry(entry) {
8975               var record = entry.completion || {};
8976               record.type = "normal";
8977               delete record.arg;
8978               entry.completion = record;
8979             }
8980
8981             function Context(tryLocsList) {
8982               // The root entry object (effectively a try statement without a catch
8983               // or a finally block) gives us a place to store values thrown from
8984               // locations where there is no enclosing try statement.
8985               this.tryEntries = [{
8986                 tryLoc: "root"
8987               }];
8988               tryLocsList.forEach(pushTryEntry, this);
8989               this.reset(true);
8990             }
8991
8992             exports.keys = function (object) {
8993               var keys = [];
8994
8995               for (var key in object) {
8996                 keys.push(key);
8997               }
8998
8999               keys.reverse(); // Rather than returning an object with a next method, we keep
9000               // things simple and return the next function itself.
9001
9002               return function next() {
9003                 while (keys.length) {
9004                   var key = keys.pop();
9005
9006                   if (key in object) {
9007                     next.value = key;
9008                     next.done = false;
9009                     return next;
9010                   }
9011                 } // To avoid creating an additional object, we just hang the .value
9012                 // and .done properties off the next function object itself. This
9013                 // also ensures that the minifier will not anonymize the function.
9014
9015
9016                 next.done = true;
9017                 return next;
9018               };
9019             };
9020
9021             function values(iterable) {
9022               if (iterable) {
9023                 var iteratorMethod = iterable[iteratorSymbol];
9024
9025                 if (iteratorMethod) {
9026                   return iteratorMethod.call(iterable);
9027                 }
9028
9029                 if (typeof iterable.next === "function") {
9030                   return iterable;
9031                 }
9032
9033                 if (!isNaN(iterable.length)) {
9034                   var i = -1,
9035                       next = function next() {
9036                     while (++i < iterable.length) {
9037                       if (hasOwn.call(iterable, i)) {
9038                         next.value = iterable[i];
9039                         next.done = false;
9040                         return next;
9041                       }
9042                     }
9043
9044                     next.value = undefined$1;
9045                     next.done = true;
9046                     return next;
9047                   };
9048
9049                   return next.next = next;
9050                 }
9051               } // Return an iterator with no values.
9052
9053
9054               return {
9055                 next: doneResult
9056               };
9057             }
9058
9059             exports.values = values;
9060
9061             function doneResult() {
9062               return {
9063                 value: undefined$1,
9064                 done: true
9065               };
9066             }
9067
9068             Context.prototype = {
9069               constructor: Context,
9070               reset: function reset(skipTempReset) {
9071                 this.prev = 0;
9072                 this.next = 0; // Resetting context._sent for legacy support of Babel's
9073                 // function.sent implementation.
9074
9075                 this.sent = this._sent = undefined$1;
9076                 this.done = false;
9077                 this.delegate = null;
9078                 this.method = "next";
9079                 this.arg = undefined$1;
9080                 this.tryEntries.forEach(resetTryEntry);
9081
9082                 if (!skipTempReset) {
9083                   for (var name in this) {
9084                     // Not sure about the optimal order of these conditions:
9085                     if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
9086                       this[name] = undefined$1;
9087                     }
9088                   }
9089                 }
9090               },
9091               stop: function stop() {
9092                 this.done = true;
9093                 var rootEntry = this.tryEntries[0];
9094                 var rootRecord = rootEntry.completion;
9095
9096                 if (rootRecord.type === "throw") {
9097                   throw rootRecord.arg;
9098                 }
9099
9100                 return this.rval;
9101               },
9102               dispatchException: function dispatchException(exception) {
9103                 if (this.done) {
9104                   throw exception;
9105                 }
9106
9107                 var context = this;
9108
9109                 function handle(loc, caught) {
9110                   record.type = "throw";
9111                   record.arg = exception;
9112                   context.next = loc;
9113
9114                   if (caught) {
9115                     // If the dispatched exception was caught by a catch block,
9116                     // then let that catch block handle the exception normally.
9117                     context.method = "next";
9118                     context.arg = undefined$1;
9119                   }
9120
9121                   return !!caught;
9122                 }
9123
9124                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9125                   var entry = this.tryEntries[i];
9126                   var record = entry.completion;
9127
9128                   if (entry.tryLoc === "root") {
9129                     // Exception thrown outside of any try block that could handle
9130                     // it, so set the completion value of the entire function to
9131                     // throw the exception.
9132                     return handle("end");
9133                   }
9134
9135                   if (entry.tryLoc <= this.prev) {
9136                     var hasCatch = hasOwn.call(entry, "catchLoc");
9137                     var hasFinally = hasOwn.call(entry, "finallyLoc");
9138
9139                     if (hasCatch && hasFinally) {
9140                       if (this.prev < entry.catchLoc) {
9141                         return handle(entry.catchLoc, true);
9142                       } else if (this.prev < entry.finallyLoc) {
9143                         return handle(entry.finallyLoc);
9144                       }
9145                     } else if (hasCatch) {
9146                       if (this.prev < entry.catchLoc) {
9147                         return handle(entry.catchLoc, true);
9148                       }
9149                     } else if (hasFinally) {
9150                       if (this.prev < entry.finallyLoc) {
9151                         return handle(entry.finallyLoc);
9152                       }
9153                     } else {
9154                       throw new Error("try statement without catch or finally");
9155                     }
9156                   }
9157                 }
9158               },
9159               abrupt: function abrupt(type, arg) {
9160                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9161                   var entry = this.tryEntries[i];
9162
9163                   if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
9164                     var finallyEntry = entry;
9165                     break;
9166                   }
9167                 }
9168
9169                 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
9170                   // Ignore the finally entry if control is not jumping to a
9171                   // location outside the try/catch block.
9172                   finallyEntry = null;
9173                 }
9174
9175                 var record = finallyEntry ? finallyEntry.completion : {};
9176                 record.type = type;
9177                 record.arg = arg;
9178
9179                 if (finallyEntry) {
9180                   this.method = "next";
9181                   this.next = finallyEntry.finallyLoc;
9182                   return ContinueSentinel;
9183                 }
9184
9185                 return this.complete(record);
9186               },
9187               complete: function complete(record, afterLoc) {
9188                 if (record.type === "throw") {
9189                   throw record.arg;
9190                 }
9191
9192                 if (record.type === "break" || record.type === "continue") {
9193                   this.next = record.arg;
9194                 } else if (record.type === "return") {
9195                   this.rval = this.arg = record.arg;
9196                   this.method = "return";
9197                   this.next = "end";
9198                 } else if (record.type === "normal" && afterLoc) {
9199                   this.next = afterLoc;
9200                 }
9201
9202                 return ContinueSentinel;
9203               },
9204               finish: function finish(finallyLoc) {
9205                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9206                   var entry = this.tryEntries[i];
9207
9208                   if (entry.finallyLoc === finallyLoc) {
9209                     this.complete(entry.completion, entry.afterLoc);
9210                     resetTryEntry(entry);
9211                     return ContinueSentinel;
9212                   }
9213                 }
9214               },
9215               "catch": function _catch(tryLoc) {
9216                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9217                   var entry = this.tryEntries[i];
9218
9219                   if (entry.tryLoc === tryLoc) {
9220                     var record = entry.completion;
9221
9222                     if (record.type === "throw") {
9223                       var thrown = record.arg;
9224                       resetTryEntry(entry);
9225                     }
9226
9227                     return thrown;
9228                   }
9229                 } // The context.catch method must only be called with a location
9230                 // argument that corresponds to a known catch block.
9231
9232
9233                 throw new Error("illegal catch attempt");
9234               },
9235               delegateYield: function delegateYield(iterable, resultName, nextLoc) {
9236                 this.delegate = {
9237                   iterator: values(iterable),
9238                   resultName: resultName,
9239                   nextLoc: nextLoc
9240                 };
9241
9242                 if (this.method === "next") {
9243                   // Deliberately forget the last sent value so that we don't
9244                   // accidentally pass it on to the delegate.
9245                   this.arg = undefined$1;
9246                 }
9247
9248                 return ContinueSentinel;
9249               }
9250             }; // Regardless of whether this script is executing as a CommonJS module
9251             // or not, return the runtime object so that we can declare the variable
9252             // regeneratorRuntime in the outer scope, which allows this module to be
9253             // injected easily by `bin/regenerator --include-runtime script.js`.
9254
9255             return exports;
9256           }( // If this script is executing as a CommonJS module, use module.exports
9257           // as the regeneratorRuntime namespace. Otherwise create a new empty
9258           // object. Either way, the resulting object will be used to initialize
9259           // the regeneratorRuntime variable at the top of this file.
9260            module.exports );
9261
9262           try {
9263             regeneratorRuntime = runtime;
9264           } catch (accidentalStrictMode) {
9265             // This module should not be running in strict mode, so the above
9266             // assignment should always work unless something is misconfigured. Just
9267             // in case runtime.js accidentally runs in strict mode, we can escape
9268             // strict mode using a global Function call. This could conceivably fail
9269             // if a Content Security Policy forbids using Function, but in that case
9270             // the proper solution is to fix the accidental strict mode problem. If
9271             // you've misconfigured your bundler to force strict mode and applied a
9272             // CSP to forbid Function, and you're not willing to fix either of those
9273             // problems, please detail your unique predicament in a GitHub issue.
9274             Function("r", "regeneratorRuntime = r")(runtime);
9275           }
9276         });
9277
9278         var _marked = /*#__PURE__*/regeneratorRuntime.mark(numbers);
9279
9280         function number (x) {
9281           return x === null ? NaN : +x;
9282         }
9283         function numbers(values, valueof) {
9284           var _iterator, _step, value, index, _iterator2, _step2, _value;
9285
9286           return regeneratorRuntime.wrap(function numbers$(_context) {
9287             while (1) {
9288               switch (_context.prev = _context.next) {
9289                 case 0:
9290                   if (!(valueof === undefined)) {
9291                     _context.next = 21;
9292                     break;
9293                   }
9294
9295                   _iterator = _createForOfIteratorHelper(values);
9296                   _context.prev = 2;
9297
9298                   _iterator.s();
9299
9300                 case 4:
9301                   if ((_step = _iterator.n()).done) {
9302                     _context.next = 11;
9303                     break;
9304                   }
9305
9306                   value = _step.value;
9307
9308                   if (!(value != null && (value = +value) >= value)) {
9309                     _context.next = 9;
9310                     break;
9311                   }
9312
9313                   _context.next = 9;
9314                   return value;
9315
9316                 case 9:
9317                   _context.next = 4;
9318                   break;
9319
9320                 case 11:
9321                   _context.next = 16;
9322                   break;
9323
9324                 case 13:
9325                   _context.prev = 13;
9326                   _context.t0 = _context["catch"](2);
9327
9328                   _iterator.e(_context.t0);
9329
9330                 case 16:
9331                   _context.prev = 16;
9332
9333                   _iterator.f();
9334
9335                   return _context.finish(16);
9336
9337                 case 19:
9338                   _context.next = 40;
9339                   break;
9340
9341                 case 21:
9342                   index = -1;
9343                   _iterator2 = _createForOfIteratorHelper(values);
9344                   _context.prev = 23;
9345
9346                   _iterator2.s();
9347
9348                 case 25:
9349                   if ((_step2 = _iterator2.n()).done) {
9350                     _context.next = 32;
9351                     break;
9352                   }
9353
9354                   _value = _step2.value;
9355
9356                   if (!((_value = valueof(_value, ++index, values)) != null && (_value = +_value) >= _value)) {
9357                     _context.next = 30;
9358                     break;
9359                   }
9360
9361                   _context.next = 30;
9362                   return _value;
9363
9364                 case 30:
9365                   _context.next = 25;
9366                   break;
9367
9368                 case 32:
9369                   _context.next = 37;
9370                   break;
9371
9372                 case 34:
9373                   _context.prev = 34;
9374                   _context.t1 = _context["catch"](23);
9375
9376                   _iterator2.e(_context.t1);
9377
9378                 case 37:
9379                   _context.prev = 37;
9380
9381                   _iterator2.f();
9382
9383                   return _context.finish(37);
9384
9385                 case 40:
9386                 case "end":
9387                   return _context.stop();
9388               }
9389             }
9390           }, _marked, null, [[2, 13, 16, 19], [23, 34, 37, 40]]);
9391         }
9392
9393         var ascendingBisect = d3_bisector(d3_ascending);
9394         var bisectRight = ascendingBisect.right;
9395         var bisectCenter = d3_bisector(number).center;
9396
9397         var INCORRECT_ITERATION$1 = !checkCorrectnessOfIteration(function (iterable) {
9398           Array.from(iterable);
9399         });
9400
9401         // `Array.from` method
9402         // https://tc39.es/ecma262/#sec-array.from
9403         _export({ target: 'Array', stat: true, forced: INCORRECT_ITERATION$1 }, {
9404           from: arrayFrom
9405         });
9406
9407         // `Array.prototype.fill` method
9408         // https://tc39.es/ecma262/#sec-array.prototype.fill
9409         _export({ target: 'Array', proto: true }, {
9410           fill: arrayFill
9411         });
9412
9413         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
9414         addToUnscopables('fill');
9415
9416         var $some$1 = arrayIteration.some;
9417
9418
9419         var STRICT_METHOD$4 = arrayMethodIsStrict('some');
9420
9421         // `Array.prototype.some` method
9422         // https://tc39.es/ecma262/#sec-array.prototype.some
9423         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$4 }, {
9424           some: function some(callbackfn /* , thisArg */) {
9425             return $some$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
9426           }
9427         });
9428
9429         var exportTypedArrayStaticMethod$1 = arrayBufferViewCore.exportTypedArrayStaticMethod;
9430
9431
9432         // `%TypedArray%.from` method
9433         // https://tc39.es/ecma262/#sec-%typedarray%.from
9434         exportTypedArrayStaticMethod$1('from', typedArrayFrom, typedArrayConstructorsRequireWrappers);
9435
9436         // `Float64Array` constructor
9437         // https://tc39.es/ecma262/#sec-typedarray-objects
9438         typedArrayConstructor('Float64', function (init) {
9439           return function Float64Array(data, byteOffset, length) {
9440             return init(this, data, byteOffset, length);
9441           };
9442         });
9443
9444         function d3_descending (a, b) {
9445           return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
9446         }
9447
9448         // https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
9449         var Adder = /*#__PURE__*/function () {
9450           function Adder() {
9451             _classCallCheck(this, Adder);
9452
9453             this._partials = new Float64Array(32);
9454             this._n = 0;
9455           }
9456
9457           _createClass(Adder, [{
9458             key: "add",
9459             value: function add(x) {
9460               var p = this._partials;
9461               var i = 0;
9462
9463               for (var j = 0; j < this._n && j < 32; j++) {
9464                 var y = p[j],
9465                     hi = x + y,
9466                     lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
9467                 if (lo) p[i++] = lo;
9468                 x = hi;
9469               }
9470
9471               p[i] = x;
9472               this._n = i + 1;
9473               return this;
9474             }
9475           }, {
9476             key: "valueOf",
9477             value: function valueOf() {
9478               var p = this._partials;
9479               var n = this._n,
9480                   x,
9481                   y,
9482                   lo,
9483                   hi = 0;
9484
9485               if (n > 0) {
9486                 hi = p[--n];
9487
9488                 while (n > 0) {
9489                   x = hi;
9490                   y = p[--n];
9491                   hi = x + y;
9492                   lo = y - (hi - x);
9493                   if (lo) break;
9494                 }
9495
9496                 if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
9497                   y = lo * 2;
9498                   x = hi + y;
9499                   if (y == x - hi) hi = x;
9500                 }
9501               }
9502
9503               return hi;
9504             }
9505           }]);
9506
9507           return Adder;
9508         }();
9509
9510         // `Object.defineProperties` method
9511         // https://tc39.es/ecma262/#sec-object.defineproperties
9512         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
9513           defineProperties: objectDefineProperties
9514         });
9515
9516         // `Map` constructor
9517         // https://tc39.es/ecma262/#sec-map-objects
9518         var es_map = collection('Map', function (init) {
9519           return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };
9520         }, collectionStrong);
9521
9522         var test$2 = [];
9523         var nativeSort = test$2.sort;
9524
9525         // IE8-
9526         var FAILS_ON_UNDEFINED = fails(function () {
9527           test$2.sort(undefined);
9528         });
9529         // V8 bug
9530         var FAILS_ON_NULL = fails(function () {
9531           test$2.sort(null);
9532         });
9533         // Old WebKit
9534         var STRICT_METHOD$5 = arrayMethodIsStrict('sort');
9535
9536         var FORCED$a = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$5;
9537
9538         // `Array.prototype.sort` method
9539         // https://tc39.es/ecma262/#sec-array.prototype.sort
9540         _export({ target: 'Array', proto: true, forced: FORCED$a }, {
9541           sort: function sort(comparefn) {
9542             return comparefn === undefined
9543               ? nativeSort.call(toObject(this))
9544               : nativeSort.call(toObject(this), aFunction$1(comparefn));
9545           }
9546         });
9547
9548         var e10 = Math.sqrt(50),
9549             e5 = Math.sqrt(10),
9550             e2 = Math.sqrt(2);
9551         function ticks (start, stop, count) {
9552           var reverse,
9553               i = -1,
9554               n,
9555               ticks,
9556               step;
9557           stop = +stop, start = +start, count = +count;
9558           if (start === stop && count > 0) return [start];
9559           if (reverse = stop < start) n = start, start = stop, stop = n;
9560           if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
9561
9562           if (step > 0) {
9563             start = Math.ceil(start / step);
9564             stop = Math.floor(stop / step);
9565             ticks = new Array(n = Math.ceil(stop - start + 1));
9566
9567             while (++i < n) {
9568               ticks[i] = (start + i) * step;
9569             }
9570           } else {
9571             step = -step;
9572             start = Math.ceil(start * step);
9573             stop = Math.floor(stop * step);
9574             ticks = new Array(n = Math.ceil(stop - start + 1));
9575
9576             while (++i < n) {
9577               ticks[i] = (start + i) / step;
9578             }
9579           }
9580
9581           if (reverse) ticks.reverse();
9582           return ticks;
9583         }
9584         function tickIncrement(start, stop, count) {
9585           var step = (stop - start) / Math.max(0, count),
9586               power = Math.floor(Math.log(step) / Math.LN10),
9587               error = step / Math.pow(10, power);
9588           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);
9589         }
9590         function tickStep(start, stop, count) {
9591           var step0 = Math.abs(stop - start) / Math.max(0, count),
9592               step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
9593               error = step0 / step1;
9594           if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
9595           return stop < start ? -step1 : step1;
9596         }
9597
9598         function max$4(values, valueof) {
9599           var max;
9600
9601           if (valueof === undefined) {
9602             var _iterator = _createForOfIteratorHelper(values),
9603                 _step;
9604
9605             try {
9606               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9607                 var value = _step.value;
9608
9609                 if (value != null && (max < value || max === undefined && value >= value)) {
9610                   max = value;
9611                 }
9612               }
9613             } catch (err) {
9614               _iterator.e(err);
9615             } finally {
9616               _iterator.f();
9617             }
9618           } else {
9619             var index = -1;
9620
9621             var _iterator2 = _createForOfIteratorHelper(values),
9622                 _step2;
9623
9624             try {
9625               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9626                 var _value = _step2.value;
9627
9628                 if ((_value = valueof(_value, ++index, values)) != null && (max < _value || max === undefined && _value >= _value)) {
9629                   max = _value;
9630                 }
9631               }
9632             } catch (err) {
9633               _iterator2.e(err);
9634             } finally {
9635               _iterator2.f();
9636             }
9637           }
9638
9639           return max;
9640         }
9641
9642         function min$7(values, valueof) {
9643           var min;
9644
9645           if (valueof === undefined) {
9646             var _iterator = _createForOfIteratorHelper(values),
9647                 _step;
9648
9649             try {
9650               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9651                 var value = _step.value;
9652
9653                 if (value != null && (min > value || min === undefined && value >= value)) {
9654                   min = value;
9655                 }
9656               }
9657             } catch (err) {
9658               _iterator.e(err);
9659             } finally {
9660               _iterator.f();
9661             }
9662           } else {
9663             var index = -1;
9664
9665             var _iterator2 = _createForOfIteratorHelper(values),
9666                 _step2;
9667
9668             try {
9669               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9670                 var _value = _step2.value;
9671
9672                 if ((_value = valueof(_value, ++index, values)) != null && (min > _value || min === undefined && _value >= _value)) {
9673                   min = _value;
9674                 }
9675               }
9676             } catch (err) {
9677               _iterator2.e(err);
9678             } finally {
9679               _iterator2.f();
9680             }
9681           }
9682
9683           return min;
9684         }
9685
9686         // ISC license, Copyright 2018 Vladimir Agafonkin.
9687
9688         function quickselect(array, k) {
9689           var left = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
9690           var right = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : array.length - 1;
9691           var compare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : d3_ascending;
9692
9693           while (right > left) {
9694             if (right - left > 600) {
9695               var n = right - left + 1;
9696               var m = k - left + 1;
9697               var z = Math.log(n);
9698               var s = 0.5 * Math.exp(2 * z / 3);
9699               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
9700               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
9701               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
9702               quickselect(array, k, newLeft, newRight, compare);
9703             }
9704
9705             var t = array[k];
9706             var i = left;
9707             var j = right;
9708             swap(array, left, k);
9709             if (compare(array[right], t) > 0) swap(array, left, right);
9710
9711             while (i < j) {
9712               swap(array, i, j), ++i, --j;
9713
9714               while (compare(array[i], t) < 0) {
9715                 ++i;
9716               }
9717
9718               while (compare(array[j], t) > 0) {
9719                 --j;
9720               }
9721             }
9722
9723             if (compare(array[left], t) === 0) swap(array, left, j);else ++j, swap(array, j, right);
9724             if (j <= k) left = j + 1;
9725             if (k <= j) right = j - 1;
9726           }
9727
9728           return array;
9729         }
9730
9731         function swap(array, i, j) {
9732           var t = array[i];
9733           array[i] = array[j];
9734           array[j] = t;
9735         }
9736
9737         function quantile(values, p, valueof) {
9738           values = Float64Array.from(numbers(values, valueof));
9739           if (!(n = values.length)) return;
9740           if ((p = +p) <= 0 || n < 2) return min$7(values);
9741           if (p >= 1) return max$4(values);
9742           var n,
9743               i = (n - 1) * p,
9744               i0 = Math.floor(i),
9745               value0 = max$4(quickselect(values, i0).subarray(0, i0 + 1)),
9746               value1 = min$7(values.subarray(i0 + 1));
9747           return value0 + (value1 - value0) * (i - i0);
9748         }
9749
9750         function d3_median (values, valueof) {
9751           return quantile(values, 0.5, valueof);
9752         }
9753
9754         var _marked$1 = /*#__PURE__*/regeneratorRuntime.mark(flatten);
9755
9756         function flatten(arrays) {
9757           var _iterator, _step, array;
9758
9759           return regeneratorRuntime.wrap(function flatten$(_context) {
9760             while (1) {
9761               switch (_context.prev = _context.next) {
9762                 case 0:
9763                   _iterator = _createForOfIteratorHelper(arrays);
9764                   _context.prev = 1;
9765
9766                   _iterator.s();
9767
9768                 case 3:
9769                   if ((_step = _iterator.n()).done) {
9770                     _context.next = 8;
9771                     break;
9772                   }
9773
9774                   array = _step.value;
9775                   return _context.delegateYield(array, "t0", 6);
9776
9777                 case 6:
9778                   _context.next = 3;
9779                   break;
9780
9781                 case 8:
9782                   _context.next = 13;
9783                   break;
9784
9785                 case 10:
9786                   _context.prev = 10;
9787                   _context.t1 = _context["catch"](1);
9788
9789                   _iterator.e(_context.t1);
9790
9791                 case 13:
9792                   _context.prev = 13;
9793
9794                   _iterator.f();
9795
9796                   return _context.finish(13);
9797
9798                 case 16:
9799                 case "end":
9800                   return _context.stop();
9801               }
9802             }
9803           }, _marked$1, null, [[1, 10, 13, 16]]);
9804         }
9805
9806         function merge(arrays) {
9807           return Array.from(flatten(arrays));
9808         }
9809
9810         function range (start, stop, step) {
9811           start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
9812           var i = -1,
9813               n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
9814               range = new Array(n);
9815
9816           while (++i < n) {
9817             range[i] = start + i * step;
9818           }
9819
9820           return range;
9821         }
9822
9823         // `SameValue` abstract operation
9824         // https://tc39.es/ecma262/#sec-samevalue
9825         var sameValue = Object.is || function is(x, y) {
9826           // eslint-disable-next-line no-self-compare -- NaN check
9827           return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
9828         };
9829
9830         var $hypot = Math.hypot;
9831         var abs$1 = Math.abs;
9832         var sqrt = Math.sqrt;
9833
9834         // Chrome 77 bug
9835         // https://bugs.chromium.org/p/v8/issues/detail?id=9546
9836         var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity;
9837
9838         // `Math.hypot` method
9839         // https://tc39.es/ecma262/#sec-math.hypot
9840         _export({ target: 'Math', stat: true, forced: BUGGY }, {
9841           // eslint-disable-next-line no-unused-vars -- required for `.length`
9842           hypot: function hypot(value1, value2) {
9843             var sum = 0;
9844             var i = 0;
9845             var aLen = arguments.length;
9846             var larg = 0;
9847             var arg, div;
9848             while (i < aLen) {
9849               arg = abs$1(arguments[i++]);
9850               if (larg < arg) {
9851                 div = larg / arg;
9852                 sum = sum * div * div + 1;
9853                 larg = arg;
9854               } else if (arg > 0) {
9855                 div = arg / larg;
9856                 sum += div * div;
9857               } else sum += arg;
9858             }
9859             return larg === Infinity ? Infinity : larg * sqrt(sum);
9860           }
9861         });
9862
9863         // `Math.sign` method implementation
9864         // https://tc39.es/ecma262/#sec-math.sign
9865         var mathSign = Math.sign || function sign(x) {
9866           // eslint-disable-next-line no-self-compare -- NaN check
9867           return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
9868         };
9869
9870         // `Math.sign` method
9871         // https://tc39.es/ecma262/#sec-math.sign
9872         _export({ target: 'Math', stat: true }, {
9873           sign: mathSign
9874         });
9875
9876         var epsilon = 1e-6;
9877         var epsilon2 = 1e-12;
9878         var pi = Math.PI;
9879         var halfPi = pi / 2;
9880         var quarterPi = pi / 4;
9881         var tau = pi * 2;
9882         var degrees = 180 / pi;
9883         var radians = pi / 180;
9884         var abs$2 = Math.abs;
9885         var atan = Math.atan;
9886         var atan2 = Math.atan2;
9887         var cos = Math.cos;
9888         var exp = Math.exp;
9889         var hypot = Math.hypot;
9890         var log$1 = Math.log;
9891         var sin = Math.sin;
9892         var sign = Math.sign || function (x) {
9893           return x > 0 ? 1 : x < 0 ? -1 : 0;
9894         };
9895         var sqrt$1 = Math.sqrt;
9896         var tan = Math.tan;
9897         function acos(x) {
9898           return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
9899         }
9900         function asin(x) {
9901           return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
9902         }
9903
9904         function noop() {}
9905
9906         function streamGeometry(geometry, stream) {
9907           if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
9908             streamGeometryType[geometry.type](geometry, stream);
9909           }
9910         }
9911
9912         var streamObjectType = {
9913           Feature: function Feature(object, stream) {
9914             streamGeometry(object.geometry, stream);
9915           },
9916           FeatureCollection: function FeatureCollection(object, stream) {
9917             var features = object.features,
9918                 i = -1,
9919                 n = features.length;
9920
9921             while (++i < n) {
9922               streamGeometry(features[i].geometry, stream);
9923             }
9924           }
9925         };
9926         var streamGeometryType = {
9927           Sphere: function Sphere(object, stream) {
9928             stream.sphere();
9929           },
9930           Point: function Point(object, stream) {
9931             object = object.coordinates;
9932             stream.point(object[0], object[1], object[2]);
9933           },
9934           MultiPoint: function MultiPoint(object, stream) {
9935             var coordinates = object.coordinates,
9936                 i = -1,
9937                 n = coordinates.length;
9938
9939             while (++i < n) {
9940               object = coordinates[i], stream.point(object[0], object[1], object[2]);
9941             }
9942           },
9943           LineString: function LineString(object, stream) {
9944             streamLine(object.coordinates, stream, 0);
9945           },
9946           MultiLineString: function MultiLineString(object, stream) {
9947             var coordinates = object.coordinates,
9948                 i = -1,
9949                 n = coordinates.length;
9950
9951             while (++i < n) {
9952               streamLine(coordinates[i], stream, 0);
9953             }
9954           },
9955           Polygon: function Polygon(object, stream) {
9956             streamPolygon(object.coordinates, stream);
9957           },
9958           MultiPolygon: function MultiPolygon(object, stream) {
9959             var coordinates = object.coordinates,
9960                 i = -1,
9961                 n = coordinates.length;
9962
9963             while (++i < n) {
9964               streamPolygon(coordinates[i], stream);
9965             }
9966           },
9967           GeometryCollection: function GeometryCollection(object, stream) {
9968             var geometries = object.geometries,
9969                 i = -1,
9970                 n = geometries.length;
9971
9972             while (++i < n) {
9973               streamGeometry(geometries[i], stream);
9974             }
9975           }
9976         };
9977
9978         function streamLine(coordinates, stream, closed) {
9979           var i = -1,
9980               n = coordinates.length - closed,
9981               coordinate;
9982           stream.lineStart();
9983
9984           while (++i < n) {
9985             coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
9986           }
9987
9988           stream.lineEnd();
9989         }
9990
9991         function streamPolygon(coordinates, stream) {
9992           var i = -1,
9993               n = coordinates.length;
9994           stream.polygonStart();
9995
9996           while (++i < n) {
9997             streamLine(coordinates[i], stream, 1);
9998           }
9999
10000           stream.polygonEnd();
10001         }
10002
10003         function d3_geoStream (object, stream) {
10004           if (object && streamObjectType.hasOwnProperty(object.type)) {
10005             streamObjectType[object.type](object, stream);
10006           } else {
10007             streamGeometry(object, stream);
10008           }
10009         }
10010
10011         var areaRingSum = new Adder(); // hello?
10012
10013         var areaSum = new Adder(),
10014             lambda00,
10015             phi00,
10016             lambda0,
10017             cosPhi0,
10018             sinPhi0;
10019         var areaStream = {
10020           point: noop,
10021           lineStart: noop,
10022           lineEnd: noop,
10023           polygonStart: function polygonStart() {
10024             areaRingSum = new Adder();
10025             areaStream.lineStart = areaRingStart;
10026             areaStream.lineEnd = areaRingEnd;
10027           },
10028           polygonEnd: function polygonEnd() {
10029             var areaRing = +areaRingSum;
10030             areaSum.add(areaRing < 0 ? tau + areaRing : areaRing);
10031             this.lineStart = this.lineEnd = this.point = noop;
10032           },
10033           sphere: function sphere() {
10034             areaSum.add(tau);
10035           }
10036         };
10037
10038         function areaRingStart() {
10039           areaStream.point = areaPointFirst;
10040         }
10041
10042         function areaRingEnd() {
10043           areaPoint(lambda00, phi00);
10044         }
10045
10046         function areaPointFirst(lambda, phi) {
10047           areaStream.point = areaPoint;
10048           lambda00 = lambda, phi00 = phi;
10049           lambda *= radians, phi *= radians;
10050           lambda0 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
10051         }
10052
10053         function areaPoint(lambda, phi) {
10054           lambda *= radians, phi *= radians;
10055           phi = phi / 2 + quarterPi; // half the angular distance from south pole
10056           // Spherical excess E for a spherical triangle with vertices: south pole,
10057           // previous point, current point.  Uses a formula derived from Cagnoli’s
10058           // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
10059
10060           var dLambda = lambda - lambda0,
10061               sdLambda = dLambda >= 0 ? 1 : -1,
10062               adLambda = sdLambda * dLambda,
10063               cosPhi = cos(phi),
10064               sinPhi = sin(phi),
10065               k = sinPhi0 * sinPhi,
10066               u = cosPhi0 * cosPhi + k * cos(adLambda),
10067               v = k * sdLambda * sin(adLambda);
10068           areaRingSum.add(atan2(v, u)); // Advance the previous points.
10069
10070           lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
10071         }
10072
10073         function d3_geoArea (object) {
10074           areaSum = new Adder();
10075           d3_geoStream(object, areaStream);
10076           return areaSum * 2;
10077         }
10078
10079         function spherical(cartesian) {
10080           return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
10081         }
10082         function cartesian(spherical) {
10083           var lambda = spherical[0],
10084               phi = spherical[1],
10085               cosPhi = cos(phi);
10086           return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
10087         }
10088         function cartesianDot(a, b) {
10089           return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
10090         }
10091         function cartesianCross(a, b) {
10092           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]];
10093         } // TODO return a
10094
10095         function cartesianAddInPlace(a, b) {
10096           a[0] += b[0], a[1] += b[1], a[2] += b[2];
10097         }
10098         function cartesianScale(vector, k) {
10099           return [vector[0] * k, vector[1] * k, vector[2] * k];
10100         } // TODO return d
10101
10102         function cartesianNormalizeInPlace(d) {
10103           var l = sqrt$1(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
10104           d[0] /= l, d[1] /= l, d[2] /= l;
10105         }
10106
10107         var lambda0$1, phi0, lambda1, phi1, // bounds
10108         lambda2, // previous lambda-coordinate
10109         lambda00$1, phi00$1, // first point
10110         p0, // previous 3D point
10111         deltaSum, ranges, range$1;
10112         var boundsStream = {
10113           point: boundsPoint,
10114           lineStart: boundsLineStart,
10115           lineEnd: boundsLineEnd,
10116           polygonStart: function polygonStart() {
10117             boundsStream.point = boundsRingPoint;
10118             boundsStream.lineStart = boundsRingStart;
10119             boundsStream.lineEnd = boundsRingEnd;
10120             deltaSum = new Adder();
10121             areaStream.polygonStart();
10122           },
10123           polygonEnd: function polygonEnd() {
10124             areaStream.polygonEnd();
10125             boundsStream.point = boundsPoint;
10126             boundsStream.lineStart = boundsLineStart;
10127             boundsStream.lineEnd = boundsLineEnd;
10128             if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);else if (deltaSum > epsilon) phi1 = 90;else if (deltaSum < -epsilon) phi0 = -90;
10129             range$1[0] = lambda0$1, range$1[1] = lambda1;
10130           },
10131           sphere: function sphere() {
10132             lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
10133           }
10134         };
10135
10136         function boundsPoint(lambda, phi) {
10137           ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
10138           if (phi < phi0) phi0 = phi;
10139           if (phi > phi1) phi1 = phi;
10140         }
10141
10142         function linePoint(lambda, phi) {
10143           var p = cartesian([lambda * radians, phi * radians]);
10144
10145           if (p0) {
10146             var normal = cartesianCross(p0, p),
10147                 equatorial = [normal[1], -normal[0], 0],
10148                 inflection = cartesianCross(equatorial, normal);
10149             cartesianNormalizeInPlace(inflection);
10150             inflection = spherical(inflection);
10151             var delta = lambda - lambda2,
10152                 sign = delta > 0 ? 1 : -1,
10153                 lambdai = inflection[0] * degrees * sign,
10154                 phii,
10155                 antimeridian = abs$2(delta) > 180;
10156
10157             if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10158               phii = inflection[1] * degrees;
10159               if (phii > phi1) phi1 = phii;
10160             } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10161               phii = -inflection[1] * degrees;
10162               if (phii < phi0) phi0 = phii;
10163             } else {
10164               if (phi < phi0) phi0 = phi;
10165               if (phi > phi1) phi1 = phi;
10166             }
10167
10168             if (antimeridian) {
10169               if (lambda < lambda2) {
10170                 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10171               } else {
10172                 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10173               }
10174             } else {
10175               if (lambda1 >= lambda0$1) {
10176                 if (lambda < lambda0$1) lambda0$1 = lambda;
10177                 if (lambda > lambda1) lambda1 = lambda;
10178               } else {
10179                 if (lambda > lambda2) {
10180                   if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10181                 } else {
10182                   if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10183                 }
10184               }
10185             }
10186           } else {
10187             ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
10188           }
10189
10190           if (phi < phi0) phi0 = phi;
10191           if (phi > phi1) phi1 = phi;
10192           p0 = p, lambda2 = lambda;
10193         }
10194
10195         function boundsLineStart() {
10196           boundsStream.point = linePoint;
10197         }
10198
10199         function boundsLineEnd() {
10200           range$1[0] = lambda0$1, range$1[1] = lambda1;
10201           boundsStream.point = boundsPoint;
10202           p0 = null;
10203         }
10204
10205         function boundsRingPoint(lambda, phi) {
10206           if (p0) {
10207             var delta = lambda - lambda2;
10208             deltaSum.add(abs$2(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
10209           } else {
10210             lambda00$1 = lambda, phi00$1 = phi;
10211           }
10212
10213           areaStream.point(lambda, phi);
10214           linePoint(lambda, phi);
10215         }
10216
10217         function boundsRingStart() {
10218           areaStream.lineStart();
10219         }
10220
10221         function boundsRingEnd() {
10222           boundsRingPoint(lambda00$1, phi00$1);
10223           areaStream.lineEnd();
10224           if (abs$2(deltaSum) > epsilon) lambda0$1 = -(lambda1 = 180);
10225           range$1[0] = lambda0$1, range$1[1] = lambda1;
10226           p0 = null;
10227         } // Finds the left-right distance between two longitudes.
10228         // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
10229         // the distance between ±180° to be 360°.
10230
10231
10232         function angle(lambda0, lambda1) {
10233           return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
10234         }
10235
10236         function rangeCompare(a, b) {
10237           return a[0] - b[0];
10238         }
10239
10240         function rangeContains(range, x) {
10241           return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
10242         }
10243
10244         function d3_geoBounds (feature) {
10245           var i, n, a, b, merged, deltaMax, delta;
10246           phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
10247           ranges = [];
10248           d3_geoStream(feature, boundsStream); // First, sort ranges by their minimum longitudes.
10249
10250           if (n = ranges.length) {
10251             ranges.sort(rangeCompare); // Then, merge any ranges that overlap.
10252
10253             for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
10254               b = ranges[i];
10255
10256               if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
10257                 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
10258                 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
10259               } else {
10260                 merged.push(a = b);
10261               }
10262             } // Finally, find the largest gap between the merged ranges.
10263             // The final bounding box will be the inverse of this gap.
10264
10265
10266             for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
10267               b = merged[i];
10268               if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
10269             }
10270           }
10271
10272           ranges = range$1 = null;
10273           return lambda0$1 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0$1, phi0], [lambda1, phi1]];
10274         }
10275
10276         var W0, W1, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, lambda00$2, phi00$2, // first point
10277         x0, y0, z0; // previous point
10278
10279         var centroidStream = {
10280           sphere: noop,
10281           point: centroidPoint,
10282           lineStart: centroidLineStart,
10283           lineEnd: centroidLineEnd,
10284           polygonStart: function polygonStart() {
10285             centroidStream.lineStart = centroidRingStart;
10286             centroidStream.lineEnd = centroidRingEnd;
10287           },
10288           polygonEnd: function polygonEnd() {
10289             centroidStream.lineStart = centroidLineStart;
10290             centroidStream.lineEnd = centroidLineEnd;
10291           }
10292         }; // Arithmetic mean of Cartesian vectors.
10293
10294         function centroidPoint(lambda, phi) {
10295           lambda *= radians, phi *= radians;
10296           var cosPhi = cos(phi);
10297           centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
10298         }
10299
10300         function centroidPointCartesian(x, y, z) {
10301           ++W0;
10302           X0 += (x - X0) / W0;
10303           Y0 += (y - Y0) / W0;
10304           Z0 += (z - Z0) / W0;
10305         }
10306
10307         function centroidLineStart() {
10308           centroidStream.point = centroidLinePointFirst;
10309         }
10310
10311         function centroidLinePointFirst(lambda, phi) {
10312           lambda *= radians, phi *= radians;
10313           var cosPhi = cos(phi);
10314           x0 = cosPhi * cos(lambda);
10315           y0 = cosPhi * sin(lambda);
10316           z0 = sin(phi);
10317           centroidStream.point = centroidLinePoint;
10318           centroidPointCartesian(x0, y0, z0);
10319         }
10320
10321         function centroidLinePoint(lambda, phi) {
10322           lambda *= radians, phi *= radians;
10323           var cosPhi = cos(phi),
10324               x = cosPhi * cos(lambda),
10325               y = cosPhi * sin(lambda),
10326               z = sin(phi),
10327               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);
10328           W1 += w;
10329           X1 += w * (x0 + (x0 = x));
10330           Y1 += w * (y0 + (y0 = y));
10331           Z1 += w * (z0 + (z0 = z));
10332           centroidPointCartesian(x0, y0, z0);
10333         }
10334
10335         function centroidLineEnd() {
10336           centroidStream.point = centroidPoint;
10337         } // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
10338         // J. Applied Mechanics 42, 239 (1975).
10339
10340
10341         function centroidRingStart() {
10342           centroidStream.point = centroidRingPointFirst;
10343         }
10344
10345         function centroidRingEnd() {
10346           centroidRingPoint(lambda00$2, phi00$2);
10347           centroidStream.point = centroidPoint;
10348         }
10349
10350         function centroidRingPointFirst(lambda, phi) {
10351           lambda00$2 = lambda, phi00$2 = phi;
10352           lambda *= radians, phi *= radians;
10353           centroidStream.point = centroidRingPoint;
10354           var cosPhi = cos(phi);
10355           x0 = cosPhi * cos(lambda);
10356           y0 = cosPhi * sin(lambda);
10357           z0 = sin(phi);
10358           centroidPointCartesian(x0, y0, z0);
10359         }
10360
10361         function centroidRingPoint(lambda, phi) {
10362           lambda *= radians, phi *= radians;
10363           var cosPhi = cos(phi),
10364               x = cosPhi * cos(lambda),
10365               y = cosPhi * sin(lambda),
10366               z = sin(phi),
10367               cx = y0 * z - z0 * y,
10368               cy = z0 * x - x0 * z,
10369               cz = x0 * y - y0 * x,
10370               m = hypot(cx, cy, cz),
10371               w = asin(m),
10372               // line weight = angle
10373           v = m && -w / m; // area weight multiplier
10374
10375           X2.add(v * cx);
10376           Y2.add(v * cy);
10377           Z2.add(v * cz);
10378           W1 += w;
10379           X1 += w * (x0 + (x0 = x));
10380           Y1 += w * (y0 + (y0 = y));
10381           Z1 += w * (z0 + (z0 = z));
10382           centroidPointCartesian(x0, y0, z0);
10383         }
10384
10385         function d3_geoCentroid (object) {
10386           W0 = W1 = X0 = Y0 = Z0 = X1 = Y1 = Z1 = 0;
10387           X2 = new Adder();
10388           Y2 = new Adder();
10389           Z2 = new Adder();
10390           d3_geoStream(object, centroidStream);
10391           var x = +X2,
10392               y = +Y2,
10393               z = +Z2,
10394               m = hypot(x, y, z); // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
10395
10396           if (m < epsilon2) {
10397             x = X1, y = Y1, z = Z1; // If the feature has zero length, fall back to arithmetic mean of point vectors.
10398
10399             if (W1 < epsilon) x = X0, y = Y0, z = Z0;
10400             m = hypot(x, y, z); // If the feature still has an undefined ccentroid, then return.
10401
10402             if (m < epsilon2) return [NaN, NaN];
10403           }
10404
10405           return [atan2(y, x) * degrees, asin(z / m) * degrees];
10406         }
10407
10408         function compose (a, b) {
10409           function compose(x, y) {
10410             return x = a(x, y), b(x[0], x[1]);
10411           }
10412
10413           if (a.invert && b.invert) compose.invert = function (x, y) {
10414             return x = b.invert(x, y), x && a.invert(x[0], x[1]);
10415           };
10416           return compose;
10417         }
10418
10419         function rotationIdentity(lambda, phi) {
10420           return [abs$2(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
10421         }
10422
10423         rotationIdentity.invert = rotationIdentity;
10424         function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
10425           return (deltaLambda %= tau) ? deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda) : deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity;
10426         }
10427
10428         function forwardRotationLambda(deltaLambda) {
10429           return function (lambda, phi) {
10430             return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
10431           };
10432         }
10433
10434         function rotationLambda(deltaLambda) {
10435           var rotation = forwardRotationLambda(deltaLambda);
10436           rotation.invert = forwardRotationLambda(-deltaLambda);
10437           return rotation;
10438         }
10439
10440         function rotationPhiGamma(deltaPhi, deltaGamma) {
10441           var cosDeltaPhi = cos(deltaPhi),
10442               sinDeltaPhi = sin(deltaPhi),
10443               cosDeltaGamma = cos(deltaGamma),
10444               sinDeltaGamma = sin(deltaGamma);
10445
10446           function rotation(lambda, phi) {
10447             var cosPhi = cos(phi),
10448                 x = cos(lambda) * cosPhi,
10449                 y = sin(lambda) * cosPhi,
10450                 z = sin(phi),
10451                 k = z * cosDeltaPhi + x * sinDeltaPhi;
10452             return [atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin(k * cosDeltaGamma + y * sinDeltaGamma)];
10453           }
10454
10455           rotation.invert = function (lambda, phi) {
10456             var cosPhi = cos(phi),
10457                 x = cos(lambda) * cosPhi,
10458                 y = sin(lambda) * cosPhi,
10459                 z = sin(phi),
10460                 k = z * cosDeltaGamma - y * sinDeltaGamma;
10461             return [atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin(k * cosDeltaPhi - x * sinDeltaPhi)];
10462           };
10463
10464           return rotation;
10465         }
10466
10467         function rotation (rotate) {
10468           rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
10469
10470           function forward(coordinates) {
10471             coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
10472             return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
10473           }
10474
10475           forward.invert = function (coordinates) {
10476             coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
10477             return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
10478           };
10479
10480           return forward;
10481         }
10482
10483         function circleStream(stream, radius, delta, direction, t0, t1) {
10484           if (!delta) return;
10485           var cosRadius = cos(radius),
10486               sinRadius = sin(radius),
10487               step = direction * delta;
10488
10489           if (t0 == null) {
10490             t0 = radius + direction * tau;
10491             t1 = radius - step / 2;
10492           } else {
10493             t0 = circleRadius(cosRadius, t0);
10494             t1 = circleRadius(cosRadius, t1);
10495             if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
10496           }
10497
10498           for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
10499             point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
10500             stream.point(point[0], point[1]);
10501           }
10502         } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
10503
10504         function circleRadius(cosRadius, point) {
10505           point = cartesian(point), point[0] -= cosRadius;
10506           cartesianNormalizeInPlace(point);
10507           var radius = acos(-point[1]);
10508           return ((-point[2] < 0 ? -radius : radius) + tau - epsilon) % tau;
10509         }
10510
10511         function clipBuffer () {
10512           var lines = [],
10513               line;
10514           return {
10515             point: function point(x, y, m) {
10516               line.push([x, y, m]);
10517             },
10518             lineStart: function lineStart() {
10519               lines.push(line = []);
10520             },
10521             lineEnd: noop,
10522             rejoin: function rejoin() {
10523               if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
10524             },
10525             result: function result() {
10526               var result = lines;
10527               lines = [];
10528               line = null;
10529               return result;
10530             }
10531           };
10532         }
10533
10534         function pointEqual (a, b) {
10535           return abs$2(a[0] - b[0]) < epsilon && abs$2(a[1] - b[1]) < epsilon;
10536         }
10537
10538         function Intersection(point, points, other, entry) {
10539           this.x = point;
10540           this.z = points;
10541           this.o = other; // another intersection
10542
10543           this.e = entry; // is an entry?
10544
10545           this.v = false; // visited
10546
10547           this.n = this.p = null; // next & previous
10548         } // A generalized polygon clipping algorithm: given a polygon that has been cut
10549         // into its visible line segments, and rejoins the segments by interpolating
10550         // along the clip edge.
10551
10552
10553         function clipRejoin (segments, compareIntersection, startInside, interpolate, stream) {
10554           var subject = [],
10555               clip = [],
10556               i,
10557               n;
10558           segments.forEach(function (segment) {
10559             if ((n = segment.length - 1) <= 0) return;
10560             var n,
10561                 p0 = segment[0],
10562                 p1 = segment[n],
10563                 x;
10564
10565             if (pointEqual(p0, p1)) {
10566               if (!p0[2] && !p1[2]) {
10567                 stream.lineStart();
10568
10569                 for (i = 0; i < n; ++i) {
10570                   stream.point((p0 = segment[i])[0], p0[1]);
10571                 }
10572
10573                 stream.lineEnd();
10574                 return;
10575               } // handle degenerate cases by moving the point
10576
10577
10578               p1[0] += 2 * epsilon;
10579             }
10580
10581             subject.push(x = new Intersection(p0, segment, null, true));
10582             clip.push(x.o = new Intersection(p0, null, x, false));
10583             subject.push(x = new Intersection(p1, segment, null, false));
10584             clip.push(x.o = new Intersection(p1, null, x, true));
10585           });
10586           if (!subject.length) return;
10587           clip.sort(compareIntersection);
10588           link(subject);
10589           link(clip);
10590
10591           for (i = 0, n = clip.length; i < n; ++i) {
10592             clip[i].e = startInside = !startInside;
10593           }
10594
10595           var start = subject[0],
10596               points,
10597               point;
10598
10599           while (1) {
10600             // Find first unvisited intersection.
10601             var current = start,
10602                 isSubject = true;
10603
10604             while (current.v) {
10605               if ((current = current.n) === start) return;
10606             }
10607
10608             points = current.z;
10609             stream.lineStart();
10610
10611             do {
10612               current.v = current.o.v = true;
10613
10614               if (current.e) {
10615                 if (isSubject) {
10616                   for (i = 0, n = points.length; i < n; ++i) {
10617                     stream.point((point = points[i])[0], point[1]);
10618                   }
10619                 } else {
10620                   interpolate(current.x, current.n.x, 1, stream);
10621                 }
10622
10623                 current = current.n;
10624               } else {
10625                 if (isSubject) {
10626                   points = current.p.z;
10627
10628                   for (i = points.length - 1; i >= 0; --i) {
10629                     stream.point((point = points[i])[0], point[1]);
10630                   }
10631                 } else {
10632                   interpolate(current.x, current.p.x, -1, stream);
10633                 }
10634
10635                 current = current.p;
10636               }
10637
10638               current = current.o;
10639               points = current.z;
10640               isSubject = !isSubject;
10641             } while (!current.v);
10642
10643             stream.lineEnd();
10644           }
10645         }
10646
10647         function link(array) {
10648           if (!(n = array.length)) return;
10649           var n,
10650               i = 0,
10651               a = array[0],
10652               b;
10653
10654           while (++i < n) {
10655             a.n = b = array[i];
10656             b.p = a;
10657             a = b;
10658           }
10659
10660           a.n = b = array[0];
10661           b.p = a;
10662         }
10663
10664         function longitude(point) {
10665           if (abs$2(point[0]) <= pi) return point[0];else return sign(point[0]) * ((abs$2(point[0]) + pi) % tau - pi);
10666         }
10667
10668         function polygonContains (polygon, point) {
10669           var lambda = longitude(point),
10670               phi = point[1],
10671               sinPhi = sin(phi),
10672               normal = [sin(lambda), -cos(lambda), 0],
10673               angle = 0,
10674               winding = 0;
10675           var sum = new Adder();
10676           if (sinPhi === 1) phi = halfPi + epsilon;else if (sinPhi === -1) phi = -halfPi - epsilon;
10677
10678           for (var i = 0, n = polygon.length; i < n; ++i) {
10679             if (!(m = (ring = polygon[i]).length)) continue;
10680             var ring,
10681                 m,
10682                 point0 = ring[m - 1],
10683                 lambda0 = longitude(point0),
10684                 phi0 = point0[1] / 2 + quarterPi,
10685                 sinPhi0 = sin(phi0),
10686                 cosPhi0 = cos(phi0);
10687
10688             for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
10689               var point1 = ring[j],
10690                   lambda1 = longitude(point1),
10691                   phi1 = point1[1] / 2 + quarterPi,
10692                   sinPhi1 = sin(phi1),
10693                   cosPhi1 = cos(phi1),
10694                   delta = lambda1 - lambda0,
10695                   sign = delta >= 0 ? 1 : -1,
10696                   absDelta = sign * delta,
10697                   antimeridian = absDelta > pi,
10698                   k = sinPhi0 * sinPhi1;
10699               sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
10700               angle += antimeridian ? delta + sign * tau : delta; // Are the longitudes either side of the point’s meridian (lambda),
10701               // and are the latitudes smaller than the parallel (phi)?
10702
10703               if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
10704                 var arc = cartesianCross(cartesian(point0), cartesian(point1));
10705                 cartesianNormalizeInPlace(arc);
10706                 var intersection = cartesianCross(normal, arc);
10707                 cartesianNormalizeInPlace(intersection);
10708                 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
10709
10710                 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
10711                   winding += antimeridian ^ delta >= 0 ? 1 : -1;
10712                 }
10713               }
10714             }
10715           } // First, determine whether the South pole is inside or outside:
10716           //
10717           // It is inside if:
10718           // * the polygon winds around it in a clockwise direction.
10719           // * the polygon does not (cumulatively) wind around it, but has a negative
10720           //   (counter-clockwise) area.
10721           //
10722           // Second, count the (signed) number of times a segment crosses a lambda
10723           // from the point to the South pole.  If it is zero, then the point is the
10724           // same side as the South pole.
10725
10726
10727           return (angle < -epsilon || angle < epsilon && sum < -epsilon2) ^ winding & 1;
10728         }
10729
10730         function clip (pointVisible, clipLine, interpolate, start) {
10731           return function (sink) {
10732             var line = clipLine(sink),
10733                 ringBuffer = clipBuffer(),
10734                 ringSink = clipLine(ringBuffer),
10735                 polygonStarted = false,
10736                 polygon,
10737                 segments,
10738                 ring;
10739             var clip = {
10740               point: point,
10741               lineStart: lineStart,
10742               lineEnd: lineEnd,
10743               polygonStart: function polygonStart() {
10744                 clip.point = pointRing;
10745                 clip.lineStart = ringStart;
10746                 clip.lineEnd = ringEnd;
10747                 segments = [];
10748                 polygon = [];
10749               },
10750               polygonEnd: function polygonEnd() {
10751                 clip.point = point;
10752                 clip.lineStart = lineStart;
10753                 clip.lineEnd = lineEnd;
10754                 segments = merge(segments);
10755                 var startInside = polygonContains(polygon, start);
10756
10757                 if (segments.length) {
10758                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10759                   clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
10760                 } else if (startInside) {
10761                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10762                   sink.lineStart();
10763                   interpolate(null, null, 1, sink);
10764                   sink.lineEnd();
10765                 }
10766
10767                 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
10768                 segments = polygon = null;
10769               },
10770               sphere: function sphere() {
10771                 sink.polygonStart();
10772                 sink.lineStart();
10773                 interpolate(null, null, 1, sink);
10774                 sink.lineEnd();
10775                 sink.polygonEnd();
10776               }
10777             };
10778
10779             function point(lambda, phi) {
10780               if (pointVisible(lambda, phi)) sink.point(lambda, phi);
10781             }
10782
10783             function pointLine(lambda, phi) {
10784               line.point(lambda, phi);
10785             }
10786
10787             function lineStart() {
10788               clip.point = pointLine;
10789               line.lineStart();
10790             }
10791
10792             function lineEnd() {
10793               clip.point = point;
10794               line.lineEnd();
10795             }
10796
10797             function pointRing(lambda, phi) {
10798               ring.push([lambda, phi]);
10799               ringSink.point(lambda, phi);
10800             }
10801
10802             function ringStart() {
10803               ringSink.lineStart();
10804               ring = [];
10805             }
10806
10807             function ringEnd() {
10808               pointRing(ring[0][0], ring[0][1]);
10809               ringSink.lineEnd();
10810               var clean = ringSink.clean(),
10811                   ringSegments = ringBuffer.result(),
10812                   i,
10813                   n = ringSegments.length,
10814                   m,
10815                   segment,
10816                   point;
10817               ring.pop();
10818               polygon.push(ring);
10819               ring = null;
10820               if (!n) return; // No intersections.
10821
10822               if (clean & 1) {
10823                 segment = ringSegments[0];
10824
10825                 if ((m = segment.length - 1) > 0) {
10826                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10827                   sink.lineStart();
10828
10829                   for (i = 0; i < m; ++i) {
10830                     sink.point((point = segment[i])[0], point[1]);
10831                   }
10832
10833                   sink.lineEnd();
10834                 }
10835
10836                 return;
10837               } // Rejoin connected segments.
10838               // TODO reuse ringBuffer.rejoin()?
10839
10840
10841               if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
10842               segments.push(ringSegments.filter(validSegment));
10843             }
10844
10845             return clip;
10846           };
10847         }
10848
10849         function validSegment(segment) {
10850           return segment.length > 1;
10851         } // Intersections are sorted along the clip edge. For both antimeridian cutting
10852         // and circle clipping, the same comparison is used.
10853
10854
10855         function compareIntersection(a, b) {
10856           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]);
10857         }
10858
10859         var clipAntimeridian = clip(function () {
10860           return true;
10861         }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi, -halfPi]); // Takes a line and cuts into visible segments. Return values: 0 - there were
10862         // intersections or the line was empty; 1 - no intersections; 2 - there were
10863         // intersections, and the first and last segments should be rejoined.
10864
10865         function clipAntimeridianLine(stream) {
10866           var lambda0 = NaN,
10867               phi0 = NaN,
10868               sign0 = NaN,
10869               _clean; // no intersections
10870
10871
10872           return {
10873             lineStart: function lineStart() {
10874               stream.lineStart();
10875               _clean = 1;
10876             },
10877             point: function point(lambda1, phi1) {
10878               var sign1 = lambda1 > 0 ? pi : -pi,
10879                   delta = abs$2(lambda1 - lambda0);
10880
10881               if (abs$2(delta - pi) < epsilon) {
10882                 // line crosses a pole
10883                 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
10884                 stream.point(sign0, phi0);
10885                 stream.lineEnd();
10886                 stream.lineStart();
10887                 stream.point(sign1, phi0);
10888                 stream.point(lambda1, phi0);
10889                 _clean = 0;
10890               } else if (sign0 !== sign1 && delta >= pi) {
10891                 // line crosses antimeridian
10892                 if (abs$2(lambda0 - sign0) < epsilon) lambda0 -= sign0 * epsilon; // handle degeneracies
10893
10894                 if (abs$2(lambda1 - sign1) < epsilon) lambda1 -= sign1 * epsilon;
10895                 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
10896                 stream.point(sign0, phi0);
10897                 stream.lineEnd();
10898                 stream.lineStart();
10899                 stream.point(sign1, phi0);
10900                 _clean = 0;
10901               }
10902
10903               stream.point(lambda0 = lambda1, phi0 = phi1);
10904               sign0 = sign1;
10905             },
10906             lineEnd: function lineEnd() {
10907               stream.lineEnd();
10908               lambda0 = phi0 = NaN;
10909             },
10910             clean: function clean() {
10911               return 2 - _clean; // if intersections, rejoin first and last segments
10912             }
10913           };
10914         }
10915
10916         function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
10917           var cosPhi0,
10918               cosPhi1,
10919               sinLambda0Lambda1 = sin(lambda0 - lambda1);
10920           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;
10921         }
10922
10923         function clipAntimeridianInterpolate(from, to, direction, stream) {
10924           var phi;
10925
10926           if (from == null) {
10927             phi = direction * halfPi;
10928             stream.point(-pi, phi);
10929             stream.point(0, phi);
10930             stream.point(pi, phi);
10931             stream.point(pi, 0);
10932             stream.point(pi, -phi);
10933             stream.point(0, -phi);
10934             stream.point(-pi, -phi);
10935             stream.point(-pi, 0);
10936             stream.point(-pi, phi);
10937           } else if (abs$2(from[0] - to[0]) > epsilon) {
10938             var lambda = from[0] < to[0] ? pi : -pi;
10939             phi = direction * lambda / 2;
10940             stream.point(-lambda, phi);
10941             stream.point(0, phi);
10942             stream.point(lambda, phi);
10943           } else {
10944             stream.point(to[0], to[1]);
10945           }
10946         }
10947
10948         function clipCircle (radius) {
10949           var cr = cos(radius),
10950               delta = 6 * radians,
10951               smallRadius = cr > 0,
10952               notHemisphere = abs$2(cr) > epsilon; // TODO optimise for this common case
10953
10954           function interpolate(from, to, direction, stream) {
10955             circleStream(stream, radius, delta, direction, from, to);
10956           }
10957
10958           function visible(lambda, phi) {
10959             return cos(lambda) * cos(phi) > cr;
10960           } // Takes a line and cuts into visible segments. Return values used for polygon
10961           // clipping: 0 - there were intersections or the line was empty; 1 - no
10962           // intersections 2 - there were intersections, and the first and last segments
10963           // should be rejoined.
10964
10965
10966           function clipLine(stream) {
10967             var point0, // previous point
10968             c0, // code for previous point
10969             v0, // visibility of previous point
10970             v00, // visibility of first point
10971             _clean; // no intersections
10972
10973
10974             return {
10975               lineStart: function lineStart() {
10976                 v00 = v0 = false;
10977                 _clean = 1;
10978               },
10979               point: function point(lambda, phi) {
10980                 var point1 = [lambda, phi],
10981                     point2,
10982                     v = visible(lambda, phi),
10983                     c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
10984                 if (!point0 && (v00 = v0 = v)) stream.lineStart();
10985
10986                 if (v !== v0) {
10987                   point2 = intersect(point0, point1);
10988                   if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) point1[2] = 1;
10989                 }
10990
10991                 if (v !== v0) {
10992                   _clean = 0;
10993
10994                   if (v) {
10995                     // outside going in
10996                     stream.lineStart();
10997                     point2 = intersect(point1, point0);
10998                     stream.point(point2[0], point2[1]);
10999                   } else {
11000                     // inside going out
11001                     point2 = intersect(point0, point1);
11002                     stream.point(point2[0], point2[1], 2);
11003                     stream.lineEnd();
11004                   }
11005
11006                   point0 = point2;
11007                 } else if (notHemisphere && point0 && smallRadius ^ v) {
11008                   var t; // If the codes for two points are different, or are both zero,
11009                   // and there this segment intersects with the small circle.
11010
11011                   if (!(c & c0) && (t = intersect(point1, point0, true))) {
11012                     _clean = 0;
11013
11014                     if (smallRadius) {
11015                       stream.lineStart();
11016                       stream.point(t[0][0], t[0][1]);
11017                       stream.point(t[1][0], t[1][1]);
11018                       stream.lineEnd();
11019                     } else {
11020                       stream.point(t[1][0], t[1][1]);
11021                       stream.lineEnd();
11022                       stream.lineStart();
11023                       stream.point(t[0][0], t[0][1], 3);
11024                     }
11025                   }
11026                 }
11027
11028                 if (v && (!point0 || !pointEqual(point0, point1))) {
11029                   stream.point(point1[0], point1[1]);
11030                 }
11031
11032                 point0 = point1, v0 = v, c0 = c;
11033               },
11034               lineEnd: function lineEnd() {
11035                 if (v0) stream.lineEnd();
11036                 point0 = null;
11037               },
11038               // Rejoin first and last segments if there were intersections and the first
11039               // and last points were visible.
11040               clean: function clean() {
11041                 return _clean | (v00 && v0) << 1;
11042               }
11043             };
11044           } // Intersects the great circle between a and b with the clip circle.
11045
11046
11047           function intersect(a, b, two) {
11048             var pa = cartesian(a),
11049                 pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2.
11050             // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
11051
11052             var n1 = [1, 0, 0],
11053                 // normal
11054             n2 = cartesianCross(pa, pb),
11055                 n2n2 = cartesianDot(n2, n2),
11056                 n1n2 = n2[0],
11057                 // cartesianDot(n1, n2),
11058             determinant = n2n2 - n1n2 * n1n2; // Two polar points.
11059
11060             if (!determinant) return !two && a;
11061             var c1 = cr * n2n2 / determinant,
11062                 c2 = -cr * n1n2 / determinant,
11063                 n1xn2 = cartesianCross(n1, n2),
11064                 A = cartesianScale(n1, c1),
11065                 B = cartesianScale(n2, c2);
11066             cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1.
11067
11068             var u = n1xn2,
11069                 w = cartesianDot(A, u),
11070                 uu = cartesianDot(u, u),
11071                 t2 = w * w - uu * (cartesianDot(A, A) - 1);
11072             if (t2 < 0) return;
11073             var t = sqrt$1(t2),
11074                 q = cartesianScale(u, (-w - t) / uu);
11075             cartesianAddInPlace(q, A);
11076             q = spherical(q);
11077             if (!two) return q; // Two intersection points.
11078
11079             var lambda0 = a[0],
11080                 lambda1 = b[0],
11081                 phi0 = a[1],
11082                 phi1 = b[1],
11083                 z;
11084             if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
11085             var delta = lambda1 - lambda0,
11086                 polar = abs$2(delta - pi) < epsilon,
11087                 meridian = polar || delta < epsilon;
11088             if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b.
11089
11090             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)) {
11091               var q1 = cartesianScale(u, (-w + t) / uu);
11092               cartesianAddInPlace(q1, A);
11093               return [q, spherical(q1)];
11094             }
11095           } // Generates a 4-bit vector representing the location of a point relative to
11096           // the small circle's bounding box.
11097
11098
11099           function code(lambda, phi) {
11100             var r = smallRadius ? radius : pi - radius,
11101                 code = 0;
11102             if (lambda < -r) code |= 1; // left
11103             else if (lambda > r) code |= 2; // right
11104
11105             if (phi < -r) code |= 4; // below
11106             else if (phi > r) code |= 8; // above
11107
11108             return code;
11109           }
11110
11111           return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
11112         }
11113
11114         function clipLine (a, b, x0, y0, x1, y1) {
11115           var ax = a[0],
11116               ay = a[1],
11117               bx = b[0],
11118               by = b[1],
11119               t0 = 0,
11120               t1 = 1,
11121               dx = bx - ax,
11122               dy = by - ay,
11123               r;
11124           r = x0 - ax;
11125           if (!dx && r > 0) return;
11126           r /= dx;
11127
11128           if (dx < 0) {
11129             if (r < t0) return;
11130             if (r < t1) t1 = r;
11131           } else if (dx > 0) {
11132             if (r > t1) return;
11133             if (r > t0) t0 = r;
11134           }
11135
11136           r = x1 - ax;
11137           if (!dx && r < 0) return;
11138           r /= dx;
11139
11140           if (dx < 0) {
11141             if (r > t1) return;
11142             if (r > t0) t0 = r;
11143           } else if (dx > 0) {
11144             if (r < t0) return;
11145             if (r < t1) t1 = r;
11146           }
11147
11148           r = y0 - ay;
11149           if (!dy && r > 0) return;
11150           r /= dy;
11151
11152           if (dy < 0) {
11153             if (r < t0) return;
11154             if (r < t1) t1 = r;
11155           } else if (dy > 0) {
11156             if (r > t1) return;
11157             if (r > t0) t0 = r;
11158           }
11159
11160           r = y1 - ay;
11161           if (!dy && r < 0) return;
11162           r /= dy;
11163
11164           if (dy < 0) {
11165             if (r > t1) return;
11166             if (r > t0) t0 = r;
11167           } else if (dy > 0) {
11168             if (r < t0) return;
11169             if (r < t1) t1 = r;
11170           }
11171
11172           if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
11173           if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
11174           return true;
11175         }
11176
11177         var clipMax = 1e9,
11178             clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check?
11179         // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
11180
11181         function clipRectangle(x0, y0, x1, y1) {
11182           function visible(x, y) {
11183             return x0 <= x && x <= x1 && y0 <= y && y <= y1;
11184           }
11185
11186           function interpolate(from, to, direction, stream) {
11187             var a = 0,
11188                 a1 = 0;
11189
11190             if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
11191               do {
11192                 stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
11193               } while ((a = (a + direction + 4) % 4) !== a1);
11194             } else {
11195               stream.point(to[0], to[1]);
11196             }
11197           }
11198
11199           function corner(p, direction) {
11200             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
11201           }
11202
11203           function compareIntersection(a, b) {
11204             return comparePoint(a.x, b.x);
11205           }
11206
11207           function comparePoint(a, b) {
11208             var ca = corner(a, 1),
11209                 cb = corner(b, 1);
11210             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];
11211           }
11212
11213           return function (stream) {
11214             var activeStream = stream,
11215                 bufferStream = clipBuffer(),
11216                 segments,
11217                 polygon,
11218                 ring,
11219                 x__,
11220                 y__,
11221                 v__,
11222                 // first point
11223             x_,
11224                 y_,
11225                 v_,
11226                 // previous point
11227             first,
11228                 clean;
11229             var clipStream = {
11230               point: point,
11231               lineStart: lineStart,
11232               lineEnd: lineEnd,
11233               polygonStart: polygonStart,
11234               polygonEnd: polygonEnd
11235             };
11236
11237             function point(x, y) {
11238               if (visible(x, y)) activeStream.point(x, y);
11239             }
11240
11241             function polygonInside() {
11242               var winding = 0;
11243
11244               for (var i = 0, n = polygon.length; i < n; ++i) {
11245                 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
11246                   a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
11247
11248                   if (a1 <= y1) {
11249                     if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding;
11250                   } else {
11251                     if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding;
11252                   }
11253                 }
11254               }
11255
11256               return winding;
11257             } // Buffer geometry within a polygon and then clip it en masse.
11258
11259
11260             function polygonStart() {
11261               activeStream = bufferStream, segments = [], polygon = [], clean = true;
11262             }
11263
11264             function polygonEnd() {
11265               var startInside = polygonInside(),
11266                   cleanInside = clean && startInside,
11267                   visible = (segments = merge(segments)).length;
11268
11269               if (cleanInside || visible) {
11270                 stream.polygonStart();
11271
11272                 if (cleanInside) {
11273                   stream.lineStart();
11274                   interpolate(null, null, 1, stream);
11275                   stream.lineEnd();
11276                 }
11277
11278                 if (visible) {
11279                   clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
11280                 }
11281
11282                 stream.polygonEnd();
11283               }
11284
11285               activeStream = stream, segments = polygon = ring = null;
11286             }
11287
11288             function lineStart() {
11289               clipStream.point = linePoint;
11290               if (polygon) polygon.push(ring = []);
11291               first = true;
11292               v_ = false;
11293               x_ = y_ = NaN;
11294             } // TODO rather than special-case polygons, simply handle them separately.
11295             // Ideally, coincident intersection points should be jittered to avoid
11296             // clipping issues.
11297
11298
11299             function lineEnd() {
11300               if (segments) {
11301                 linePoint(x__, y__);
11302                 if (v__ && v_) bufferStream.rejoin();
11303                 segments.push(bufferStream.result());
11304               }
11305
11306               clipStream.point = point;
11307               if (v_) activeStream.lineEnd();
11308             }
11309
11310             function linePoint(x, y) {
11311               var v = visible(x, y);
11312               if (polygon) ring.push([x, y]);
11313
11314               if (first) {
11315                 x__ = x, y__ = y, v__ = v;
11316                 first = false;
11317
11318                 if (v) {
11319                   activeStream.lineStart();
11320                   activeStream.point(x, y);
11321                 }
11322               } else {
11323                 if (v && v_) activeStream.point(x, y);else {
11324                   var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
11325                       b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
11326
11327                   if (clipLine(a, b, x0, y0, x1, y1)) {
11328                     if (!v_) {
11329                       activeStream.lineStart();
11330                       activeStream.point(a[0], a[1]);
11331                     }
11332
11333                     activeStream.point(b[0], b[1]);
11334                     if (!v) activeStream.lineEnd();
11335                     clean = false;
11336                   } else if (v) {
11337                     activeStream.lineStart();
11338                     activeStream.point(x, y);
11339                     clean = false;
11340                   }
11341                 }
11342               }
11343
11344               x_ = x, y_ = y, v_ = v;
11345             }
11346
11347             return clipStream;
11348           };
11349         }
11350
11351         var lengthSum, lambda0$2, sinPhi0$1, cosPhi0$1;
11352         var lengthStream = {
11353           sphere: noop,
11354           point: noop,
11355           lineStart: lengthLineStart,
11356           lineEnd: noop,
11357           polygonStart: noop,
11358           polygonEnd: noop
11359         };
11360
11361         function lengthLineStart() {
11362           lengthStream.point = lengthPointFirst;
11363           lengthStream.lineEnd = lengthLineEnd;
11364         }
11365
11366         function lengthLineEnd() {
11367           lengthStream.point = lengthStream.lineEnd = noop;
11368         }
11369
11370         function lengthPointFirst(lambda, phi) {
11371           lambda *= radians, phi *= radians;
11372           lambda0$2 = lambda, sinPhi0$1 = sin(phi), cosPhi0$1 = cos(phi);
11373           lengthStream.point = lengthPoint;
11374         }
11375
11376         function lengthPoint(lambda, phi) {
11377           lambda *= radians, phi *= radians;
11378           var sinPhi = sin(phi),
11379               cosPhi = cos(phi),
11380               delta = abs$2(lambda - lambda0$2),
11381               cosDelta = cos(delta),
11382               sinDelta = sin(delta),
11383               x = cosPhi * sinDelta,
11384               y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
11385               z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
11386           lengthSum.add(atan2(sqrt$1(x * x + y * y), z));
11387           lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
11388         }
11389
11390         function d3_geoLength (object) {
11391           lengthSum = new Adder();
11392           d3_geoStream(object, lengthStream);
11393           return +lengthSum;
11394         }
11395
11396         var identity = (function (x) {
11397           return x;
11398         });
11399
11400         var areaSum$1 = new Adder(),
11401             areaRingSum$1 = new Adder(),
11402             x00,
11403             y00,
11404             x0$1,
11405             y0$1;
11406         var areaStream$1 = {
11407           point: noop,
11408           lineStart: noop,
11409           lineEnd: noop,
11410           polygonStart: function polygonStart() {
11411             areaStream$1.lineStart = areaRingStart$1;
11412             areaStream$1.lineEnd = areaRingEnd$1;
11413           },
11414           polygonEnd: function polygonEnd() {
11415             areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop;
11416             areaSum$1.add(abs$2(areaRingSum$1));
11417             areaRingSum$1 = new Adder();
11418           },
11419           result: function result() {
11420             var area = areaSum$1 / 2;
11421             areaSum$1 = new Adder();
11422             return area;
11423           }
11424         };
11425
11426         function areaRingStart$1() {
11427           areaStream$1.point = areaPointFirst$1;
11428         }
11429
11430         function areaPointFirst$1(x, y) {
11431           areaStream$1.point = areaPoint$1;
11432           x00 = x0$1 = x, y00 = y0$1 = y;
11433         }
11434
11435         function areaPoint$1(x, y) {
11436           areaRingSum$1.add(y0$1 * x - x0$1 * y);
11437           x0$1 = x, y0$1 = y;
11438         }
11439
11440         function areaRingEnd$1() {
11441           areaPoint$1(x00, y00);
11442         }
11443
11444         var x0$2 = Infinity,
11445             y0$2 = x0$2,
11446             x1 = -x0$2,
11447             y1 = x1;
11448         var boundsStream$1 = {
11449           point: boundsPoint$1,
11450           lineStart: noop,
11451           lineEnd: noop,
11452           polygonStart: noop,
11453           polygonEnd: noop,
11454           result: function result() {
11455             var bounds = [[x0$2, y0$2], [x1, y1]];
11456             x1 = y1 = -(y0$2 = x0$2 = Infinity);
11457             return bounds;
11458           }
11459         };
11460
11461         function boundsPoint$1(x, y) {
11462           if (x < x0$2) x0$2 = x;
11463           if (x > x1) x1 = x;
11464           if (y < y0$2) y0$2 = y;
11465           if (y > y1) y1 = y;
11466         }
11467
11468         var X0$1 = 0,
11469             Y0$1 = 0,
11470             Z0$1 = 0,
11471             X1$1 = 0,
11472             Y1$1 = 0,
11473             Z1$1 = 0,
11474             X2$1 = 0,
11475             Y2$1 = 0,
11476             Z2$1 = 0,
11477             x00$1,
11478             y00$1,
11479             x0$3,
11480             y0$3;
11481         var centroidStream$1 = {
11482           point: centroidPoint$1,
11483           lineStart: centroidLineStart$1,
11484           lineEnd: centroidLineEnd$1,
11485           polygonStart: function polygonStart() {
11486             centroidStream$1.lineStart = centroidRingStart$1;
11487             centroidStream$1.lineEnd = centroidRingEnd$1;
11488           },
11489           polygonEnd: function polygonEnd() {
11490             centroidStream$1.point = centroidPoint$1;
11491             centroidStream$1.lineStart = centroidLineStart$1;
11492             centroidStream$1.lineEnd = centroidLineEnd$1;
11493           },
11494           result: function result() {
11495             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];
11496             X0$1 = Y0$1 = Z0$1 = X1$1 = Y1$1 = Z1$1 = X2$1 = Y2$1 = Z2$1 = 0;
11497             return centroid;
11498           }
11499         };
11500
11501         function centroidPoint$1(x, y) {
11502           X0$1 += x;
11503           Y0$1 += y;
11504           ++Z0$1;
11505         }
11506
11507         function centroidLineStart$1() {
11508           centroidStream$1.point = centroidPointFirstLine;
11509         }
11510
11511         function centroidPointFirstLine(x, y) {
11512           centroidStream$1.point = centroidPointLine;
11513           centroidPoint$1(x0$3 = x, y0$3 = y);
11514         }
11515
11516         function centroidPointLine(x, y) {
11517           var dx = x - x0$3,
11518               dy = y - y0$3,
11519               z = sqrt$1(dx * dx + dy * dy);
11520           X1$1 += z * (x0$3 + x) / 2;
11521           Y1$1 += z * (y0$3 + y) / 2;
11522           Z1$1 += z;
11523           centroidPoint$1(x0$3 = x, y0$3 = y);
11524         }
11525
11526         function centroidLineEnd$1() {
11527           centroidStream$1.point = centroidPoint$1;
11528         }
11529
11530         function centroidRingStart$1() {
11531           centroidStream$1.point = centroidPointFirstRing;
11532         }
11533
11534         function centroidRingEnd$1() {
11535           centroidPointRing(x00$1, y00$1);
11536         }
11537
11538         function centroidPointFirstRing(x, y) {
11539           centroidStream$1.point = centroidPointRing;
11540           centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
11541         }
11542
11543         function centroidPointRing(x, y) {
11544           var dx = x - x0$3,
11545               dy = y - y0$3,
11546               z = sqrt$1(dx * dx + dy * dy);
11547           X1$1 += z * (x0$3 + x) / 2;
11548           Y1$1 += z * (y0$3 + y) / 2;
11549           Z1$1 += z;
11550           z = y0$3 * x - x0$3 * y;
11551           X2$1 += z * (x0$3 + x);
11552           Y2$1 += z * (y0$3 + y);
11553           Z2$1 += z * 3;
11554           centroidPoint$1(x0$3 = x, y0$3 = y);
11555         }
11556
11557         function PathContext(context) {
11558           this._context = context;
11559         }
11560         PathContext.prototype = {
11561           _radius: 4.5,
11562           pointRadius: function pointRadius(_) {
11563             return this._radius = _, this;
11564           },
11565           polygonStart: function polygonStart() {
11566             this._line = 0;
11567           },
11568           polygonEnd: function polygonEnd() {
11569             this._line = NaN;
11570           },
11571           lineStart: function lineStart() {
11572             this._point = 0;
11573           },
11574           lineEnd: function lineEnd() {
11575             if (this._line === 0) this._context.closePath();
11576             this._point = NaN;
11577           },
11578           point: function point(x, y) {
11579             switch (this._point) {
11580               case 0:
11581                 {
11582                   this._context.moveTo(x, y);
11583
11584                   this._point = 1;
11585                   break;
11586                 }
11587
11588               case 1:
11589                 {
11590                   this._context.lineTo(x, y);
11591
11592                   break;
11593                 }
11594
11595               default:
11596                 {
11597                   this._context.moveTo(x + this._radius, y);
11598
11599                   this._context.arc(x, y, this._radius, 0, tau);
11600
11601                   break;
11602                 }
11603             }
11604           },
11605           result: noop
11606         };
11607
11608         var lengthSum$1 = new Adder(),
11609             lengthRing,
11610             x00$2,
11611             y00$2,
11612             x0$4,
11613             y0$4;
11614         var lengthStream$1 = {
11615           point: noop,
11616           lineStart: function lineStart() {
11617             lengthStream$1.point = lengthPointFirst$1;
11618           },
11619           lineEnd: function lineEnd() {
11620             if (lengthRing) lengthPoint$1(x00$2, y00$2);
11621             lengthStream$1.point = noop;
11622           },
11623           polygonStart: function polygonStart() {
11624             lengthRing = true;
11625           },
11626           polygonEnd: function polygonEnd() {
11627             lengthRing = null;
11628           },
11629           result: function result() {
11630             var length = +lengthSum$1;
11631             lengthSum$1 = new Adder();
11632             return length;
11633           }
11634         };
11635
11636         function lengthPointFirst$1(x, y) {
11637           lengthStream$1.point = lengthPoint$1;
11638           x00$2 = x0$4 = x, y00$2 = y0$4 = y;
11639         }
11640
11641         function lengthPoint$1(x, y) {
11642           x0$4 -= x, y0$4 -= y;
11643           lengthSum$1.add(sqrt$1(x0$4 * x0$4 + y0$4 * y0$4));
11644           x0$4 = x, y0$4 = y;
11645         }
11646
11647         function PathString() {
11648           this._string = [];
11649         }
11650         PathString.prototype = {
11651           _radius: 4.5,
11652           _circle: circle(4.5),
11653           pointRadius: function pointRadius(_) {
11654             if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
11655             return this;
11656           },
11657           polygonStart: function polygonStart() {
11658             this._line = 0;
11659           },
11660           polygonEnd: function polygonEnd() {
11661             this._line = NaN;
11662           },
11663           lineStart: function lineStart() {
11664             this._point = 0;
11665           },
11666           lineEnd: function lineEnd() {
11667             if (this._line === 0) this._string.push("Z");
11668             this._point = NaN;
11669           },
11670           point: function point(x, y) {
11671             switch (this._point) {
11672               case 0:
11673                 {
11674                   this._string.push("M", x, ",", y);
11675
11676                   this._point = 1;
11677                   break;
11678                 }
11679
11680               case 1:
11681                 {
11682                   this._string.push("L", x, ",", y);
11683
11684                   break;
11685                 }
11686
11687               default:
11688                 {
11689                   if (this._circle == null) this._circle = circle(this._radius);
11690
11691                   this._string.push("M", x, ",", y, this._circle);
11692
11693                   break;
11694                 }
11695             }
11696           },
11697           result: function result() {
11698             if (this._string.length) {
11699               var result = this._string.join("");
11700
11701               this._string = [];
11702               return result;
11703             } else {
11704               return null;
11705             }
11706           }
11707         };
11708
11709         function circle(radius) {
11710           return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
11711         }
11712
11713         function d3_geoPath (projection, context) {
11714           var pointRadius = 4.5,
11715               projectionStream,
11716               contextStream;
11717
11718           function path(object) {
11719             if (object) {
11720               if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
11721               d3_geoStream(object, projectionStream(contextStream));
11722             }
11723
11724             return contextStream.result();
11725           }
11726
11727           path.area = function (object) {
11728             d3_geoStream(object, projectionStream(areaStream$1));
11729             return areaStream$1.result();
11730           };
11731
11732           path.measure = function (object) {
11733             d3_geoStream(object, projectionStream(lengthStream$1));
11734             return lengthStream$1.result();
11735           };
11736
11737           path.bounds = function (object) {
11738             d3_geoStream(object, projectionStream(boundsStream$1));
11739             return boundsStream$1.result();
11740           };
11741
11742           path.centroid = function (object) {
11743             d3_geoStream(object, projectionStream(centroidStream$1));
11744             return centroidStream$1.result();
11745           };
11746
11747           path.projection = function (_) {
11748             return arguments.length ? (projectionStream = _ == null ? (projection = null, identity) : (projection = _).stream, path) : projection;
11749           };
11750
11751           path.context = function (_) {
11752             if (!arguments.length) return context;
11753             contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
11754             if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
11755             return path;
11756           };
11757
11758           path.pointRadius = function (_) {
11759             if (!arguments.length) return pointRadius;
11760             pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
11761             return path;
11762           };
11763
11764           return path.projection(projection).context(context);
11765         }
11766
11767         function d3_geoTransform (methods) {
11768           return {
11769             stream: transformer(methods)
11770           };
11771         }
11772         function transformer(methods) {
11773           return function (stream) {
11774             var s = new TransformStream();
11775
11776             for (var key in methods) {
11777               s[key] = methods[key];
11778             }
11779
11780             s.stream = stream;
11781             return s;
11782           };
11783         }
11784
11785         function TransformStream() {}
11786
11787         TransformStream.prototype = {
11788           constructor: TransformStream,
11789           point: function point(x, y) {
11790             this.stream.point(x, y);
11791           },
11792           sphere: function sphere() {
11793             this.stream.sphere();
11794           },
11795           lineStart: function lineStart() {
11796             this.stream.lineStart();
11797           },
11798           lineEnd: function lineEnd() {
11799             this.stream.lineEnd();
11800           },
11801           polygonStart: function polygonStart() {
11802             this.stream.polygonStart();
11803           },
11804           polygonEnd: function polygonEnd() {
11805             this.stream.polygonEnd();
11806           }
11807         };
11808
11809         function fit(projection, fitBounds, object) {
11810           var clip = projection.clipExtent && projection.clipExtent();
11811           projection.scale(150).translate([0, 0]);
11812           if (clip != null) projection.clipExtent(null);
11813           d3_geoStream(object, projection.stream(boundsStream$1));
11814           fitBounds(boundsStream$1.result());
11815           if (clip != null) projection.clipExtent(clip);
11816           return projection;
11817         }
11818
11819         function fitExtent(projection, extent, object) {
11820           return fit(projection, function (b) {
11821             var w = extent[1][0] - extent[0][0],
11822                 h = extent[1][1] - extent[0][1],
11823                 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
11824                 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
11825                 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
11826             projection.scale(150 * k).translate([x, y]);
11827           }, object);
11828         }
11829         function fitSize(projection, size, object) {
11830           return fitExtent(projection, [[0, 0], size], object);
11831         }
11832         function fitWidth(projection, width, object) {
11833           return fit(projection, function (b) {
11834             var w = +width,
11835                 k = w / (b[1][0] - b[0][0]),
11836                 x = (w - k * (b[1][0] + b[0][0])) / 2,
11837                 y = -k * b[0][1];
11838             projection.scale(150 * k).translate([x, y]);
11839           }, object);
11840         }
11841         function fitHeight(projection, height, object) {
11842           return fit(projection, function (b) {
11843             var h = +height,
11844                 k = h / (b[1][1] - b[0][1]),
11845                 x = -k * b[0][0],
11846                 y = (h - k * (b[1][1] + b[0][1])) / 2;
11847             projection.scale(150 * k).translate([x, y]);
11848           }, object);
11849         }
11850
11851         var maxDepth = 16,
11852             // maximum depth of subdivision
11853         cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
11854
11855         function resample (project, delta2) {
11856           return +delta2 ? resample$1(project, delta2) : resampleNone(project);
11857         }
11858
11859         function resampleNone(project) {
11860           return transformer({
11861             point: function point(x, y) {
11862               x = project(x, y);
11863               this.stream.point(x[0], x[1]);
11864             }
11865           });
11866         }
11867
11868         function resample$1(project, delta2) {
11869           function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
11870             var dx = x1 - x0,
11871                 dy = y1 - y0,
11872                 d2 = dx * dx + dy * dy;
11873
11874             if (d2 > 4 * delta2 && depth--) {
11875               var a = a0 + a1,
11876                   b = b0 + b1,
11877                   c = c0 + c1,
11878                   m = sqrt$1(a * a + b * b + c * c),
11879                   phi2 = asin(c /= m),
11880                   lambda2 = abs$2(abs$2(c) - 1) < epsilon || abs$2(lambda0 - lambda1) < epsilon ? (lambda0 + lambda1) / 2 : atan2(b, a),
11881                   p = project(lambda2, phi2),
11882                   x2 = p[0],
11883                   y2 = p[1],
11884                   dx2 = x2 - x0,
11885                   dy2 = y2 - y0,
11886                   dz = dy * dx2 - dx * dy2;
11887
11888               if (dz * dz / d2 > delta2 // perpendicular projected distance
11889               || abs$2((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
11890               || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
11891                 // angular distance
11892                 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
11893                 stream.point(x2, y2);
11894                 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
11895               }
11896             }
11897           }
11898
11899           return function (stream) {
11900             var lambda00, x00, y00, a00, b00, c00, // first point
11901             lambda0, x0, y0, a0, b0, c0; // previous point
11902
11903             var resampleStream = {
11904               point: point,
11905               lineStart: lineStart,
11906               lineEnd: lineEnd,
11907               polygonStart: function polygonStart() {
11908                 stream.polygonStart();
11909                 resampleStream.lineStart = ringStart;
11910               },
11911               polygonEnd: function polygonEnd() {
11912                 stream.polygonEnd();
11913                 resampleStream.lineStart = lineStart;
11914               }
11915             };
11916
11917             function point(x, y) {
11918               x = project(x, y);
11919               stream.point(x[0], x[1]);
11920             }
11921
11922             function lineStart() {
11923               x0 = NaN;
11924               resampleStream.point = linePoint;
11925               stream.lineStart();
11926             }
11927
11928             function linePoint(lambda, phi) {
11929               var c = cartesian([lambda, phi]),
11930                   p = project(lambda, phi);
11931               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);
11932               stream.point(x0, y0);
11933             }
11934
11935             function lineEnd() {
11936               resampleStream.point = point;
11937               stream.lineEnd();
11938             }
11939
11940             function ringStart() {
11941               lineStart();
11942               resampleStream.point = ringPoint;
11943               resampleStream.lineEnd = ringEnd;
11944             }
11945
11946             function ringPoint(lambda, phi) {
11947               linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
11948               resampleStream.point = linePoint;
11949             }
11950
11951             function ringEnd() {
11952               resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
11953               resampleStream.lineEnd = lineEnd;
11954               lineEnd();
11955             }
11956
11957             return resampleStream;
11958           };
11959         }
11960
11961         var transformRadians = transformer({
11962           point: function point(x, y) {
11963             this.stream.point(x * radians, y * radians);
11964           }
11965         });
11966
11967         function transformRotate(rotate) {
11968           return transformer({
11969             point: function point(x, y) {
11970               var r = rotate(x, y);
11971               return this.stream.point(r[0], r[1]);
11972             }
11973           });
11974         }
11975
11976         function scaleTranslate(k, dx, dy, sx, sy) {
11977           function transform(x, y) {
11978             x *= sx;
11979             y *= sy;
11980             return [dx + k * x, dy - k * y];
11981           }
11982
11983           transform.invert = function (x, y) {
11984             return [(x - dx) / k * sx, (dy - y) / k * sy];
11985           };
11986
11987           return transform;
11988         }
11989
11990         function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
11991           if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
11992           var cosAlpha = cos(alpha),
11993               sinAlpha = sin(alpha),
11994               a = cosAlpha * k,
11995               b = sinAlpha * k,
11996               ai = cosAlpha / k,
11997               bi = sinAlpha / k,
11998               ci = (sinAlpha * dy - cosAlpha * dx) / k,
11999               fi = (sinAlpha * dx + cosAlpha * dy) / k;
12000
12001           function transform(x, y) {
12002             x *= sx;
12003             y *= sy;
12004             return [a * x - b * y + dx, dy - b * x - a * y];
12005           }
12006
12007           transform.invert = function (x, y) {
12008             return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
12009           };
12010
12011           return transform;
12012         }
12013
12014         function projection(project) {
12015           return projectionMutator(function () {
12016             return project;
12017           })();
12018         }
12019         function projectionMutator(projectAt) {
12020           var project,
12021               k = 150,
12022               // scale
12023           x = 480,
12024               y = 250,
12025               // translate
12026           lambda = 0,
12027               phi = 0,
12028               // center
12029           deltaLambda = 0,
12030               deltaPhi = 0,
12031               deltaGamma = 0,
12032               rotate,
12033               // pre-rotate
12034           alpha = 0,
12035               // post-rotate angle
12036           sx = 1,
12037               // reflectX
12038           sy = 1,
12039               // reflectX
12040           theta = null,
12041               preclip = clipAntimeridian,
12042               // pre-clip angle
12043           x0 = null,
12044               y0,
12045               x1,
12046               y1,
12047               postclip = identity,
12048               // post-clip extent
12049           delta2 = 0.5,
12050               // precision
12051           projectResample,
12052               projectTransform,
12053               projectRotateTransform,
12054               cache,
12055               cacheStream;
12056
12057           function projection(point) {
12058             return projectRotateTransform(point[0] * radians, point[1] * radians);
12059           }
12060
12061           function invert(point) {
12062             point = projectRotateTransform.invert(point[0], point[1]);
12063             return point && [point[0] * degrees, point[1] * degrees];
12064           }
12065
12066           projection.stream = function (stream) {
12067             return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
12068           };
12069
12070           projection.preclip = function (_) {
12071             return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
12072           };
12073
12074           projection.postclip = function (_) {
12075             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12076           };
12077
12078           projection.clipAngle = function (_) {
12079             return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees;
12080           };
12081
12082           projection.clipExtent = function (_) {
12083             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]];
12084           };
12085
12086           projection.scale = function (_) {
12087             return arguments.length ? (k = +_, recenter()) : k;
12088           };
12089
12090           projection.translate = function (_) {
12091             return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
12092           };
12093
12094           projection.center = function (_) {
12095             return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
12096           };
12097
12098           projection.rotate = function (_) {
12099             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];
12100           };
12101
12102           projection.angle = function (_) {
12103             return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees;
12104           };
12105
12106           projection.reflectX = function (_) {
12107             return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
12108           };
12109
12110           projection.reflectY = function (_) {
12111             return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
12112           };
12113
12114           projection.precision = function (_) {
12115             return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$1(delta2);
12116           };
12117
12118           projection.fitExtent = function (extent, object) {
12119             return fitExtent(projection, extent, object);
12120           };
12121
12122           projection.fitSize = function (size, object) {
12123             return fitSize(projection, size, object);
12124           };
12125
12126           projection.fitWidth = function (width, object) {
12127             return fitWidth(projection, width, object);
12128           };
12129
12130           projection.fitHeight = function (height, object) {
12131             return fitHeight(projection, height, object);
12132           };
12133
12134           function recenter() {
12135             var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
12136                 transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
12137             rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
12138             projectTransform = compose(project, transform);
12139             projectRotateTransform = compose(rotate, projectTransform);
12140             projectResample = resample(projectTransform, delta2);
12141             return reset();
12142           }
12143
12144           function reset() {
12145             cache = cacheStream = null;
12146             return projection;
12147           }
12148
12149           return function () {
12150             project = projectAt.apply(this, arguments);
12151             projection.invert = project.invert && invert;
12152             return recenter();
12153           };
12154         }
12155
12156         function mercatorRaw(lambda, phi) {
12157           return [lambda, log$1(tan((halfPi + phi) / 2))];
12158         }
12159
12160         mercatorRaw.invert = function (x, y) {
12161           return [x, 2 * atan(exp(y)) - halfPi];
12162         };
12163
12164         function mercator () {
12165           return mercatorProjection(mercatorRaw).scale(961 / tau);
12166         }
12167         function mercatorProjection(project) {
12168           var m = projection(project),
12169               center = m.center,
12170               scale = m.scale,
12171               translate = m.translate,
12172               clipExtent = m.clipExtent,
12173               x0 = null,
12174               y0,
12175               x1,
12176               y1; // clip extent
12177
12178           m.scale = function (_) {
12179             return arguments.length ? (scale(_), reclip()) : scale();
12180           };
12181
12182           m.translate = function (_) {
12183             return arguments.length ? (translate(_), reclip()) : translate();
12184           };
12185
12186           m.center = function (_) {
12187             return arguments.length ? (center(_), reclip()) : center();
12188           };
12189
12190           m.clipExtent = function (_) {
12191             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]];
12192           };
12193
12194           function reclip() {
12195             var k = pi * scale(),
12196                 t = m(rotation(m.rotate()).invert([0, 0]));
12197             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)]]);
12198           }
12199
12200           return reclip();
12201         }
12202
12203         function d3_geoIdentity () {
12204           var k = 1,
12205               tx = 0,
12206               ty = 0,
12207               sx = 1,
12208               sy = 1,
12209               // scale, translate and reflect
12210           alpha = 0,
12211               ca,
12212               sa,
12213               // angle
12214           x0 = null,
12215               y0,
12216               x1,
12217               y1,
12218               // clip extent
12219           kx = 1,
12220               ky = 1,
12221               transform = transformer({
12222             point: function point(x, y) {
12223               var p = projection([x, y]);
12224               this.stream.point(p[0], p[1]);
12225             }
12226           }),
12227               postclip = identity,
12228               cache,
12229               cacheStream;
12230
12231           function reset() {
12232             kx = k * sx;
12233             ky = k * sy;
12234             cache = cacheStream = null;
12235             return projection;
12236           }
12237
12238           function projection(p) {
12239             var x = p[0] * kx,
12240                 y = p[1] * ky;
12241
12242             if (alpha) {
12243               var t = y * ca - x * sa;
12244               x = x * ca + y * sa;
12245               y = t;
12246             }
12247
12248             return [x + tx, y + ty];
12249           }
12250
12251           projection.invert = function (p) {
12252             var x = p[0] - tx,
12253                 y = p[1] - ty;
12254
12255             if (alpha) {
12256               var t = y * ca + x * sa;
12257               x = x * ca - y * sa;
12258               y = t;
12259             }
12260
12261             return [x / kx, y / ky];
12262           };
12263
12264           projection.stream = function (stream) {
12265             return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
12266           };
12267
12268           projection.postclip = function (_) {
12269             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12270           };
12271
12272           projection.clipExtent = function (_) {
12273             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]];
12274           };
12275
12276           projection.scale = function (_) {
12277             return arguments.length ? (k = +_, reset()) : k;
12278           };
12279
12280           projection.translate = function (_) {
12281             return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
12282           };
12283
12284           projection.angle = function (_) {
12285             return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees;
12286           };
12287
12288           projection.reflectX = function (_) {
12289             return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
12290           };
12291
12292           projection.reflectY = function (_) {
12293             return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
12294           };
12295
12296           projection.fitExtent = function (extent, object) {
12297             return fitExtent(projection, extent, object);
12298           };
12299
12300           projection.fitSize = function (size, object) {
12301             return fitSize(projection, size, object);
12302           };
12303
12304           projection.fitWidth = function (width, object) {
12305             return fitWidth(projection, width, object);
12306           };
12307
12308           projection.fitHeight = function (height, object) {
12309             return fitHeight(projection, height, object);
12310           };
12311
12312           return projection;
12313         }
12314
12315         // constants
12316         var TAU = 2 * Math.PI;
12317         var EQUATORIAL_RADIUS = 6356752.314245179;
12318         var POLAR_RADIUS = 6378137.0;
12319         function geoLatToMeters(dLat) {
12320           return dLat * (TAU * POLAR_RADIUS / 360);
12321         }
12322         function geoLonToMeters(dLon, atLat) {
12323           return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
12324         }
12325         function geoMetersToLat(m) {
12326           return m / (TAU * POLAR_RADIUS / 360);
12327         }
12328         function geoMetersToLon(m, atLat) {
12329           return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
12330         }
12331         function geoMetersToOffset(meters, tileSize) {
12332           tileSize = tileSize || 256;
12333           return [meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), -meters[1] * tileSize / (TAU * POLAR_RADIUS)];
12334         }
12335         function geoOffsetToMeters(offset, tileSize) {
12336           tileSize = tileSize || 256;
12337           return [offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, -offset[1] * TAU * POLAR_RADIUS / tileSize];
12338         } // Equirectangular approximation of spherical distances on Earth
12339
12340         function geoSphericalDistance(a, b) {
12341           var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
12342           var y = geoLatToMeters(a[1] - b[1]);
12343           return Math.sqrt(x * x + y * y);
12344         } // scale to zoom
12345
12346         function geoScaleToZoom(k, tileSize) {
12347           tileSize = tileSize || 256;
12348           var log2ts = Math.log(tileSize) * Math.LOG2E;
12349           return Math.log(k * TAU) / Math.LN2 - log2ts;
12350         } // zoom to scale
12351
12352         function geoZoomToScale(z, tileSize) {
12353           tileSize = tileSize || 256;
12354           return tileSize * Math.pow(2, z) / TAU;
12355         } // returns info about the node from `nodes` closest to the given `point`
12356
12357         function geoSphericalClosestNode(nodes, point) {
12358           var minDistance = Infinity,
12359               distance;
12360           var indexOfMin;
12361
12362           for (var i in nodes) {
12363             distance = geoSphericalDistance(nodes[i].loc, point);
12364
12365             if (distance < minDistance) {
12366               minDistance = distance;
12367               indexOfMin = i;
12368             }
12369           }
12370
12371           if (indexOfMin !== undefined) {
12372             return {
12373               index: indexOfMin,
12374               distance: minDistance,
12375               node: nodes[indexOfMin]
12376             };
12377           } else {
12378             return null;
12379           }
12380         }
12381
12382         function geoExtent(min, max) {
12383           if (!(this instanceof geoExtent)) {
12384             return new geoExtent(min, max);
12385           } else if (min instanceof geoExtent) {
12386             return min;
12387           } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
12388             this[0] = min[0];
12389             this[1] = min[1];
12390           } else {
12391             this[0] = min || [Infinity, Infinity];
12392             this[1] = max || min || [-Infinity, -Infinity];
12393           }
12394         }
12395         geoExtent.prototype = new Array(2);
12396         Object.assign(geoExtent.prototype, {
12397           equals: function equals(obj) {
12398             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];
12399           },
12400           extend: function extend(obj) {
12401             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12402             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])]);
12403           },
12404           _extend: function _extend(extent) {
12405             this[0][0] = Math.min(extent[0][0], this[0][0]);
12406             this[0][1] = Math.min(extent[0][1], this[0][1]);
12407             this[1][0] = Math.max(extent[1][0], this[1][0]);
12408             this[1][1] = Math.max(extent[1][1], this[1][1]);
12409           },
12410           area: function area() {
12411             return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
12412           },
12413           center: function center() {
12414             return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
12415           },
12416           rectangle: function rectangle() {
12417             return [this[0][0], this[0][1], this[1][0], this[1][1]];
12418           },
12419           bbox: function bbox() {
12420             return {
12421               minX: this[0][0],
12422               minY: this[0][1],
12423               maxX: this[1][0],
12424               maxY: this[1][1]
12425             };
12426           },
12427           polygon: function polygon() {
12428             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]]];
12429           },
12430           contains: function contains(obj) {
12431             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12432             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];
12433           },
12434           intersects: function intersects(obj) {
12435             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12436             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];
12437           },
12438           intersection: function intersection(obj) {
12439             if (!this.intersects(obj)) return new geoExtent();
12440             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])]);
12441           },
12442           percentContainedIn: function percentContainedIn(obj) {
12443             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12444             var a1 = this.intersection(obj).area();
12445             var a2 = this.area();
12446
12447             if (a1 === Infinity || a2 === Infinity) {
12448               return 0;
12449             } else if (a1 === 0 || a2 === 0) {
12450               if (obj.contains(this)) {
12451                 return 1;
12452               }
12453
12454               return 0;
12455             } else {
12456               return a1 / a2;
12457             }
12458           },
12459           padByMeters: function padByMeters(meters) {
12460             var dLat = geoMetersToLat(meters);
12461             var dLon = geoMetersToLon(meters, this.center()[1]);
12462             return geoExtent([this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat]);
12463           },
12464           toParam: function toParam() {
12465             return this.rectangle().join(',');
12466           }
12467         });
12468
12469         var $every$1 = arrayIteration.every;
12470
12471
12472         var STRICT_METHOD$6 = arrayMethodIsStrict('every');
12473
12474         // `Array.prototype.every` method
12475         // https://tc39.es/ecma262/#sec-array.prototype.every
12476         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$6 }, {
12477           every: function every(callbackfn /* , thisArg */) {
12478             return $every$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
12479           }
12480         });
12481
12482         var $reduce$1 = arrayReduce.left;
12483
12484
12485
12486
12487         var STRICT_METHOD$7 = arrayMethodIsStrict('reduce');
12488         // Chrome 80-82 has a critical bug
12489         // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
12490         var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83;
12491
12492         // `Array.prototype.reduce` method
12493         // https://tc39.es/ecma262/#sec-array.prototype.reduce
12494         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$7 || CHROME_BUG }, {
12495           reduce: function reduce(callbackfn /* , initialValue */) {
12496             return $reduce$1(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
12497           }
12498         });
12499
12500         function d3_polygonArea (polygon) {
12501           var i = -1,
12502               n = polygon.length,
12503               a,
12504               b = polygon[n - 1],
12505               area = 0;
12506
12507           while (++i < n) {
12508             a = b;
12509             b = polygon[i];
12510             area += a[1] * b[0] - a[0] * b[1];
12511           }
12512
12513           return area / 2;
12514         }
12515
12516         function d3_polygonCentroid (polygon) {
12517           var i = -1,
12518               n = polygon.length,
12519               x = 0,
12520               y = 0,
12521               a,
12522               b = polygon[n - 1],
12523               c,
12524               k = 0;
12525
12526           while (++i < n) {
12527             a = b;
12528             b = polygon[i];
12529             k += c = a[0] * b[1] - b[0] * a[1];
12530             x += (a[0] + b[0]) * c;
12531             y += (a[1] + b[1]) * c;
12532           }
12533
12534           return k *= 3, [x / k, y / k];
12535         }
12536
12537         // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
12538         // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
12539         // right, +y is up). Returns a positive value if ABC is counter-clockwise,
12540         // negative if clockwise, and zero if the points are collinear.
12541         function cross (a, b, c) {
12542           return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
12543         }
12544
12545         function lexicographicOrder(a, b) {
12546           return a[0] - b[0] || a[1] - b[1];
12547         } // Computes the upper convex hull per the monotone chain algorithm.
12548         // Assumes points.length >= 3, is sorted by x, unique in y.
12549         // Returns an array of indices into points in left-to-right order.
12550
12551
12552         function computeUpperHullIndexes(points) {
12553           var n = points.length,
12554               indexes = [0, 1];
12555           var size = 2,
12556               i;
12557
12558           for (i = 2; i < n; ++i) {
12559             while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) {
12560               --size;
12561             }
12562
12563             indexes[size++] = i;
12564           }
12565
12566           return indexes.slice(0, size); // remove popped points
12567         }
12568
12569         function d3_polygonHull (points) {
12570           if ((n = points.length) < 3) return null;
12571           var i,
12572               n,
12573               sortedPoints = new Array(n),
12574               flippedPoints = new Array(n);
12575
12576           for (i = 0; i < n; ++i) {
12577             sortedPoints[i] = [+points[i][0], +points[i][1], i];
12578           }
12579
12580           sortedPoints.sort(lexicographicOrder);
12581
12582           for (i = 0; i < n; ++i) {
12583             flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
12584           }
12585
12586           var upperIndexes = computeUpperHullIndexes(sortedPoints),
12587               lowerIndexes = computeUpperHullIndexes(flippedPoints); // Construct the hull polygon, removing possible duplicate endpoints.
12588
12589           var skipLeft = lowerIndexes[0] === upperIndexes[0],
12590               skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
12591               hull = []; // Add upper hull in right-to-l order.
12592           // Then add lower hull in left-to-right order.
12593
12594           for (i = upperIndexes.length - 1; i >= 0; --i) {
12595             hull.push(points[sortedPoints[upperIndexes[i]][2]]);
12596           }
12597
12598           for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) {
12599             hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
12600           }
12601
12602           return hull;
12603         }
12604
12605         // vector equals
12606         function geoVecEqual(a, b, epsilon) {
12607           if (epsilon) {
12608             return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon;
12609           } else {
12610             return a[0] === b[0] && a[1] === b[1];
12611           }
12612         } // vector addition
12613
12614         function geoVecAdd(a, b) {
12615           return [a[0] + b[0], a[1] + b[1]];
12616         } // vector subtraction
12617
12618         function geoVecSubtract(a, b) {
12619           return [a[0] - b[0], a[1] - b[1]];
12620         } // vector scaling
12621
12622         function geoVecScale(a, mag) {
12623           return [a[0] * mag, a[1] * mag];
12624         } // vector rounding (was: geoRoundCoordinates)
12625
12626         function geoVecFloor(a) {
12627           return [Math.floor(a[0]), Math.floor(a[1])];
12628         } // linear interpolation
12629
12630         function geoVecInterp(a, b, t) {
12631           return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
12632         } // http://jsperf.com/id-dist-optimization
12633
12634         function geoVecLength(a, b) {
12635           return Math.sqrt(geoVecLengthSquare(a, b));
12636         } // length of vector raised to the power two
12637
12638         function geoVecLengthSquare(a, b) {
12639           b = b || [0, 0];
12640           var x = a[0] - b[0];
12641           var y = a[1] - b[1];
12642           return x * x + y * y;
12643         } // get a unit vector
12644
12645         function geoVecNormalize(a) {
12646           var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
12647
12648           if (length !== 0) {
12649             return geoVecScale(a, 1 / length);
12650           }
12651
12652           return [0, 0];
12653         } // Return the counterclockwise angle in the range (-pi, pi)
12654         // between the positive X axis and the line intersecting a and b.
12655
12656         function geoVecAngle(a, b) {
12657           return Math.atan2(b[1] - a[1], b[0] - a[0]);
12658         } // dot product
12659
12660         function geoVecDot(a, b, origin) {
12661           origin = origin || [0, 0];
12662           var p = geoVecSubtract(a, origin);
12663           var q = geoVecSubtract(b, origin);
12664           return p[0] * q[0] + p[1] * q[1];
12665         } // normalized dot product
12666
12667         function geoVecNormalizedDot(a, b, origin) {
12668           origin = origin || [0, 0];
12669           var p = geoVecNormalize(geoVecSubtract(a, origin));
12670           var q = geoVecNormalize(geoVecSubtract(b, origin));
12671           return geoVecDot(p, q);
12672         } // 2D cross product of OA and OB vectors, returns magnitude of Z vector
12673         // Returns a positive value, if OAB makes a counter-clockwise turn,
12674         // negative for clockwise turn, and zero if the points are collinear.
12675
12676         function geoVecCross(a, b, origin) {
12677           origin = origin || [0, 0];
12678           var p = geoVecSubtract(a, origin);
12679           var q = geoVecSubtract(b, origin);
12680           return p[0] * q[1] - p[1] * q[0];
12681         } // find closest orthogonal projection of point onto points array
12682
12683         function geoVecProject(a, points) {
12684           var min = Infinity;
12685           var idx;
12686           var target;
12687
12688           for (var i = 0; i < points.length - 1; i++) {
12689             var o = points[i];
12690             var s = geoVecSubtract(points[i + 1], o);
12691             var v = geoVecSubtract(a, o);
12692             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12693             var p;
12694
12695             if (proj < 0) {
12696               p = o;
12697             } else if (proj > 1) {
12698               p = points[i + 1];
12699             } else {
12700               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12701             }
12702
12703             var dist = geoVecLength(p, a);
12704
12705             if (dist < min) {
12706               min = dist;
12707               idx = i + 1;
12708               target = p;
12709             }
12710           }
12711
12712           if (idx !== undefined) {
12713             return {
12714               index: idx,
12715               distance: min,
12716               target: target
12717             };
12718           } else {
12719             return null;
12720           }
12721         }
12722
12723         // between the positive X axis and the line intersecting a and b.
12724
12725         function geoAngle(a, b, projection) {
12726           return geoVecAngle(projection(a.loc), projection(b.loc));
12727         }
12728         function geoEdgeEqual(a, b) {
12729           return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
12730         } // Rotate all points counterclockwise around a pivot point by given angle
12731
12732         function geoRotate(points, angle, around) {
12733           return points.map(function (point) {
12734             var radial = geoVecSubtract(point, around);
12735             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]];
12736           });
12737         } // Choose the edge with the minimal distance from `point` to its orthogonal
12738         // projection onto that edge, if such a projection exists, or the distance to
12739         // the closest vertex on that edge. Returns an object with the `index` of the
12740         // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
12741
12742         function geoChooseEdge(nodes, point, projection, activeID) {
12743           var dist = geoVecLength;
12744           var points = nodes.map(function (n) {
12745             return projection(n.loc);
12746           });
12747           var ids = nodes.map(function (n) {
12748             return n.id;
12749           });
12750           var min = Infinity;
12751           var idx;
12752           var loc;
12753
12754           for (var i = 0; i < points.length - 1; i++) {
12755             if (ids[i] === activeID || ids[i + 1] === activeID) continue;
12756             var o = points[i];
12757             var s = geoVecSubtract(points[i + 1], o);
12758             var v = geoVecSubtract(point, o);
12759             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12760             var p;
12761
12762             if (proj < 0) {
12763               p = o;
12764             } else if (proj > 1) {
12765               p = points[i + 1];
12766             } else {
12767               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12768             }
12769
12770             var d = dist(p, point);
12771
12772             if (d < min) {
12773               min = d;
12774               idx = i + 1;
12775               loc = projection.invert(p);
12776             }
12777           }
12778
12779           if (idx !== undefined) {
12780             return {
12781               index: idx,
12782               distance: min,
12783               loc: loc
12784             };
12785           } else {
12786             return null;
12787           }
12788         } // Test active (dragged or drawing) segments against inactive segments
12789         // This is used to test e.g. multipolygon rings that cross
12790         // `activeNodes` is the ring containing the activeID being dragged.
12791         // `inactiveNodes` is the other ring to test against
12792
12793         function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
12794           var actives = [];
12795           var inactives = [];
12796           var j, k, n1, n2, segment; // gather active segments (only segments in activeNodes that contain the activeID)
12797
12798           for (j = 0; j < activeNodes.length - 1; j++) {
12799             n1 = activeNodes[j];
12800             n2 = activeNodes[j + 1];
12801             segment = [n1.loc, n2.loc];
12802
12803             if (n1.id === activeID || n2.id === activeID) {
12804               actives.push(segment);
12805             }
12806           } // gather inactive segments
12807
12808
12809           for (j = 0; j < inactiveNodes.length - 1; j++) {
12810             n1 = inactiveNodes[j];
12811             n2 = inactiveNodes[j + 1];
12812             segment = [n1.loc, n2.loc];
12813             inactives.push(segment);
12814           } // test
12815
12816
12817           for (j = 0; j < actives.length; j++) {
12818             for (k = 0; k < inactives.length; k++) {
12819               var p = actives[j];
12820               var q = inactives[k];
12821               var hit = geoLineIntersection(p, q);
12822
12823               if (hit) {
12824                 return true;
12825               }
12826             }
12827           }
12828
12829           return false;
12830         } // Test active (dragged or drawing) segments against inactive segments
12831         // This is used to test whether a way intersects with itself.
12832
12833         function geoHasSelfIntersections(nodes, activeID) {
12834           var actives = [];
12835           var inactives = [];
12836           var j, k; // group active and passive segments along the nodes
12837
12838           for (j = 0; j < nodes.length - 1; j++) {
12839             var n1 = nodes[j];
12840             var n2 = nodes[j + 1];
12841             var segment = [n1.loc, n2.loc];
12842
12843             if (n1.id === activeID || n2.id === activeID) {
12844               actives.push(segment);
12845             } else {
12846               inactives.push(segment);
12847             }
12848           } // test
12849
12850
12851           for (j = 0; j < actives.length; j++) {
12852             for (k = 0; k < inactives.length; k++) {
12853               var p = actives[j];
12854               var q = inactives[k]; // skip if segments share an endpoint
12855
12856               if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
12857                 continue;
12858               }
12859
12860               var hit = geoLineIntersection(p, q);
12861
12862               if (hit) {
12863                 var epsilon = 1e-8; // skip if the hit is at the segment's endpoint
12864
12865                 if (geoVecEqual(p[1], hit, epsilon) || geoVecEqual(p[0], hit, epsilon) || geoVecEqual(q[1], hit, epsilon) || geoVecEqual(q[0], hit, epsilon)) {
12866                   continue;
12867                 } else {
12868                   return true;
12869                 }
12870               }
12871             }
12872           }
12873
12874           return false;
12875         } // Return the intersection point of 2 line segments.
12876         // From https://github.com/pgkelley4/line-segments-intersect
12877         // This uses the vector cross product approach described below:
12878         //  http://stackoverflow.com/a/565282/786339
12879
12880         function geoLineIntersection(a, b) {
12881           var p = [a[0][0], a[0][1]];
12882           var p2 = [a[1][0], a[1][1]];
12883           var q = [b[0][0], b[0][1]];
12884           var q2 = [b[1][0], b[1][1]];
12885           var r = geoVecSubtract(p2, p);
12886           var s = geoVecSubtract(q2, q);
12887           var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
12888           var denominator = geoVecCross(r, s);
12889
12890           if (uNumerator && denominator) {
12891             var u = uNumerator / denominator;
12892             var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
12893
12894             if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
12895               return geoVecInterp(p, p2, t);
12896             }
12897           }
12898
12899           return null;
12900         }
12901         function geoPathIntersections(path1, path2) {
12902           var intersections = [];
12903
12904           for (var i = 0; i < path1.length - 1; i++) {
12905             for (var j = 0; j < path2.length - 1; j++) {
12906               var a = [path1[i], path1[i + 1]];
12907               var b = [path2[j], path2[j + 1]];
12908               var hit = geoLineIntersection(a, b);
12909
12910               if (hit) {
12911                 intersections.push(hit);
12912               }
12913             }
12914           }
12915
12916           return intersections;
12917         }
12918         function geoPathHasIntersections(path1, path2) {
12919           for (var i = 0; i < path1.length - 1; i++) {
12920             for (var j = 0; j < path2.length - 1; j++) {
12921               var a = [path1[i], path1[i + 1]];
12922               var b = [path2[j], path2[j + 1]];
12923               var hit = geoLineIntersection(a, b);
12924
12925               if (hit) {
12926                 return true;
12927               }
12928             }
12929           }
12930
12931           return false;
12932         } // Return whether point is contained in polygon.
12933         //
12934         // `point` should be a 2-item array of coordinates.
12935         // `polygon` should be an array of 2-item arrays of coordinates.
12936         //
12937         // From https://github.com/substack/point-in-polygon.
12938         // ray-casting algorithm based on
12939         // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
12940         //
12941
12942         function geoPointInPolygon(point, polygon) {
12943           var x = point[0];
12944           var y = point[1];
12945           var inside = false;
12946
12947           for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
12948             var xi = polygon[i][0];
12949             var yi = polygon[i][1];
12950             var xj = polygon[j][0];
12951             var yj = polygon[j][1];
12952             var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
12953             if (intersect) inside = !inside;
12954           }
12955
12956           return inside;
12957         }
12958         function geoPolygonContainsPolygon(outer, inner) {
12959           return inner.every(function (point) {
12960             return geoPointInPolygon(point, outer);
12961           });
12962         }
12963         function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
12964           function testPoints(outer, inner) {
12965             return inner.some(function (point) {
12966               return geoPointInPolygon(point, outer);
12967             });
12968           }
12969
12970           return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
12971         } // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
12972         // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
12973
12974         function geoGetSmallestSurroundingRectangle(points) {
12975           var hull = d3_polygonHull(points);
12976           var centroid = d3_polygonCentroid(hull);
12977           var minArea = Infinity;
12978           var ssrExtent = [];
12979           var ssrAngle = 0;
12980           var c1 = hull[0];
12981
12982           for (var i = 0; i <= hull.length - 1; i++) {
12983             var c2 = i === hull.length - 1 ? hull[0] : hull[i + 1];
12984             var angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
12985             var poly = geoRotate(hull, -angle, centroid);
12986             var extent = poly.reduce(function (extent, point) {
12987               return extent.extend(geoExtent(point));
12988             }, geoExtent());
12989             var area = extent.area();
12990
12991             if (area < minArea) {
12992               minArea = area;
12993               ssrExtent = extent;
12994               ssrAngle = angle;
12995             }
12996
12997             c1 = c2;
12998           }
12999
13000           return {
13001             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
13002             angle: ssrAngle
13003           };
13004         }
13005         function geoPathLength(path) {
13006           var length = 0;
13007
13008           for (var i = 0; i < path.length - 1; i++) {
13009             length += geoVecLength(path[i], path[i + 1]);
13010           }
13011
13012           return length;
13013         } // If the given point is at the edge of the padded viewport,
13014         // return a vector that will nudge the viewport in that direction
13015
13016         function geoViewportEdge(point, dimensions) {
13017           var pad = [80, 20, 50, 20]; // top, right, bottom, left
13018
13019           var x = 0;
13020           var y = 0;
13021           if (point[0] > dimensions[0] - pad[1]) x = -10;
13022           if (point[0] < pad[3]) x = 10;
13023           if (point[1] > dimensions[1] - pad[2]) y = -10;
13024           if (point[1] < pad[0]) y = 10;
13025
13026           if (x || y) {
13027             return [x, y];
13028           } else {
13029             return null;
13030           }
13031         }
13032
13033         var noop$1 = {
13034           value: function value() {}
13035         };
13036
13037         function dispatch() {
13038           for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
13039             if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
13040             _[t] = [];
13041           }
13042
13043           return new Dispatch$1(_);
13044         }
13045
13046         function Dispatch$1(_) {
13047           this._ = _;
13048         }
13049
13050         function parseTypenames(typenames, types) {
13051           return typenames.trim().split(/^|\s+/).map(function (t) {
13052             var name = "",
13053                 i = t.indexOf(".");
13054             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13055             if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
13056             return {
13057               type: t,
13058               name: name
13059             };
13060           });
13061         }
13062
13063         Dispatch$1.prototype = dispatch.prototype = {
13064           constructor: Dispatch$1,
13065           on: function on(typename, callback) {
13066             var _ = this._,
13067                 T = parseTypenames(typename + "", _),
13068                 t,
13069                 i = -1,
13070                 n = T.length; // If no callback was specified, return the callback of the given type and name.
13071
13072             if (arguments.length < 2) {
13073               while (++i < n) {
13074                 if ((t = (typename = T[i]).type) && (t = get$3(_[t], typename.name))) return t;
13075               }
13076
13077               return;
13078             } // If a type was specified, set the callback for the given type and name.
13079             // Otherwise, if a null callback was specified, remove callbacks of the given name.
13080
13081
13082             if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
13083
13084             while (++i < n) {
13085               if (t = (typename = T[i]).type) _[t] = set$3(_[t], typename.name, callback);else if (callback == null) for (t in _) {
13086                 _[t] = set$3(_[t], typename.name, null);
13087               }
13088             }
13089
13090             return this;
13091           },
13092           copy: function copy() {
13093             var copy = {},
13094                 _ = this._;
13095
13096             for (var t in _) {
13097               copy[t] = _[t].slice();
13098             }
13099
13100             return new Dispatch$1(copy);
13101           },
13102           call: function call(type, that) {
13103             if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) {
13104               args[i] = arguments[i + 2];
13105             }
13106             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13107
13108             for (t = this._[type], i = 0, n = t.length; i < n; ++i) {
13109               t[i].value.apply(that, args);
13110             }
13111           },
13112           apply: function apply(type, that, args) {
13113             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13114
13115             for (var t = this._[type], i = 0, n = t.length; i < n; ++i) {
13116               t[i].value.apply(that, args);
13117             }
13118           }
13119         };
13120
13121         function get$3(type, name) {
13122           for (var i = 0, n = type.length, c; i < n; ++i) {
13123             if ((c = type[i]).name === name) {
13124               return c.value;
13125             }
13126           }
13127         }
13128
13129         function set$3(type, name, callback) {
13130           for (var i = 0, n = type.length; i < n; ++i) {
13131             if (type[i].name === name) {
13132               type[i] = noop$1, type = type.slice(0, i).concat(type.slice(i + 1));
13133               break;
13134             }
13135           }
13136
13137           if (callback != null) type.push({
13138             name: name,
13139             value: callback
13140           });
13141           return type;
13142         }
13143
13144         var xhtml = "http://www.w3.org/1999/xhtml";
13145         var namespaces = {
13146           svg: "http://www.w3.org/2000/svg",
13147           xhtml: xhtml,
13148           xlink: "http://www.w3.org/1999/xlink",
13149           xml: "http://www.w3.org/XML/1998/namespace",
13150           xmlns: "http://www.w3.org/2000/xmlns/"
13151         };
13152
13153         function namespace (name) {
13154           var prefix = name += "",
13155               i = prefix.indexOf(":");
13156           if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
13157           return namespaces.hasOwnProperty(prefix) ? {
13158             space: namespaces[prefix],
13159             local: name
13160           } : name; // eslint-disable-line no-prototype-builtins
13161         }
13162
13163         function creatorInherit(name) {
13164           return function () {
13165             var document = this.ownerDocument,
13166                 uri = this.namespaceURI;
13167             return uri === xhtml && document.documentElement.namespaceURI === xhtml ? document.createElement(name) : document.createElementNS(uri, name);
13168           };
13169         }
13170
13171         function creatorFixed(fullname) {
13172           return function () {
13173             return this.ownerDocument.createElementNS(fullname.space, fullname.local);
13174           };
13175         }
13176
13177         function creator (name) {
13178           var fullname = namespace(name);
13179           return (fullname.local ? creatorFixed : creatorInherit)(fullname);
13180         }
13181
13182         function none() {}
13183
13184         function selector (selector) {
13185           return selector == null ? none : function () {
13186             return this.querySelector(selector);
13187           };
13188         }
13189
13190         function selection_select (select) {
13191           if (typeof select !== "function") select = selector(select);
13192
13193           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13194             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
13195               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
13196                 if ("__data__" in node) subnode.__data__ = node.__data__;
13197                 subgroup[i] = subnode;
13198               }
13199             }
13200           }
13201
13202           return new Selection(subgroups, this._parents);
13203         }
13204
13205         function array (x) {
13206           return _typeof(x) === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like
13207           : Array.from(x); // Map, Set, iterable, string, or anything else
13208         }
13209
13210         function empty() {
13211           return [];
13212         }
13213
13214         function selectorAll (selector) {
13215           return selector == null ? empty : function () {
13216             return this.querySelectorAll(selector);
13217           };
13218         }
13219
13220         function arrayAll(select) {
13221           return function () {
13222             var group = select.apply(this, arguments);
13223             return group == null ? [] : array(group);
13224           };
13225         }
13226
13227         function selection_selectAll (select) {
13228           if (typeof select === "function") select = arrayAll(select);else select = selectorAll(select);
13229
13230           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
13231             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
13232               if (node = group[i]) {
13233                 subgroups.push(select.call(node, node.__data__, i, group));
13234                 parents.push(node);
13235               }
13236             }
13237           }
13238
13239           return new Selection(subgroups, parents);
13240         }
13241
13242         var $find$1 = arrayIteration.find;
13243
13244
13245         var FIND = 'find';
13246         var SKIPS_HOLES = true;
13247
13248         // Shouldn't skip holes
13249         if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES = false; });
13250
13251         // `Array.prototype.find` method
13252         // https://tc39.es/ecma262/#sec-array.prototype.find
13253         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES }, {
13254           find: function find(callbackfn /* , that = undefined */) {
13255             return $find$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13256           }
13257         });
13258
13259         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
13260         addToUnscopables(FIND);
13261
13262         function matcher (selector) {
13263           return function () {
13264             return this.matches(selector);
13265           };
13266         }
13267         function childMatcher(selector) {
13268           return function (node) {
13269             return node.matches(selector);
13270           };
13271         }
13272
13273         var find$1 = Array.prototype.find;
13274
13275         function childFind(match) {
13276           return function () {
13277             return find$1.call(this.children, match);
13278           };
13279         }
13280
13281         function childFirst() {
13282           return this.firstElementChild;
13283         }
13284
13285         function selection_selectChild (match) {
13286           return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
13287         }
13288
13289         var filter = Array.prototype.filter;
13290
13291         function children() {
13292           return this.children;
13293         }
13294
13295         function childrenFilter(match) {
13296           return function () {
13297             return filter.call(this.children, match);
13298           };
13299         }
13300
13301         function selection_selectChildren (match) {
13302           return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
13303         }
13304
13305         function selection_filter (match) {
13306           if (typeof match !== "function") match = matcher(match);
13307
13308           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13309             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
13310               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
13311                 subgroup.push(node);
13312               }
13313             }
13314           }
13315
13316           return new Selection(subgroups, this._parents);
13317         }
13318
13319         function sparse (update) {
13320           return new Array(update.length);
13321         }
13322
13323         function selection_enter () {
13324           return new Selection(this._enter || this._groups.map(sparse), this._parents);
13325         }
13326         function EnterNode(parent, datum) {
13327           this.ownerDocument = parent.ownerDocument;
13328           this.namespaceURI = parent.namespaceURI;
13329           this._next = null;
13330           this._parent = parent;
13331           this.__data__ = datum;
13332         }
13333         EnterNode.prototype = {
13334           constructor: EnterNode,
13335           appendChild: function appendChild(child) {
13336             return this._parent.insertBefore(child, this._next);
13337           },
13338           insertBefore: function insertBefore(child, next) {
13339             return this._parent.insertBefore(child, next);
13340           },
13341           querySelector: function querySelector(selector) {
13342             return this._parent.querySelector(selector);
13343           },
13344           querySelectorAll: function querySelectorAll(selector) {
13345             return this._parent.querySelectorAll(selector);
13346           }
13347         };
13348
13349         function constant (x) {
13350           return function () {
13351             return x;
13352           };
13353         }
13354
13355         function bindIndex(parent, group, enter, update, exit, data) {
13356           var i = 0,
13357               node,
13358               groupLength = group.length,
13359               dataLength = data.length; // Put any non-null nodes that fit into update.
13360           // Put any null nodes into enter.
13361           // Put any remaining data into enter.
13362
13363           for (; i < dataLength; ++i) {
13364             if (node = group[i]) {
13365               node.__data__ = data[i];
13366               update[i] = node;
13367             } else {
13368               enter[i] = new EnterNode(parent, data[i]);
13369             }
13370           } // Put any non-null nodes that don’t fit into exit.
13371
13372
13373           for (; i < groupLength; ++i) {
13374             if (node = group[i]) {
13375               exit[i] = node;
13376             }
13377           }
13378         }
13379
13380         function bindKey(parent, group, enter, update, exit, data, key) {
13381           var i,
13382               node,
13383               nodeByKeyValue = new Map(),
13384               groupLength = group.length,
13385               dataLength = data.length,
13386               keyValues = new Array(groupLength),
13387               keyValue; // Compute the key for each node.
13388           // If multiple nodes have the same key, the duplicates are added to exit.
13389
13390           for (i = 0; i < groupLength; ++i) {
13391             if (node = group[i]) {
13392               keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
13393
13394               if (nodeByKeyValue.has(keyValue)) {
13395                 exit[i] = node;
13396               } else {
13397                 nodeByKeyValue.set(keyValue, node);
13398               }
13399             }
13400           } // Compute the key for each datum.
13401           // If there a node associated with this key, join and add it to update.
13402           // If there is not (or the key is a duplicate), add it to enter.
13403
13404
13405           for (i = 0; i < dataLength; ++i) {
13406             keyValue = key.call(parent, data[i], i, data) + "";
13407
13408             if (node = nodeByKeyValue.get(keyValue)) {
13409               update[i] = node;
13410               node.__data__ = data[i];
13411               nodeByKeyValue["delete"](keyValue);
13412             } else {
13413               enter[i] = new EnterNode(parent, data[i]);
13414             }
13415           } // Add any remaining nodes that were not bound to data to exit.
13416
13417
13418           for (i = 0; i < groupLength; ++i) {
13419             if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
13420               exit[i] = node;
13421             }
13422           }
13423         }
13424
13425         function datum(node) {
13426           return node.__data__;
13427         }
13428
13429         function selection_data (value, key) {
13430           if (!arguments.length) return Array.from(this, datum);
13431           var bind = key ? bindKey : bindIndex,
13432               parents = this._parents,
13433               groups = this._groups;
13434           if (typeof value !== "function") value = constant(value);
13435
13436           for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
13437             var parent = parents[j],
13438                 group = groups[j],
13439                 groupLength = group.length,
13440                 data = array(value.call(parent, parent && parent.__data__, j, parents)),
13441                 dataLength = data.length,
13442                 enterGroup = enter[j] = new Array(dataLength),
13443                 updateGroup = update[j] = new Array(dataLength),
13444                 exitGroup = exit[j] = new Array(groupLength);
13445             bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); // Now connect the enter nodes to their following update node, such that
13446             // appendChild can insert the materialized enter node before this node,
13447             // rather than at the end of the parent node.
13448
13449             for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
13450               if (previous = enterGroup[i0]) {
13451                 if (i0 >= i1) i1 = i0 + 1;
13452
13453                 while (!(next = updateGroup[i1]) && ++i1 < dataLength) {
13454                 }
13455
13456                 previous._next = next || null;
13457               }
13458             }
13459           }
13460
13461           update = new Selection(update, parents);
13462           update._enter = enter;
13463           update._exit = exit;
13464           return update;
13465         }
13466
13467         function selection_exit () {
13468           return new Selection(this._exit || this._groups.map(sparse), this._parents);
13469         }
13470
13471         function selection_join (onenter, onupdate, onexit) {
13472           var enter = this.enter(),
13473               update = this,
13474               exit = this.exit();
13475           enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
13476           if (onupdate != null) update = onupdate(update);
13477           if (onexit == null) exit.remove();else onexit(exit);
13478           return enter && update ? enter.merge(update).order() : update;
13479         }
13480
13481         function selection_merge (selection) {
13482           if (!(selection instanceof Selection)) throw new Error("invalid merge");
13483
13484           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) {
13485             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
13486               if (node = group0[i] || group1[i]) {
13487                 merge[i] = node;
13488               }
13489             }
13490           }
13491
13492           for (; j < m0; ++j) {
13493             merges[j] = groups0[j];
13494           }
13495
13496           return new Selection(merges, this._parents);
13497         }
13498
13499         function selection_order () {
13500           for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
13501             for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
13502               if (node = group[i]) {
13503                 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
13504                 next = node;
13505               }
13506             }
13507           }
13508
13509           return this;
13510         }
13511
13512         function selection_sort (compare) {
13513           if (!compare) compare = ascending;
13514
13515           function compareNode(a, b) {
13516             return a && b ? compare(a.__data__, b.__data__) : !a - !b;
13517           }
13518
13519           for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
13520             for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
13521               if (node = group[i]) {
13522                 sortgroup[i] = node;
13523               }
13524             }
13525
13526             sortgroup.sort(compareNode);
13527           }
13528
13529           return new Selection(sortgroups, this._parents).order();
13530         }
13531
13532         function ascending(a, b) {
13533           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
13534         }
13535
13536         function selection_call () {
13537           var callback = arguments[0];
13538           arguments[0] = this;
13539           callback.apply(null, arguments);
13540           return this;
13541         }
13542
13543         function selection_nodes () {
13544           return Array.from(this);
13545         }
13546
13547         function selection_node () {
13548           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13549             for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
13550               var node = group[i];
13551               if (node) return node;
13552             }
13553           }
13554
13555           return null;
13556         }
13557
13558         function selection_size () {
13559           var size = 0;
13560
13561           var _iterator = _createForOfIteratorHelper(this),
13562               _step;
13563
13564           try {
13565             for (_iterator.s(); !(_step = _iterator.n()).done;) {
13566               var node = _step.value;
13567               ++size;
13568             } // eslint-disable-line no-unused-vars
13569
13570           } catch (err) {
13571             _iterator.e(err);
13572           } finally {
13573             _iterator.f();
13574           }
13575
13576           return size;
13577         }
13578
13579         function selection_empty () {
13580           return !this.node();
13581         }
13582
13583         function selection_each (callback) {
13584           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13585             for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
13586               if (node = group[i]) callback.call(node, node.__data__, i, group);
13587             }
13588           }
13589
13590           return this;
13591         }
13592
13593         function attrRemove(name) {
13594           return function () {
13595             this.removeAttribute(name);
13596           };
13597         }
13598
13599         function attrRemoveNS(fullname) {
13600           return function () {
13601             this.removeAttributeNS(fullname.space, fullname.local);
13602           };
13603         }
13604
13605         function attrConstant(name, value) {
13606           return function () {
13607             this.setAttribute(name, value);
13608           };
13609         }
13610
13611         function attrConstantNS(fullname, value) {
13612           return function () {
13613             this.setAttributeNS(fullname.space, fullname.local, value);
13614           };
13615         }
13616
13617         function attrFunction(name, value) {
13618           return function () {
13619             var v = value.apply(this, arguments);
13620             if (v == null) this.removeAttribute(name);else this.setAttribute(name, v);
13621           };
13622         }
13623
13624         function attrFunctionNS(fullname, value) {
13625           return function () {
13626             var v = value.apply(this, arguments);
13627             if (v == null) this.removeAttributeNS(fullname.space, fullname.local);else this.setAttributeNS(fullname.space, fullname.local, v);
13628           };
13629         }
13630
13631         function selection_attr (name, value) {
13632           var fullname = namespace(name);
13633
13634           if (arguments.length < 2) {
13635             var node = this.node();
13636             return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
13637           }
13638
13639           return this.each((value == null ? fullname.local ? attrRemoveNS : attrRemove : typeof value === "function" ? fullname.local ? attrFunctionNS : attrFunction : fullname.local ? attrConstantNS : attrConstant)(fullname, value));
13640         }
13641
13642         function defaultView (node) {
13643           return node.ownerDocument && node.ownerDocument.defaultView || // node is a Node
13644           node.document && node // node is a Window
13645           || node.defaultView; // node is a Document
13646         }
13647
13648         function styleRemove(name) {
13649           return function () {
13650             this.style.removeProperty(name);
13651           };
13652         }
13653
13654         function styleConstant(name, value, priority) {
13655           return function () {
13656             this.style.setProperty(name, value, priority);
13657           };
13658         }
13659
13660         function styleFunction(name, value, priority) {
13661           return function () {
13662             var v = value.apply(this, arguments);
13663             if (v == null) this.style.removeProperty(name);else this.style.setProperty(name, v, priority);
13664           };
13665         }
13666
13667         function selection_style (name, value, priority) {
13668           return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function" ? styleFunction : styleConstant)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
13669         }
13670         function styleValue(node, name) {
13671           return node.style.getPropertyValue(name) || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
13672         }
13673
13674         function propertyRemove(name) {
13675           return function () {
13676             delete this[name];
13677           };
13678         }
13679
13680         function propertyConstant(name, value) {
13681           return function () {
13682             this[name] = value;
13683           };
13684         }
13685
13686         function propertyFunction(name, value) {
13687           return function () {
13688             var v = value.apply(this, arguments);
13689             if (v == null) delete this[name];else this[name] = v;
13690           };
13691         }
13692
13693         function selection_property (name, value) {
13694           return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
13695         }
13696
13697         function classArray(string) {
13698           return string.trim().split(/^|\s+/);
13699         }
13700
13701         function classList(node) {
13702           return node.classList || new ClassList(node);
13703         }
13704
13705         function ClassList(node) {
13706           this._node = node;
13707           this._names = classArray(node.getAttribute("class") || "");
13708         }
13709
13710         ClassList.prototype = {
13711           add: function add(name) {
13712             var i = this._names.indexOf(name);
13713
13714             if (i < 0) {
13715               this._names.push(name);
13716
13717               this._node.setAttribute("class", this._names.join(" "));
13718             }
13719           },
13720           remove: function remove(name) {
13721             var i = this._names.indexOf(name);
13722
13723             if (i >= 0) {
13724               this._names.splice(i, 1);
13725
13726               this._node.setAttribute("class", this._names.join(" "));
13727             }
13728           },
13729           contains: function contains(name) {
13730             return this._names.indexOf(name) >= 0;
13731           }
13732         };
13733
13734         function classedAdd(node, names) {
13735           var list = classList(node),
13736               i = -1,
13737               n = names.length;
13738
13739           while (++i < n) {
13740             list.add(names[i]);
13741           }
13742         }
13743
13744         function classedRemove(node, names) {
13745           var list = classList(node),
13746               i = -1,
13747               n = names.length;
13748
13749           while (++i < n) {
13750             list.remove(names[i]);
13751           }
13752         }
13753
13754         function classedTrue(names) {
13755           return function () {
13756             classedAdd(this, names);
13757           };
13758         }
13759
13760         function classedFalse(names) {
13761           return function () {
13762             classedRemove(this, names);
13763           };
13764         }
13765
13766         function classedFunction(names, value) {
13767           return function () {
13768             (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
13769           };
13770         }
13771
13772         function selection_classed (name, value) {
13773           var names = classArray(name + "");
13774
13775           if (arguments.length < 2) {
13776             var list = classList(this.node()),
13777                 i = -1,
13778                 n = names.length;
13779
13780             while (++i < n) {
13781               if (!list.contains(names[i])) return false;
13782             }
13783
13784             return true;
13785           }
13786
13787           return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
13788         }
13789
13790         function textRemove() {
13791           this.textContent = "";
13792         }
13793
13794         function textConstant(value) {
13795           return function () {
13796             this.textContent = value;
13797           };
13798         }
13799
13800         function textFunction(value) {
13801           return function () {
13802             var v = value.apply(this, arguments);
13803             this.textContent = v == null ? "" : v;
13804           };
13805         }
13806
13807         function selection_text (value) {
13808           return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction : textConstant)(value)) : this.node().textContent;
13809         }
13810
13811         function htmlRemove() {
13812           this.innerHTML = "";
13813         }
13814
13815         function htmlConstant(value) {
13816           return function () {
13817             this.innerHTML = value;
13818           };
13819         }
13820
13821         function htmlFunction(value) {
13822           return function () {
13823             var v = value.apply(this, arguments);
13824             this.innerHTML = v == null ? "" : v;
13825           };
13826         }
13827
13828         function selection_html (value) {
13829           return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
13830         }
13831
13832         function raise() {
13833           if (this.nextSibling) this.parentNode.appendChild(this);
13834         }
13835
13836         function selection_raise () {
13837           return this.each(raise);
13838         }
13839
13840         function lower() {
13841           if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
13842         }
13843
13844         function selection_lower () {
13845           return this.each(lower);
13846         }
13847
13848         function selection_append (name) {
13849           var create = typeof name === "function" ? name : creator(name);
13850           return this.select(function () {
13851             return this.appendChild(create.apply(this, arguments));
13852           });
13853         }
13854
13855         function constantNull() {
13856           return null;
13857         }
13858
13859         function selection_insert (name, before) {
13860           var create = typeof name === "function" ? name : creator(name),
13861               select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
13862           return this.select(function () {
13863             return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
13864           });
13865         }
13866
13867         function remove() {
13868           var parent = this.parentNode;
13869           if (parent) parent.removeChild(this);
13870         }
13871
13872         function selection_remove () {
13873           return this.each(remove);
13874         }
13875
13876         function selection_cloneShallow() {
13877           var clone = this.cloneNode(false),
13878               parent = this.parentNode;
13879           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
13880         }
13881
13882         function selection_cloneDeep() {
13883           var clone = this.cloneNode(true),
13884               parent = this.parentNode;
13885           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
13886         }
13887
13888         function selection_clone (deep) {
13889           return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
13890         }
13891
13892         function selection_datum (value) {
13893           return arguments.length ? this.property("__data__", value) : this.node().__data__;
13894         }
13895
13896         function contextListener(listener) {
13897           return function (event) {
13898             listener.call(this, event, this.__data__);
13899           };
13900         }
13901
13902         function parseTypenames$1(typenames) {
13903           return typenames.trim().split(/^|\s+/).map(function (t) {
13904             var name = "",
13905                 i = t.indexOf(".");
13906             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13907             return {
13908               type: t,
13909               name: name
13910             };
13911           });
13912         }
13913
13914         function onRemove(typename) {
13915           return function () {
13916             var on = this.__on;
13917             if (!on) return;
13918
13919             for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
13920               if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
13921                 this.removeEventListener(o.type, o.listener, o.options);
13922               } else {
13923                 on[++i] = o;
13924               }
13925             }
13926
13927             if (++i) on.length = i;else delete this.__on;
13928           };
13929         }
13930
13931         function onAdd(typename, value, options) {
13932           return function () {
13933             var on = this.__on,
13934                 o,
13935                 listener = contextListener(value);
13936             if (on) for (var j = 0, m = on.length; j < m; ++j) {
13937               if ((o = on[j]).type === typename.type && o.name === typename.name) {
13938                 this.removeEventListener(o.type, o.listener, o.options);
13939                 this.addEventListener(o.type, o.listener = listener, o.options = options);
13940                 o.value = value;
13941                 return;
13942               }
13943             }
13944             this.addEventListener(typename.type, listener, options);
13945             o = {
13946               type: typename.type,
13947               name: typename.name,
13948               value: value,
13949               listener: listener,
13950               options: options
13951             };
13952             if (!on) this.__on = [o];else on.push(o);
13953           };
13954         }
13955
13956         function selection_on (typename, value, options) {
13957           var typenames = parseTypenames$1(typename + ""),
13958               i,
13959               n = typenames.length,
13960               t;
13961
13962           if (arguments.length < 2) {
13963             var on = this.node().__on;
13964
13965             if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
13966               for (i = 0, o = on[j]; i < n; ++i) {
13967                 if ((t = typenames[i]).type === o.type && t.name === o.name) {
13968                   return o.value;
13969                 }
13970               }
13971             }
13972             return;
13973           }
13974
13975           on = value ? onAdd : onRemove;
13976
13977           for (i = 0; i < n; ++i) {
13978             this.each(on(typenames[i], value, options));
13979           }
13980
13981           return this;
13982         }
13983
13984         function dispatchEvent$1(node, type, params) {
13985           var window = defaultView(node),
13986               event = window.CustomEvent;
13987
13988           if (typeof event === "function") {
13989             event = new event(type, params);
13990           } else {
13991             event = window.document.createEvent("Event");
13992             if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;else event.initEvent(type, false, false);
13993           }
13994
13995           node.dispatchEvent(event);
13996         }
13997
13998         function dispatchConstant(type, params) {
13999           return function () {
14000             return dispatchEvent$1(this, type, params);
14001           };
14002         }
14003
14004         function dispatchFunction(type, params) {
14005           return function () {
14006             return dispatchEvent$1(this, type, params.apply(this, arguments));
14007           };
14008         }
14009
14010         function selection_dispatch (type, params) {
14011           return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
14012         }
14013
14014         var _marked$2 = /*#__PURE__*/regeneratorRuntime.mark(_callee);
14015
14016         function _callee() {
14017           var groups, j, m, group, i, n, node;
14018           return regeneratorRuntime.wrap(function _callee$(_context) {
14019             while (1) {
14020               switch (_context.prev = _context.next) {
14021                 case 0:
14022                   groups = this._groups, j = 0, m = groups.length;
14023
14024                 case 1:
14025                   if (!(j < m)) {
14026                     _context.next = 13;
14027                     break;
14028                   }
14029
14030                   group = groups[j], i = 0, n = group.length;
14031
14032                 case 3:
14033                   if (!(i < n)) {
14034                     _context.next = 10;
14035                     break;
14036                   }
14037
14038                   if (!(node = group[i])) {
14039                     _context.next = 7;
14040                     break;
14041                   }
14042
14043                   _context.next = 7;
14044                   return node;
14045
14046                 case 7:
14047                   ++i;
14048                   _context.next = 3;
14049                   break;
14050
14051                 case 10:
14052                   ++j;
14053                   _context.next = 1;
14054                   break;
14055
14056                 case 13:
14057                 case "end":
14058                   return _context.stop();
14059               }
14060             }
14061           }, _marked$2, this);
14062         }
14063
14064         var root = [null];
14065         function Selection(groups, parents) {
14066           this._groups = groups;
14067           this._parents = parents;
14068         }
14069
14070         function selection() {
14071           return new Selection([[document.documentElement]], root);
14072         }
14073
14074         function selection_selection() {
14075           return this;
14076         }
14077
14078         Selection.prototype = selection.prototype = _defineProperty({
14079           constructor: Selection,
14080           select: selection_select,
14081           selectAll: selection_selectAll,
14082           selectChild: selection_selectChild,
14083           selectChildren: selection_selectChildren,
14084           filter: selection_filter,
14085           data: selection_data,
14086           enter: selection_enter,
14087           exit: selection_exit,
14088           join: selection_join,
14089           merge: selection_merge,
14090           selection: selection_selection,
14091           order: selection_order,
14092           sort: selection_sort,
14093           call: selection_call,
14094           nodes: selection_nodes,
14095           node: selection_node,
14096           size: selection_size,
14097           empty: selection_empty,
14098           each: selection_each,
14099           attr: selection_attr,
14100           style: selection_style,
14101           property: selection_property,
14102           classed: selection_classed,
14103           text: selection_text,
14104           html: selection_html,
14105           raise: selection_raise,
14106           lower: selection_lower,
14107           append: selection_append,
14108           insert: selection_insert,
14109           remove: selection_remove,
14110           clone: selection_clone,
14111           datum: selection_datum,
14112           on: selection_on,
14113           dispatch: selection_dispatch
14114         }, Symbol.iterator, _callee);
14115
14116         function select (selector) {
14117           return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
14118         }
14119
14120         function sourceEvent (event) {
14121           var sourceEvent;
14122
14123           while (sourceEvent = event.sourceEvent) {
14124             event = sourceEvent;
14125           }
14126
14127           return event;
14128         }
14129
14130         function pointer (event, node) {
14131           event = sourceEvent(event);
14132           if (node === undefined) node = event.currentTarget;
14133
14134           if (node) {
14135             var svg = node.ownerSVGElement || node;
14136
14137             if (svg.createSVGPoint) {
14138               var point = svg.createSVGPoint();
14139               point.x = event.clientX, point.y = event.clientY;
14140               point = point.matrixTransform(node.getScreenCTM().inverse());
14141               return [point.x, point.y];
14142             }
14143
14144             if (node.getBoundingClientRect) {
14145               var rect = node.getBoundingClientRect();
14146               return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
14147             }
14148           }
14149
14150           return [event.pageX, event.pageY];
14151         }
14152
14153         function selectAll (selector) {
14154           return typeof selector === "string" ? new Selection([document.querySelectorAll(selector)], [document.documentElement]) : new Selection([selector == null ? [] : array(selector)], root);
14155         }
14156
14157         function nopropagation(event) {
14158           event.stopImmediatePropagation();
14159         }
14160         function noevent (event) {
14161           event.preventDefault();
14162           event.stopImmediatePropagation();
14163         }
14164
14165         function dragDisable (view) {
14166           var root = view.document.documentElement,
14167               selection = select(view).on("dragstart.drag", noevent, true);
14168
14169           if ("onselectstart" in root) {
14170             selection.on("selectstart.drag", noevent, true);
14171           } else {
14172             root.__noselect = root.style.MozUserSelect;
14173             root.style.MozUserSelect = "none";
14174           }
14175         }
14176         function yesdrag(view, noclick) {
14177           var root = view.document.documentElement,
14178               selection = select(view).on("dragstart.drag", null);
14179
14180           if (noclick) {
14181             selection.on("click.drag", noevent, true);
14182             setTimeout(function () {
14183               selection.on("click.drag", null);
14184             }, 0);
14185           }
14186
14187           if ("onselectstart" in root) {
14188             selection.on("selectstart.drag", null);
14189           } else {
14190             root.style.MozUserSelect = root.__noselect;
14191             delete root.__noselect;
14192           }
14193         }
14194
14195         var constant$1 = (function (x) {
14196           return function () {
14197             return x;
14198           };
14199         });
14200
14201         function DragEvent(type, _ref) {
14202           var sourceEvent = _ref.sourceEvent,
14203               subject = _ref.subject,
14204               target = _ref.target,
14205               identifier = _ref.identifier,
14206               active = _ref.active,
14207               x = _ref.x,
14208               y = _ref.y,
14209               dx = _ref.dx,
14210               dy = _ref.dy,
14211               dispatch = _ref.dispatch;
14212           Object.defineProperties(this, {
14213             type: {
14214               value: type,
14215               enumerable: true,
14216               configurable: true
14217             },
14218             sourceEvent: {
14219               value: sourceEvent,
14220               enumerable: true,
14221               configurable: true
14222             },
14223             subject: {
14224               value: subject,
14225               enumerable: true,
14226               configurable: true
14227             },
14228             target: {
14229               value: target,
14230               enumerable: true,
14231               configurable: true
14232             },
14233             identifier: {
14234               value: identifier,
14235               enumerable: true,
14236               configurable: true
14237             },
14238             active: {
14239               value: active,
14240               enumerable: true,
14241               configurable: true
14242             },
14243             x: {
14244               value: x,
14245               enumerable: true,
14246               configurable: true
14247             },
14248             y: {
14249               value: y,
14250               enumerable: true,
14251               configurable: true
14252             },
14253             dx: {
14254               value: dx,
14255               enumerable: true,
14256               configurable: true
14257             },
14258             dy: {
14259               value: dy,
14260               enumerable: true,
14261               configurable: true
14262             },
14263             _: {
14264               value: dispatch
14265             }
14266           });
14267         }
14268
14269         DragEvent.prototype.on = function () {
14270           var value = this._.on.apply(this._, arguments);
14271
14272           return value === this._ ? this : value;
14273         };
14274
14275         function defaultFilter(event) {
14276           return !event.ctrlKey && !event.button;
14277         }
14278
14279         function defaultContainer() {
14280           return this.parentNode;
14281         }
14282
14283         function defaultSubject(event, d) {
14284           return d == null ? {
14285             x: event.x,
14286             y: event.y
14287           } : d;
14288         }
14289
14290         function defaultTouchable() {
14291           return navigator.maxTouchPoints || "ontouchstart" in this;
14292         }
14293
14294         function d3_drag () {
14295           var filter = defaultFilter,
14296               container = defaultContainer,
14297               subject = defaultSubject,
14298               touchable = defaultTouchable,
14299               gestures = {},
14300               listeners = dispatch("start", "drag", "end"),
14301               active = 0,
14302               mousedownx,
14303               mousedowny,
14304               mousemoving,
14305               touchending,
14306               clickDistance2 = 0;
14307
14308           function drag(selection) {
14309             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)");
14310           }
14311
14312           function mousedowned(event, d) {
14313             if (touchending || !filter.call(this, event, d)) return;
14314             var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
14315             if (!gesture) return;
14316             select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
14317             dragDisable(event.view);
14318             nopropagation(event);
14319             mousemoving = false;
14320             mousedownx = event.clientX;
14321             mousedowny = event.clientY;
14322             gesture("start", event);
14323           }
14324
14325           function mousemoved(event) {
14326             noevent(event);
14327
14328             if (!mousemoving) {
14329               var dx = event.clientX - mousedownx,
14330                   dy = event.clientY - mousedowny;
14331               mousemoving = dx * dx + dy * dy > clickDistance2;
14332             }
14333
14334             gestures.mouse("drag", event);
14335           }
14336
14337           function mouseupped(event) {
14338             select(event.view).on("mousemove.drag mouseup.drag", null);
14339             yesdrag(event.view, mousemoving);
14340             noevent(event);
14341             gestures.mouse("end", event);
14342           }
14343
14344           function touchstarted(event, d) {
14345             if (!filter.call(this, event, d)) return;
14346             var touches = event.changedTouches,
14347                 c = container.call(this, event, d),
14348                 n = touches.length,
14349                 i,
14350                 gesture;
14351
14352             for (i = 0; i < n; ++i) {
14353               if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
14354                 nopropagation(event);
14355                 gesture("start", event, touches[i]);
14356               }
14357             }
14358           }
14359
14360           function touchmoved(event) {
14361             var touches = event.changedTouches,
14362                 n = touches.length,
14363                 i,
14364                 gesture;
14365
14366             for (i = 0; i < n; ++i) {
14367               if (gesture = gestures[touches[i].identifier]) {
14368                 noevent(event);
14369                 gesture("drag", event, touches[i]);
14370               }
14371             }
14372           }
14373
14374           function touchended(event) {
14375             var touches = event.changedTouches,
14376                 n = touches.length,
14377                 i,
14378                 gesture;
14379             if (touchending) clearTimeout(touchending);
14380             touchending = setTimeout(function () {
14381               touchending = null;
14382             }, 500); // Ghost clicks are delayed!
14383
14384             for (i = 0; i < n; ++i) {
14385               if (gesture = gestures[touches[i].identifier]) {
14386                 nopropagation(event);
14387                 gesture("end", event, touches[i]);
14388               }
14389             }
14390           }
14391
14392           function beforestart(that, container, event, d, identifier, touch) {
14393             var dispatch = listeners.copy(),
14394                 p = pointer(touch || event, container),
14395                 dx,
14396                 dy,
14397                 s;
14398             if ((s = subject.call(that, new DragEvent("beforestart", {
14399               sourceEvent: event,
14400               target: drag,
14401               identifier: identifier,
14402               active: active,
14403               x: p[0],
14404               y: p[1],
14405               dx: 0,
14406               dy: 0,
14407               dispatch: dispatch
14408             }), d)) == null) return;
14409             dx = s.x - p[0] || 0;
14410             dy = s.y - p[1] || 0;
14411             return function gesture(type, event, touch) {
14412               var p0 = p,
14413                   n;
14414
14415               switch (type) {
14416                 case "start":
14417                   gestures[identifier] = gesture, n = active++;
14418                   break;
14419
14420                 case "end":
14421                   delete gestures[identifier], --active;
14422                 // nobreak
14423
14424                 case "drag":
14425                   p = pointer(touch || event, container), n = active;
14426                   break;
14427               }
14428
14429               dispatch.call(type, that, new DragEvent(type, {
14430                 sourceEvent: event,
14431                 subject: s,
14432                 target: drag,
14433                 identifier: identifier,
14434                 active: n,
14435                 x: p[0] + dx,
14436                 y: p[1] + dy,
14437                 dx: p[0] - p0[0],
14438                 dy: p[1] - p0[1],
14439                 dispatch: dispatch
14440               }), d);
14441             };
14442           }
14443
14444           drag.filter = function (_) {
14445             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$1(!!_), drag) : filter;
14446           };
14447
14448           drag.container = function (_) {
14449             return arguments.length ? (container = typeof _ === "function" ? _ : constant$1(_), drag) : container;
14450           };
14451
14452           drag.subject = function (_) {
14453             return arguments.length ? (subject = typeof _ === "function" ? _ : constant$1(_), drag) : subject;
14454           };
14455
14456           drag.touchable = function (_) {
14457             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$1(!!_), drag) : touchable;
14458           };
14459
14460           drag.on = function () {
14461             var value = listeners.on.apply(listeners, arguments);
14462             return value === listeners ? drag : value;
14463           };
14464
14465           drag.clickDistance = function (_) {
14466             return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
14467           };
14468
14469           return drag;
14470         }
14471
14472         var defineProperty$8 = objectDefineProperty.f;
14473         var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
14474
14475
14476
14477
14478
14479         var setInternalState$8 = internalState.set;
14480
14481
14482
14483         var MATCH$1 = wellKnownSymbol('match');
14484         var NativeRegExp = global_1.RegExp;
14485         var RegExpPrototype$1 = NativeRegExp.prototype;
14486         var re1 = /a/g;
14487         var re2 = /a/g;
14488
14489         // "new" should create a new object, old webkit bug
14490         var CORRECT_NEW = new NativeRegExp(re1) !== re1;
14491
14492         var UNSUPPORTED_Y$2 = regexpStickyHelpers.UNSUPPORTED_Y;
14493
14494         var FORCED$b = descriptors && isForced_1('RegExp', (!CORRECT_NEW || UNSUPPORTED_Y$2 || fails(function () {
14495           re2[MATCH$1] = false;
14496           // RegExp constructor can alter flags and IsRegExp works correct with @@match
14497           return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
14498         })));
14499
14500         // `RegExp` constructor
14501         // https://tc39.es/ecma262/#sec-regexp-constructor
14502         if (FORCED$b) {
14503           var RegExpWrapper = function RegExp(pattern, flags) {
14504             var thisIsRegExp = this instanceof RegExpWrapper;
14505             var patternIsRegExp = isRegexp(pattern);
14506             var flagsAreUndefined = flags === undefined;
14507             var sticky;
14508
14509             if (!thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined) {
14510               return pattern;
14511             }
14512
14513             if (CORRECT_NEW) {
14514               if (patternIsRegExp && !flagsAreUndefined) pattern = pattern.source;
14515             } else if (pattern instanceof RegExpWrapper) {
14516               if (flagsAreUndefined) flags = regexpFlags.call(pattern);
14517               pattern = pattern.source;
14518             }
14519
14520             if (UNSUPPORTED_Y$2) {
14521               sticky = !!flags && flags.indexOf('y') > -1;
14522               if (sticky) flags = flags.replace(/y/g, '');
14523             }
14524
14525             var result = inheritIfRequired(
14526               CORRECT_NEW ? new NativeRegExp(pattern, flags) : NativeRegExp(pattern, flags),
14527               thisIsRegExp ? this : RegExpPrototype$1,
14528               RegExpWrapper
14529             );
14530
14531             if (UNSUPPORTED_Y$2 && sticky) setInternalState$8(result, { sticky: sticky });
14532
14533             return result;
14534           };
14535           var proxy = function (key) {
14536             key in RegExpWrapper || defineProperty$8(RegExpWrapper, key, {
14537               configurable: true,
14538               get: function () { return NativeRegExp[key]; },
14539               set: function (it) { NativeRegExp[key] = it; }
14540             });
14541           };
14542           var keys$2 = getOwnPropertyNames$1(NativeRegExp);
14543           var index = 0;
14544           while (keys$2.length > index) proxy(keys$2[index++]);
14545           RegExpPrototype$1.constructor = RegExpWrapper;
14546           RegExpWrapper.prototype = RegExpPrototype$1;
14547           redefine(global_1, 'RegExp', RegExpWrapper);
14548         }
14549
14550         // https://tc39.es/ecma262/#sec-get-regexp-@@species
14551         setSpecies('RegExp');
14552
14553         function define (constructor, factory, prototype) {
14554           constructor.prototype = factory.prototype = prototype;
14555           prototype.constructor = constructor;
14556         }
14557         function extend(parent, definition) {
14558           var prototype = Object.create(parent.prototype);
14559
14560           for (var key in definition) {
14561             prototype[key] = definition[key];
14562           }
14563
14564           return prototype;
14565         }
14566
14567         function Color() {}
14568         var _darker = 0.7;
14569
14570         var _brighter = 1 / _darker;
14571         var reI = "\\s*([+-]?\\d+)\\s*",
14572             reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
14573             reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
14574             reHex = /^#([0-9a-f]{3,8})$/,
14575             reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
14576             reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
14577             reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
14578             reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
14579             reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
14580             reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
14581         var named = {
14582           aliceblue: 0xf0f8ff,
14583           antiquewhite: 0xfaebd7,
14584           aqua: 0x00ffff,
14585           aquamarine: 0x7fffd4,
14586           azure: 0xf0ffff,
14587           beige: 0xf5f5dc,
14588           bisque: 0xffe4c4,
14589           black: 0x000000,
14590           blanchedalmond: 0xffebcd,
14591           blue: 0x0000ff,
14592           blueviolet: 0x8a2be2,
14593           brown: 0xa52a2a,
14594           burlywood: 0xdeb887,
14595           cadetblue: 0x5f9ea0,
14596           chartreuse: 0x7fff00,
14597           chocolate: 0xd2691e,
14598           coral: 0xff7f50,
14599           cornflowerblue: 0x6495ed,
14600           cornsilk: 0xfff8dc,
14601           crimson: 0xdc143c,
14602           cyan: 0x00ffff,
14603           darkblue: 0x00008b,
14604           darkcyan: 0x008b8b,
14605           darkgoldenrod: 0xb8860b,
14606           darkgray: 0xa9a9a9,
14607           darkgreen: 0x006400,
14608           darkgrey: 0xa9a9a9,
14609           darkkhaki: 0xbdb76b,
14610           darkmagenta: 0x8b008b,
14611           darkolivegreen: 0x556b2f,
14612           darkorange: 0xff8c00,
14613           darkorchid: 0x9932cc,
14614           darkred: 0x8b0000,
14615           darksalmon: 0xe9967a,
14616           darkseagreen: 0x8fbc8f,
14617           darkslateblue: 0x483d8b,
14618           darkslategray: 0x2f4f4f,
14619           darkslategrey: 0x2f4f4f,
14620           darkturquoise: 0x00ced1,
14621           darkviolet: 0x9400d3,
14622           deeppink: 0xff1493,
14623           deepskyblue: 0x00bfff,
14624           dimgray: 0x696969,
14625           dimgrey: 0x696969,
14626           dodgerblue: 0x1e90ff,
14627           firebrick: 0xb22222,
14628           floralwhite: 0xfffaf0,
14629           forestgreen: 0x228b22,
14630           fuchsia: 0xff00ff,
14631           gainsboro: 0xdcdcdc,
14632           ghostwhite: 0xf8f8ff,
14633           gold: 0xffd700,
14634           goldenrod: 0xdaa520,
14635           gray: 0x808080,
14636           green: 0x008000,
14637           greenyellow: 0xadff2f,
14638           grey: 0x808080,
14639           honeydew: 0xf0fff0,
14640           hotpink: 0xff69b4,
14641           indianred: 0xcd5c5c,
14642           indigo: 0x4b0082,
14643           ivory: 0xfffff0,
14644           khaki: 0xf0e68c,
14645           lavender: 0xe6e6fa,
14646           lavenderblush: 0xfff0f5,
14647           lawngreen: 0x7cfc00,
14648           lemonchiffon: 0xfffacd,
14649           lightblue: 0xadd8e6,
14650           lightcoral: 0xf08080,
14651           lightcyan: 0xe0ffff,
14652           lightgoldenrodyellow: 0xfafad2,
14653           lightgray: 0xd3d3d3,
14654           lightgreen: 0x90ee90,
14655           lightgrey: 0xd3d3d3,
14656           lightpink: 0xffb6c1,
14657           lightsalmon: 0xffa07a,
14658           lightseagreen: 0x20b2aa,
14659           lightskyblue: 0x87cefa,
14660           lightslategray: 0x778899,
14661           lightslategrey: 0x778899,
14662           lightsteelblue: 0xb0c4de,
14663           lightyellow: 0xffffe0,
14664           lime: 0x00ff00,
14665           limegreen: 0x32cd32,
14666           linen: 0xfaf0e6,
14667           magenta: 0xff00ff,
14668           maroon: 0x800000,
14669           mediumaquamarine: 0x66cdaa,
14670           mediumblue: 0x0000cd,
14671           mediumorchid: 0xba55d3,
14672           mediumpurple: 0x9370db,
14673           mediumseagreen: 0x3cb371,
14674           mediumslateblue: 0x7b68ee,
14675           mediumspringgreen: 0x00fa9a,
14676           mediumturquoise: 0x48d1cc,
14677           mediumvioletred: 0xc71585,
14678           midnightblue: 0x191970,
14679           mintcream: 0xf5fffa,
14680           mistyrose: 0xffe4e1,
14681           moccasin: 0xffe4b5,
14682           navajowhite: 0xffdead,
14683           navy: 0x000080,
14684           oldlace: 0xfdf5e6,
14685           olive: 0x808000,
14686           olivedrab: 0x6b8e23,
14687           orange: 0xffa500,
14688           orangered: 0xff4500,
14689           orchid: 0xda70d6,
14690           palegoldenrod: 0xeee8aa,
14691           palegreen: 0x98fb98,
14692           paleturquoise: 0xafeeee,
14693           palevioletred: 0xdb7093,
14694           papayawhip: 0xffefd5,
14695           peachpuff: 0xffdab9,
14696           peru: 0xcd853f,
14697           pink: 0xffc0cb,
14698           plum: 0xdda0dd,
14699           powderblue: 0xb0e0e6,
14700           purple: 0x800080,
14701           rebeccapurple: 0x663399,
14702           red: 0xff0000,
14703           rosybrown: 0xbc8f8f,
14704           royalblue: 0x4169e1,
14705           saddlebrown: 0x8b4513,
14706           salmon: 0xfa8072,
14707           sandybrown: 0xf4a460,
14708           seagreen: 0x2e8b57,
14709           seashell: 0xfff5ee,
14710           sienna: 0xa0522d,
14711           silver: 0xc0c0c0,
14712           skyblue: 0x87ceeb,
14713           slateblue: 0x6a5acd,
14714           slategray: 0x708090,
14715           slategrey: 0x708090,
14716           snow: 0xfffafa,
14717           springgreen: 0x00ff7f,
14718           steelblue: 0x4682b4,
14719           tan: 0xd2b48c,
14720           teal: 0x008080,
14721           thistle: 0xd8bfd8,
14722           tomato: 0xff6347,
14723           turquoise: 0x40e0d0,
14724           violet: 0xee82ee,
14725           wheat: 0xf5deb3,
14726           white: 0xffffff,
14727           whitesmoke: 0xf5f5f5,
14728           yellow: 0xffff00,
14729           yellowgreen: 0x9acd32
14730         };
14731         define(Color, color, {
14732           copy: function copy(channels) {
14733             return Object.assign(new this.constructor(), this, channels);
14734           },
14735           displayable: function displayable() {
14736             return this.rgb().displayable();
14737           },
14738           hex: color_formatHex,
14739           // Deprecated! Use color.formatHex.
14740           formatHex: color_formatHex,
14741           formatHsl: color_formatHsl,
14742           formatRgb: color_formatRgb,
14743           toString: color_formatRgb
14744         });
14745
14746         function color_formatHex() {
14747           return this.rgb().formatHex();
14748         }
14749
14750         function color_formatHsl() {
14751           return hslConvert(this).formatHsl();
14752         }
14753
14754         function color_formatRgb() {
14755           return this.rgb().formatRgb();
14756         }
14757
14758         function color(format) {
14759           var m, l;
14760           format = (format + "").trim().toLowerCase();
14761           return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
14762           : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
14763           : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
14764           : 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
14765           : null // invalid hex
14766           ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
14767           : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
14768           : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
14769           : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
14770           : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
14771           : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
14772           : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
14773           : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
14774         }
14775
14776         function rgbn(n) {
14777           return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
14778         }
14779
14780         function rgba(r, g, b, a) {
14781           if (a <= 0) r = g = b = NaN;
14782           return new Rgb(r, g, b, a);
14783         }
14784
14785         function rgbConvert(o) {
14786           if (!(o instanceof Color)) o = color(o);
14787           if (!o) return new Rgb();
14788           o = o.rgb();
14789           return new Rgb(o.r, o.g, o.b, o.opacity);
14790         }
14791         function rgb(r, g, b, opacity) {
14792           return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
14793         }
14794         function Rgb(r, g, b, opacity) {
14795           this.r = +r;
14796           this.g = +g;
14797           this.b = +b;
14798           this.opacity = +opacity;
14799         }
14800         define(Rgb, rgb, extend(Color, {
14801           brighter: function brighter(k) {
14802             k = k == null ? _brighter : Math.pow(_brighter, k);
14803             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
14804           },
14805           darker: function darker(k) {
14806             k = k == null ? _darker : Math.pow(_darker, k);
14807             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
14808           },
14809           rgb: function rgb() {
14810             return this;
14811           },
14812           displayable: function displayable() {
14813             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;
14814           },
14815           hex: rgb_formatHex,
14816           // Deprecated! Use color.formatHex.
14817           formatHex: rgb_formatHex,
14818           formatRgb: rgb_formatRgb,
14819           toString: rgb_formatRgb
14820         }));
14821
14822         function rgb_formatHex() {
14823           return "#" + hex$2(this.r) + hex$2(this.g) + hex$2(this.b);
14824         }
14825
14826         function rgb_formatRgb() {
14827           var a = this.opacity;
14828           a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
14829           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 + ")");
14830         }
14831
14832         function hex$2(value) {
14833           value = Math.max(0, Math.min(255, Math.round(value) || 0));
14834           return (value < 16 ? "0" : "") + value.toString(16);
14835         }
14836
14837         function hsla(h, s, l, a) {
14838           if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
14839           return new Hsl(h, s, l, a);
14840         }
14841
14842         function hslConvert(o) {
14843           if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
14844           if (!(o instanceof Color)) o = color(o);
14845           if (!o) return new Hsl();
14846           if (o instanceof Hsl) return o;
14847           o = o.rgb();
14848           var r = o.r / 255,
14849               g = o.g / 255,
14850               b = o.b / 255,
14851               min = Math.min(r, g, b),
14852               max = Math.max(r, g, b),
14853               h = NaN,
14854               s = max - min,
14855               l = (max + min) / 2;
14856
14857           if (s) {
14858             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;
14859             s /= l < 0.5 ? max + min : 2 - max - min;
14860             h *= 60;
14861           } else {
14862             s = l > 0 && l < 1 ? 0 : h;
14863           }
14864
14865           return new Hsl(h, s, l, o.opacity);
14866         }
14867         function hsl(h, s, l, opacity) {
14868           return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
14869         }
14870
14871         function Hsl(h, s, l, opacity) {
14872           this.h = +h;
14873           this.s = +s;
14874           this.l = +l;
14875           this.opacity = +opacity;
14876         }
14877
14878         define(Hsl, hsl, extend(Color, {
14879           brighter: function brighter(k) {
14880             k = k == null ? _brighter : Math.pow(_brighter, k);
14881             return new Hsl(this.h, this.s, this.l * k, this.opacity);
14882           },
14883           darker: function darker(k) {
14884             k = k == null ? _darker : Math.pow(_darker, k);
14885             return new Hsl(this.h, this.s, this.l * k, this.opacity);
14886           },
14887           rgb: function rgb() {
14888             var h = this.h % 360 + (this.h < 0) * 360,
14889                 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
14890                 l = this.l,
14891                 m2 = l + (l < 0.5 ? l : 1 - l) * s,
14892                 m1 = 2 * l - m2;
14893             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);
14894           },
14895           displayable: function displayable() {
14896             return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
14897           },
14898           formatHsl: function formatHsl() {
14899             var a = this.opacity;
14900             a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
14901             return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
14902           }
14903         }));
14904         /* From FvD 13.37, CSS Color Module Level 3 */
14905
14906         function hsl2rgb(h, m1, m2) {
14907           return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
14908         }
14909
14910         var constant$2 = (function (x) {
14911           return function () {
14912             return x;
14913           };
14914         });
14915
14916         function linear(a, d) {
14917           return function (t) {
14918             return a + t * d;
14919           };
14920         }
14921
14922         function exponential(a, b, y) {
14923           return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
14924             return Math.pow(a + t * b, y);
14925           };
14926         }
14927         function gamma(y) {
14928           return (y = +y) === 1 ? nogamma : function (a, b) {
14929             return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a);
14930           };
14931         }
14932         function nogamma(a, b) {
14933           var d = b - a;
14934           return d ? linear(a, d) : constant$2(isNaN(a) ? b : a);
14935         }
14936
14937         var d3_interpolateRgb = (function rgbGamma(y) {
14938           var color = gamma(y);
14939
14940           function rgb$1(start, end) {
14941             var r = color((start = rgb(start)).r, (end = rgb(end)).r),
14942                 g = color(start.g, end.g),
14943                 b = color(start.b, end.b),
14944                 opacity = nogamma(start.opacity, end.opacity);
14945             return function (t) {
14946               start.r = r(t);
14947               start.g = g(t);
14948               start.b = b(t);
14949               start.opacity = opacity(t);
14950               return start + "";
14951             };
14952           }
14953
14954           rgb$1.gamma = rgbGamma;
14955           return rgb$1;
14956         })(1);
14957
14958         function numberArray (a, b) {
14959           if (!b) b = [];
14960           var n = a ? Math.min(b.length, a.length) : 0,
14961               c = b.slice(),
14962               i;
14963           return function (t) {
14964             for (i = 0; i < n; ++i) {
14965               c[i] = a[i] * (1 - t) + b[i] * t;
14966             }
14967
14968             return c;
14969           };
14970         }
14971         function isNumberArray(x) {
14972           return ArrayBuffer.isView(x) && !(x instanceof DataView);
14973         }
14974
14975         function genericArray(a, b) {
14976           var nb = b ? b.length : 0,
14977               na = a ? Math.min(nb, a.length) : 0,
14978               x = new Array(na),
14979               c = new Array(nb),
14980               i;
14981
14982           for (i = 0; i < na; ++i) {
14983             x[i] = interpolate(a[i], b[i]);
14984           }
14985
14986           for (; i < nb; ++i) {
14987             c[i] = b[i];
14988           }
14989
14990           return function (t) {
14991             for (i = 0; i < na; ++i) {
14992               c[i] = x[i](t);
14993             }
14994
14995             return c;
14996           };
14997         }
14998
14999         function date (a, b) {
15000           var d = new Date();
15001           return a = +a, b = +b, function (t) {
15002             return d.setTime(a * (1 - t) + b * t), d;
15003           };
15004         }
15005
15006         function d3_interpolateNumber (a, b) {
15007           return a = +a, b = +b, function (t) {
15008             return a * (1 - t) + b * t;
15009           };
15010         }
15011
15012         function object (a, b) {
15013           var i = {},
15014               c = {},
15015               k;
15016           if (a === null || _typeof(a) !== "object") a = {};
15017           if (b === null || _typeof(b) !== "object") b = {};
15018
15019           for (k in b) {
15020             if (k in a) {
15021               i[k] = interpolate(a[k], b[k]);
15022             } else {
15023               c[k] = b[k];
15024             }
15025           }
15026
15027           return function (t) {
15028             for (k in i) {
15029               c[k] = i[k](t);
15030             }
15031
15032             return c;
15033           };
15034         }
15035
15036         var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
15037             reB = new RegExp(reA.source, "g");
15038
15039         function zero(b) {
15040           return function () {
15041             return b;
15042           };
15043         }
15044
15045         function one(b) {
15046           return function (t) {
15047             return b(t) + "";
15048           };
15049         }
15050
15051         function interpolateString (a, b) {
15052           var bi = reA.lastIndex = reB.lastIndex = 0,
15053               // scan index for next number in b
15054           am,
15055               // current match in a
15056           bm,
15057               // current match in b
15058           bs,
15059               // string preceding current number in b, if any
15060           i = -1,
15061               // index in s
15062           s = [],
15063               // string constants and placeholders
15064           q = []; // number interpolators
15065           // Coerce inputs to strings.
15066
15067           a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
15068
15069           while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
15070             if ((bs = bm.index) > bi) {
15071               // a string precedes the next number in b
15072               bs = b.slice(bi, bs);
15073               if (s[i]) s[i] += bs; // coalesce with previous string
15074               else s[++i] = bs;
15075             }
15076
15077             if ((am = am[0]) === (bm = bm[0])) {
15078               // numbers in a & b match
15079               if (s[i]) s[i] += bm; // coalesce with previous string
15080               else s[++i] = bm;
15081             } else {
15082               // interpolate non-matching numbers
15083               s[++i] = null;
15084               q.push({
15085                 i: i,
15086                 x: d3_interpolateNumber(am, bm)
15087               });
15088             }
15089
15090             bi = reB.lastIndex;
15091           } // Add remains of b.
15092
15093
15094           if (bi < b.length) {
15095             bs = b.slice(bi);
15096             if (s[i]) s[i] += bs; // coalesce with previous string
15097             else s[++i] = bs;
15098           } // Special optimization for only a single match.
15099           // Otherwise, interpolate each of the numbers and rejoin the string.
15100
15101
15102           return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
15103             for (var i = 0, o; i < b; ++i) {
15104               s[(o = q[i]).i] = o.x(t);
15105             }
15106
15107             return s.join("");
15108           });
15109         }
15110
15111         function interpolate (a, b) {
15112           var t = _typeof(b),
15113               c;
15114
15115           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);
15116         }
15117
15118         function interpolateRound (a, b) {
15119           return a = +a, b = +b, function (t) {
15120             return Math.round(a * (1 - t) + b * t);
15121           };
15122         }
15123
15124         var degrees$1 = 180 / Math.PI;
15125         var identity$1 = {
15126           translateX: 0,
15127           translateY: 0,
15128           rotate: 0,
15129           skewX: 0,
15130           scaleX: 1,
15131           scaleY: 1
15132         };
15133         function decompose (a, b, c, d, e, f) {
15134           var scaleX, scaleY, skewX;
15135           if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
15136           if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
15137           if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
15138           if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
15139           return {
15140             translateX: e,
15141             translateY: f,
15142             rotate: Math.atan2(b, a) * degrees$1,
15143             skewX: Math.atan(skewX) * degrees$1,
15144             scaleX: scaleX,
15145             scaleY: scaleY
15146           };
15147         }
15148
15149         var svgNode;
15150         /* eslint-disable no-undef */
15151
15152         function parseCss(value) {
15153           var m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
15154           return m.isIdentity ? identity$1 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
15155         }
15156         function parseSvg(value) {
15157           if (value == null) return identity$1;
15158           if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
15159           svgNode.setAttribute("transform", value);
15160           if (!(value = svgNode.transform.baseVal.consolidate())) return identity$1;
15161           value = value.matrix;
15162           return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
15163         }
15164
15165         function interpolateTransform(parse, pxComma, pxParen, degParen) {
15166           function pop(s) {
15167             return s.length ? s.pop() + " " : "";
15168           }
15169
15170           function translate(xa, ya, xb, yb, s, q) {
15171             if (xa !== xb || ya !== yb) {
15172               var i = s.push("translate(", null, pxComma, null, pxParen);
15173               q.push({
15174                 i: i - 4,
15175                 x: d3_interpolateNumber(xa, xb)
15176               }, {
15177                 i: i - 2,
15178                 x: d3_interpolateNumber(ya, yb)
15179               });
15180             } else if (xb || yb) {
15181               s.push("translate(" + xb + pxComma + yb + pxParen);
15182             }
15183           }
15184
15185           function rotate(a, b, s, q) {
15186             if (a !== b) {
15187               if (a - b > 180) b += 360;else if (b - a > 180) a += 360; // shortest path
15188
15189               q.push({
15190                 i: s.push(pop(s) + "rotate(", null, degParen) - 2,
15191                 x: d3_interpolateNumber(a, b)
15192               });
15193             } else if (b) {
15194               s.push(pop(s) + "rotate(" + b + degParen);
15195             }
15196           }
15197
15198           function skewX(a, b, s, q) {
15199             if (a !== b) {
15200               q.push({
15201                 i: s.push(pop(s) + "skewX(", null, degParen) - 2,
15202                 x: d3_interpolateNumber(a, b)
15203               });
15204             } else if (b) {
15205               s.push(pop(s) + "skewX(" + b + degParen);
15206             }
15207           }
15208
15209           function scale(xa, ya, xb, yb, s, q) {
15210             if (xa !== xb || ya !== yb) {
15211               var i = s.push(pop(s) + "scale(", null, ",", null, ")");
15212               q.push({
15213                 i: i - 4,
15214                 x: d3_interpolateNumber(xa, xb)
15215               }, {
15216                 i: i - 2,
15217                 x: d3_interpolateNumber(ya, yb)
15218               });
15219             } else if (xb !== 1 || yb !== 1) {
15220               s.push(pop(s) + "scale(" + xb + "," + yb + ")");
15221             }
15222           }
15223
15224           return function (a, b) {
15225             var s = [],
15226                 // string constants and placeholders
15227             q = []; // number interpolators
15228
15229             a = parse(a), b = parse(b);
15230             translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
15231             rotate(a.rotate, b.rotate, s, q);
15232             skewX(a.skewX, b.skewX, s, q);
15233             scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
15234             a = b = null; // gc
15235
15236             return function (t) {
15237               var i = -1,
15238                   n = q.length,
15239                   o;
15240
15241               while (++i < n) {
15242                 s[(o = q[i]).i] = o.x(t);
15243               }
15244
15245               return s.join("");
15246             };
15247           };
15248         }
15249
15250         var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
15251         var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
15252
15253         var epsilon2$1 = 1e-12;
15254
15255         function cosh(x) {
15256           return ((x = Math.exp(x)) + 1 / x) / 2;
15257         }
15258
15259         function sinh(x) {
15260           return ((x = Math.exp(x)) - 1 / x) / 2;
15261         }
15262
15263         function tanh(x) {
15264           return ((x = Math.exp(2 * x)) - 1) / (x + 1);
15265         }
15266
15267         var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
15268           // p0 = [ux0, uy0, w0]
15269           // p1 = [ux1, uy1, w1]
15270           function zoom(p0, p1) {
15271             var ux0 = p0[0],
15272                 uy0 = p0[1],
15273                 w0 = p0[2],
15274                 ux1 = p1[0],
15275                 uy1 = p1[1],
15276                 w1 = p1[2],
15277                 dx = ux1 - ux0,
15278                 dy = uy1 - uy0,
15279                 d2 = dx * dx + dy * dy,
15280                 i,
15281                 S; // Special case for u0 ≅ u1.
15282
15283             if (d2 < epsilon2$1) {
15284               S = Math.log(w1 / w0) / rho;
15285
15286               i = function i(t) {
15287                 return [ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S)];
15288               };
15289             } // General case.
15290             else {
15291                 var d1 = Math.sqrt(d2),
15292                     b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
15293                     b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
15294                     r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
15295                     r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
15296                 S = (r1 - r0) / rho;
15297
15298                 i = function i(t) {
15299                   var s = t * S,
15300                       coshr0 = cosh(r0),
15301                       u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
15302                   return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0)];
15303                 };
15304               }
15305
15306             i.duration = S * 1000 * rho / Math.SQRT2;
15307             return i;
15308           }
15309
15310           zoom.rho = function (_) {
15311             var _1 = Math.max(1e-3, +_),
15312                 _2 = _1 * _1,
15313                 _4 = _2 * _2;
15314
15315             return zoomRho(_1, _2, _4);
15316           };
15317
15318           return zoom;
15319         })(Math.SQRT2, 2, 4);
15320
15321         function d3_quantize (interpolator, n) {
15322           var samples = new Array(n);
15323
15324           for (var i = 0; i < n; ++i) {
15325             samples[i] = interpolator(i / (n - 1));
15326           }
15327
15328           return samples;
15329         }
15330
15331         // `Function.prototype.bind` method
15332         // https://tc39.es/ecma262/#sec-function.prototype.bind
15333         _export({ target: 'Function', proto: true }, {
15334           bind: functionBind
15335         });
15336
15337         var frame = 0,
15338             // is an animation frame pending?
15339         timeout = 0,
15340             // is a timeout pending?
15341         interval = 0,
15342             // are any timers active?
15343         pokeDelay = 1000,
15344             // how frequently we check for clock skew
15345         taskHead,
15346             taskTail,
15347             clockLast = 0,
15348             clockNow = 0,
15349             clockSkew = 0,
15350             clock = (typeof performance === "undefined" ? "undefined" : _typeof(performance)) === "object" && performance.now ? performance : Date,
15351             setFrame = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function (f) {
15352           setTimeout(f, 17);
15353         };
15354         function now() {
15355           return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
15356         }
15357
15358         function clearNow() {
15359           clockNow = 0;
15360         }
15361
15362         function Timer() {
15363           this._call = this._time = this._next = null;
15364         }
15365         Timer.prototype = timer.prototype = {
15366           constructor: Timer,
15367           restart: function restart(callback, delay, time) {
15368             if (typeof callback !== "function") throw new TypeError("callback is not a function");
15369             time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
15370
15371             if (!this._next && taskTail !== this) {
15372               if (taskTail) taskTail._next = this;else taskHead = this;
15373               taskTail = this;
15374             }
15375
15376             this._call = callback;
15377             this._time = time;
15378             sleep();
15379           },
15380           stop: function stop() {
15381             if (this._call) {
15382               this._call = null;
15383               this._time = Infinity;
15384               sleep();
15385             }
15386           }
15387         };
15388         function timer(callback, delay, time) {
15389           var t = new Timer();
15390           t.restart(callback, delay, time);
15391           return t;
15392         }
15393         function timerFlush() {
15394           now(); // Get the current time, if not already set.
15395
15396           ++frame; // Pretend we’ve set an alarm, if we haven’t already.
15397
15398           var t = taskHead,
15399               e;
15400
15401           while (t) {
15402             if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
15403             t = t._next;
15404           }
15405
15406           --frame;
15407         }
15408
15409         function wake() {
15410           clockNow = (clockLast = clock.now()) + clockSkew;
15411           frame = timeout = 0;
15412
15413           try {
15414             timerFlush();
15415           } finally {
15416             frame = 0;
15417             nap();
15418             clockNow = 0;
15419           }
15420         }
15421
15422         function poke() {
15423           var now = clock.now(),
15424               delay = now - clockLast;
15425           if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
15426         }
15427
15428         function nap() {
15429           var t0,
15430               t1 = taskHead,
15431               t2,
15432               time = Infinity;
15433
15434           while (t1) {
15435             if (t1._call) {
15436               if (time > t1._time) time = t1._time;
15437               t0 = t1, t1 = t1._next;
15438             } else {
15439               t2 = t1._next, t1._next = null;
15440               t1 = t0 ? t0._next = t2 : taskHead = t2;
15441             }
15442           }
15443
15444           taskTail = t0;
15445           sleep(time);
15446         }
15447
15448         function sleep(time) {
15449           if (frame) return; // Soonest alarm already set, or will be.
15450
15451           if (timeout) timeout = clearTimeout(timeout);
15452           var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
15453
15454           if (delay > 24) {
15455             if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
15456             if (interval) interval = clearInterval(interval);
15457           } else {
15458             if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
15459             frame = 1, setFrame(wake);
15460           }
15461         }
15462
15463         function d3_timeout (callback, delay, time) {
15464           var t = new Timer();
15465           delay = delay == null ? 0 : +delay;
15466           t.restart(function (elapsed) {
15467             t.stop();
15468             callback(elapsed + delay);
15469           }, delay, time);
15470           return t;
15471         }
15472
15473         var emptyOn = dispatch("start", "end", "cancel", "interrupt");
15474         var emptyTween = [];
15475         var CREATED = 0;
15476         var SCHEDULED = 1;
15477         var STARTING = 2;
15478         var STARTED = 3;
15479         var RUNNING = 4;
15480         var ENDING = 5;
15481         var ENDED = 6;
15482         function schedule (node, name, id, index, group, timing) {
15483           var schedules = node.__transition;
15484           if (!schedules) node.__transition = {};else if (id in schedules) return;
15485           create(node, id, {
15486             name: name,
15487             index: index,
15488             // For context during callback.
15489             group: group,
15490             // For context during callback.
15491             on: emptyOn,
15492             tween: emptyTween,
15493             time: timing.time,
15494             delay: timing.delay,
15495             duration: timing.duration,
15496             ease: timing.ease,
15497             timer: null,
15498             state: CREATED
15499           });
15500         }
15501         function init(node, id) {
15502           var schedule = get$4(node, id);
15503           if (schedule.state > CREATED) throw new Error("too late; already scheduled");
15504           return schedule;
15505         }
15506         function set$4(node, id) {
15507           var schedule = get$4(node, id);
15508           if (schedule.state > STARTED) throw new Error("too late; already running");
15509           return schedule;
15510         }
15511         function get$4(node, id) {
15512           var schedule = node.__transition;
15513           if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
15514           return schedule;
15515         }
15516
15517         function create(node, id, self) {
15518           var schedules = node.__transition,
15519               tween; // Initialize the self timer when the transition is created.
15520           // Note the actual delay is not known until the first callback!
15521
15522           schedules[id] = self;
15523           self.timer = timer(schedule, 0, self.time);
15524
15525           function schedule(elapsed) {
15526             self.state = SCHEDULED;
15527             self.timer.restart(start, self.delay, self.time); // If the elapsed delay is less than our first sleep, start immediately.
15528
15529             if (self.delay <= elapsed) start(elapsed - self.delay);
15530           }
15531
15532           function start(elapsed) {
15533             var i, j, n, o; // If the state is not SCHEDULED, then we previously errored on start.
15534
15535             if (self.state !== SCHEDULED) return stop();
15536
15537             for (i in schedules) {
15538               o = schedules[i];
15539               if (o.name !== self.name) continue; // While this element already has a starting transition during this frame,
15540               // defer starting an interrupting transition until that transition has a
15541               // chance to tick (and possibly end); see d3/d3-transition#54!
15542
15543               if (o.state === STARTED) return d3_timeout(start); // Interrupt the active transition, if any.
15544
15545               if (o.state === RUNNING) {
15546                 o.state = ENDED;
15547                 o.timer.stop();
15548                 o.on.call("interrupt", node, node.__data__, o.index, o.group);
15549                 delete schedules[i];
15550               } // Cancel any pre-empted transitions.
15551               else if (+i < id) {
15552                   o.state = ENDED;
15553                   o.timer.stop();
15554                   o.on.call("cancel", node, node.__data__, o.index, o.group);
15555                   delete schedules[i];
15556                 }
15557             } // Defer the first tick to end of the current frame; see d3/d3#1576.
15558             // Note the transition may be canceled after start and before the first tick!
15559             // Note this must be scheduled before the start event; see d3/d3-transition#16!
15560             // Assuming this is successful, subsequent callbacks go straight to tick.
15561
15562
15563             d3_timeout(function () {
15564               if (self.state === STARTED) {
15565                 self.state = RUNNING;
15566                 self.timer.restart(tick, self.delay, self.time);
15567                 tick(elapsed);
15568               }
15569             }); // Dispatch the start event.
15570             // Note this must be done before the tween are initialized.
15571
15572             self.state = STARTING;
15573             self.on.call("start", node, node.__data__, self.index, self.group);
15574             if (self.state !== STARTING) return; // interrupted
15575
15576             self.state = STARTED; // Initialize the tween, deleting null tween.
15577
15578             tween = new Array(n = self.tween.length);
15579
15580             for (i = 0, j = -1; i < n; ++i) {
15581               if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
15582                 tween[++j] = o;
15583               }
15584             }
15585
15586             tween.length = j + 1;
15587           }
15588
15589           function tick(elapsed) {
15590             var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
15591                 i = -1,
15592                 n = tween.length;
15593
15594             while (++i < n) {
15595               tween[i].call(node, t);
15596             } // Dispatch the end event.
15597
15598
15599             if (self.state === ENDING) {
15600               self.on.call("end", node, node.__data__, self.index, self.group);
15601               stop();
15602             }
15603           }
15604
15605           function stop() {
15606             self.state = ENDED;
15607             self.timer.stop();
15608             delete schedules[id];
15609
15610             for (var i in schedules) {
15611               return;
15612             } // eslint-disable-line no-unused-vars
15613
15614
15615             delete node.__transition;
15616           }
15617         }
15618
15619         function interrupt (node, name) {
15620           var schedules = node.__transition,
15621               schedule,
15622               active,
15623               empty = true,
15624               i;
15625           if (!schedules) return;
15626           name = name == null ? null : name + "";
15627
15628           for (i in schedules) {
15629             if ((schedule = schedules[i]).name !== name) {
15630               empty = false;
15631               continue;
15632             }
15633
15634             active = schedule.state > STARTING && schedule.state < ENDING;
15635             schedule.state = ENDED;
15636             schedule.timer.stop();
15637             schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
15638             delete schedules[i];
15639           }
15640
15641           if (empty) delete node.__transition;
15642         }
15643
15644         function selection_interrupt (name) {
15645           return this.each(function () {
15646             interrupt(this, name);
15647           });
15648         }
15649
15650         function tweenRemove(id, name) {
15651           var tween0, tween1;
15652           return function () {
15653             var schedule = set$4(this, id),
15654                 tween = schedule.tween; // If this node shared tween with the previous node,
15655             // just assign the updated shared tween and we’re done!
15656             // Otherwise, copy-on-write.
15657
15658             if (tween !== tween0) {
15659               tween1 = tween0 = tween;
15660
15661               for (var i = 0, n = tween1.length; i < n; ++i) {
15662                 if (tween1[i].name === name) {
15663                   tween1 = tween1.slice();
15664                   tween1.splice(i, 1);
15665                   break;
15666                 }
15667               }
15668             }
15669
15670             schedule.tween = tween1;
15671           };
15672         }
15673
15674         function tweenFunction(id, name, value) {
15675           var tween0, tween1;
15676           if (typeof value !== "function") throw new Error();
15677           return function () {
15678             var schedule = set$4(this, id),
15679                 tween = schedule.tween; // If this node shared tween with the previous node,
15680             // just assign the updated shared tween and we’re done!
15681             // Otherwise, copy-on-write.
15682
15683             if (tween !== tween0) {
15684               tween1 = (tween0 = tween).slice();
15685
15686               for (var t = {
15687                 name: name,
15688                 value: value
15689               }, i = 0, n = tween1.length; i < n; ++i) {
15690                 if (tween1[i].name === name) {
15691                   tween1[i] = t;
15692                   break;
15693                 }
15694               }
15695
15696               if (i === n) tween1.push(t);
15697             }
15698
15699             schedule.tween = tween1;
15700           };
15701         }
15702
15703         function transition_tween (name, value) {
15704           var id = this._id;
15705           name += "";
15706
15707           if (arguments.length < 2) {
15708             var tween = get$4(this.node(), id).tween;
15709
15710             for (var i = 0, n = tween.length, t; i < n; ++i) {
15711               if ((t = tween[i]).name === name) {
15712                 return t.value;
15713               }
15714             }
15715
15716             return null;
15717           }
15718
15719           return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
15720         }
15721         function tweenValue(transition, name, value) {
15722           var id = transition._id;
15723           transition.each(function () {
15724             var schedule = set$4(this, id);
15725             (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
15726           });
15727           return function (node) {
15728             return get$4(node, id).value[name];
15729           };
15730         }
15731
15732         function interpolate$1 (a, b) {
15733           var c;
15734           return (typeof b === "number" ? d3_interpolateNumber : b instanceof color ? d3_interpolateRgb : (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString)(a, b);
15735         }
15736
15737         function attrRemove$1(name) {
15738           return function () {
15739             this.removeAttribute(name);
15740           };
15741         }
15742
15743         function attrRemoveNS$1(fullname) {
15744           return function () {
15745             this.removeAttributeNS(fullname.space, fullname.local);
15746           };
15747         }
15748
15749         function attrConstant$1(name, interpolate, value1) {
15750           var string00,
15751               string1 = value1 + "",
15752               interpolate0;
15753           return function () {
15754             var string0 = this.getAttribute(name);
15755             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15756           };
15757         }
15758
15759         function attrConstantNS$1(fullname, interpolate, value1) {
15760           var string00,
15761               string1 = value1 + "",
15762               interpolate0;
15763           return function () {
15764             var string0 = this.getAttributeNS(fullname.space, fullname.local);
15765             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15766           };
15767         }
15768
15769         function attrFunction$1(name, interpolate, value) {
15770           var string00, string10, interpolate0;
15771           return function () {
15772             var string0,
15773                 value1 = value(this),
15774                 string1;
15775             if (value1 == null) return void this.removeAttribute(name);
15776             string0 = this.getAttribute(name);
15777             string1 = value1 + "";
15778             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
15779           };
15780         }
15781
15782         function attrFunctionNS$1(fullname, interpolate, value) {
15783           var string00, string10, interpolate0;
15784           return function () {
15785             var string0,
15786                 value1 = value(this),
15787                 string1;
15788             if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
15789             string0 = this.getAttributeNS(fullname.space, fullname.local);
15790             string1 = value1 + "";
15791             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
15792           };
15793         }
15794
15795         function transition_attr (name, value) {
15796           var fullname = namespace(name),
15797               i = fullname === "transform" ? interpolateTransformSvg : interpolate$1;
15798           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));
15799         }
15800
15801         function attrInterpolate(name, i) {
15802           return function (t) {
15803             this.setAttribute(name, i.call(this, t));
15804           };
15805         }
15806
15807         function attrInterpolateNS(fullname, i) {
15808           return function (t) {
15809             this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
15810           };
15811         }
15812
15813         function attrTweenNS(fullname, value) {
15814           var t0, i0;
15815
15816           function tween() {
15817             var i = value.apply(this, arguments);
15818             if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
15819             return t0;
15820           }
15821
15822           tween._value = value;
15823           return tween;
15824         }
15825
15826         function attrTween(name, value) {
15827           var t0, i0;
15828
15829           function tween() {
15830             var i = value.apply(this, arguments);
15831             if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
15832             return t0;
15833           }
15834
15835           tween._value = value;
15836           return tween;
15837         }
15838
15839         function transition_attrTween (name, value) {
15840           var key = "attr." + name;
15841           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
15842           if (value == null) return this.tween(key, null);
15843           if (typeof value !== "function") throw new Error();
15844           var fullname = namespace(name);
15845           return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
15846         }
15847
15848         function delayFunction(id, value) {
15849           return function () {
15850             init(this, id).delay = +value.apply(this, arguments);
15851           };
15852         }
15853
15854         function delayConstant(id, value) {
15855           return value = +value, function () {
15856             init(this, id).delay = value;
15857           };
15858         }
15859
15860         function transition_delay (value) {
15861           var id = this._id;
15862           return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get$4(this.node(), id).delay;
15863         }
15864
15865         function durationFunction(id, value) {
15866           return function () {
15867             set$4(this, id).duration = +value.apply(this, arguments);
15868           };
15869         }
15870
15871         function durationConstant(id, value) {
15872           return value = +value, function () {
15873             set$4(this, id).duration = value;
15874           };
15875         }
15876
15877         function transition_duration (value) {
15878           var id = this._id;
15879           return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get$4(this.node(), id).duration;
15880         }
15881
15882         function easeConstant(id, value) {
15883           if (typeof value !== "function") throw new Error();
15884           return function () {
15885             set$4(this, id).ease = value;
15886           };
15887         }
15888
15889         function transition_ease (value) {
15890           var id = this._id;
15891           return arguments.length ? this.each(easeConstant(id, value)) : get$4(this.node(), id).ease;
15892         }
15893
15894         function easeVarying(id, value) {
15895           return function () {
15896             var v = value.apply(this, arguments);
15897             if (typeof v !== "function") throw new Error();
15898             set$4(this, id).ease = v;
15899           };
15900         }
15901
15902         function transition_easeVarying (value) {
15903           if (typeof value !== "function") throw new Error();
15904           return this.each(easeVarying(this._id, value));
15905         }
15906
15907         function transition_filter (match) {
15908           if (typeof match !== "function") match = matcher(match);
15909
15910           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
15911             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
15912               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
15913                 subgroup.push(node);
15914               }
15915             }
15916           }
15917
15918           return new Transition(subgroups, this._parents, this._name, this._id);
15919         }
15920
15921         function transition_merge (transition) {
15922           if (transition._id !== this._id) throw new Error();
15923
15924           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) {
15925             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
15926               if (node = group0[i] || group1[i]) {
15927                 merge[i] = node;
15928               }
15929             }
15930           }
15931
15932           for (; j < m0; ++j) {
15933             merges[j] = groups0[j];
15934           }
15935
15936           return new Transition(merges, this._parents, this._name, this._id);
15937         }
15938
15939         function start(name) {
15940           return (name + "").trim().split(/^|\s+/).every(function (t) {
15941             var i = t.indexOf(".");
15942             if (i >= 0) t = t.slice(0, i);
15943             return !t || t === "start";
15944           });
15945         }
15946
15947         function onFunction(id, name, listener) {
15948           var on0,
15949               on1,
15950               sit = start(name) ? init : set$4;
15951           return function () {
15952             var schedule = sit(this, id),
15953                 on = schedule.on; // If this node shared a dispatch with the previous node,
15954             // just assign the updated shared dispatch and we’re done!
15955             // Otherwise, copy-on-write.
15956
15957             if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
15958             schedule.on = on1;
15959           };
15960         }
15961
15962         function transition_on (name, listener) {
15963           var id = this._id;
15964           return arguments.length < 2 ? get$4(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
15965         }
15966
15967         function removeFunction(id) {
15968           return function () {
15969             var parent = this.parentNode;
15970
15971             for (var i in this.__transition) {
15972               if (+i !== id) return;
15973             }
15974
15975             if (parent) parent.removeChild(this);
15976           };
15977         }
15978
15979         function transition_remove () {
15980           return this.on("end.remove", removeFunction(this._id));
15981         }
15982
15983         function transition_select (select) {
15984           var name = this._name,
15985               id = this._id;
15986           if (typeof select !== "function") select = selector(select);
15987
15988           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
15989             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
15990               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
15991                 if ("__data__" in node) subnode.__data__ = node.__data__;
15992                 subgroup[i] = subnode;
15993                 schedule(subgroup[i], name, id, i, subgroup, get$4(node, id));
15994               }
15995             }
15996           }
15997
15998           return new Transition(subgroups, this._parents, name, id);
15999         }
16000
16001         function transition_selectAll (select) {
16002           var name = this._name,
16003               id = this._id;
16004           if (typeof select !== "function") select = selectorAll(select);
16005
16006           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
16007             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16008               if (node = group[i]) {
16009                 for (var children = select.call(node, node.__data__, i, group), child, inherit = get$4(node, id), k = 0, l = children.length; k < l; ++k) {
16010                   if (child = children[k]) {
16011                     schedule(child, name, id, k, children, inherit);
16012                   }
16013                 }
16014
16015                 subgroups.push(children);
16016                 parents.push(node);
16017               }
16018             }
16019           }
16020
16021           return new Transition(subgroups, parents, name, id);
16022         }
16023
16024         var Selection$1 = selection.prototype.constructor;
16025         function transition_selection () {
16026           return new Selection$1(this._groups, this._parents);
16027         }
16028
16029         function styleNull(name, interpolate) {
16030           var string00, string10, interpolate0;
16031           return function () {
16032             var string0 = styleValue(this, name),
16033                 string1 = (this.style.removeProperty(name), styleValue(this, name));
16034             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
16035           };
16036         }
16037
16038         function styleRemove$1(name) {
16039           return function () {
16040             this.style.removeProperty(name);
16041           };
16042         }
16043
16044         function styleConstant$1(name, interpolate, value1) {
16045           var string00,
16046               string1 = value1 + "",
16047               interpolate0;
16048           return function () {
16049             var string0 = styleValue(this, name);
16050             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16051           };
16052         }
16053
16054         function styleFunction$1(name, interpolate, value) {
16055           var string00, string10, interpolate0;
16056           return function () {
16057             var string0 = styleValue(this, name),
16058                 value1 = value(this),
16059                 string1 = value1 + "";
16060             if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
16061             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16062           };
16063         }
16064
16065         function styleMaybeRemove(id, name) {
16066           var on0,
16067               on1,
16068               listener0,
16069               key = "style." + name,
16070               event = "end." + key,
16071               remove;
16072           return function () {
16073             var schedule = set$4(this, id),
16074                 on = schedule.on,
16075                 listener = schedule.value[key] == null ? remove || (remove = styleRemove$1(name)) : undefined; // If this node shared a dispatch with the previous node,
16076             // just assign the updated shared dispatch and we’re done!
16077             // Otherwise, copy-on-write.
16078
16079             if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
16080             schedule.on = on1;
16081           };
16082         }
16083
16084         function transition_style (name, value, priority) {
16085           var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$1;
16086           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);
16087         }
16088
16089         function styleInterpolate(name, i, priority) {
16090           return function (t) {
16091             this.style.setProperty(name, i.call(this, t), priority);
16092           };
16093         }
16094
16095         function styleTween(name, value, priority) {
16096           var t, i0;
16097
16098           function tween() {
16099             var i = value.apply(this, arguments);
16100             if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
16101             return t;
16102           }
16103
16104           tween._value = value;
16105           return tween;
16106         }
16107
16108         function transition_styleTween (name, value, priority) {
16109           var key = "style." + (name += "");
16110           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16111           if (value == null) return this.tween(key, null);
16112           if (typeof value !== "function") throw new Error();
16113           return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
16114         }
16115
16116         function textConstant$1(value) {
16117           return function () {
16118             this.textContent = value;
16119           };
16120         }
16121
16122         function textFunction$1(value) {
16123           return function () {
16124             var value1 = value(this);
16125             this.textContent = value1 == null ? "" : value1;
16126           };
16127         }
16128
16129         function transition_text (value) {
16130           return this.tween("text", typeof value === "function" ? textFunction$1(tweenValue(this, "text", value)) : textConstant$1(value == null ? "" : value + ""));
16131         }
16132
16133         function textInterpolate(i) {
16134           return function (t) {
16135             this.textContent = i.call(this, t);
16136           };
16137         }
16138
16139         function textTween(value) {
16140           var t0, i0;
16141
16142           function tween() {
16143             var i = value.apply(this, arguments);
16144             if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
16145             return t0;
16146           }
16147
16148           tween._value = value;
16149           return tween;
16150         }
16151
16152         function transition_textTween (value) {
16153           var key = "text";
16154           if (arguments.length < 1) return (key = this.tween(key)) && key._value;
16155           if (value == null) return this.tween(key, null);
16156           if (typeof value !== "function") throw new Error();
16157           return this.tween(key, textTween(value));
16158         }
16159
16160         function transition_transition () {
16161           var name = this._name,
16162               id0 = this._id,
16163               id1 = newId();
16164
16165           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16166             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16167               if (node = group[i]) {
16168                 var inherit = get$4(node, id0);
16169                 schedule(node, name, id1, i, group, {
16170                   time: inherit.time + inherit.delay + inherit.duration,
16171                   delay: 0,
16172                   duration: inherit.duration,
16173                   ease: inherit.ease
16174                 });
16175               }
16176             }
16177           }
16178
16179           return new Transition(groups, this._parents, name, id1);
16180         }
16181
16182         function transition_end () {
16183           var on0,
16184               on1,
16185               that = this,
16186               id = that._id,
16187               size = that.size();
16188           return new Promise(function (resolve, reject) {
16189             var cancel = {
16190               value: reject
16191             },
16192                 end = {
16193               value: function value() {
16194                 if (--size === 0) resolve();
16195               }
16196             };
16197             that.each(function () {
16198               var schedule = set$4(this, id),
16199                   on = schedule.on; // If this node shared a dispatch with the previous node,
16200               // just assign the updated shared dispatch and we’re done!
16201               // Otherwise, copy-on-write.
16202
16203               if (on !== on0) {
16204                 on1 = (on0 = on).copy();
16205
16206                 on1._.cancel.push(cancel);
16207
16208                 on1._.interrupt.push(cancel);
16209
16210                 on1._.end.push(end);
16211               }
16212
16213               schedule.on = on1;
16214             }); // The selection was empty, resolve end immediately
16215
16216             if (size === 0) resolve();
16217           });
16218         }
16219
16220         var id$1 = 0;
16221         function Transition(groups, parents, name, id) {
16222           this._groups = groups;
16223           this._parents = parents;
16224           this._name = name;
16225           this._id = id;
16226         }
16227         function transition(name) {
16228           return selection().transition(name);
16229         }
16230         function newId() {
16231           return ++id$1;
16232         }
16233         var selection_prototype = selection.prototype;
16234         Transition.prototype = transition.prototype = _defineProperty({
16235           constructor: Transition,
16236           select: transition_select,
16237           selectAll: transition_selectAll,
16238           filter: transition_filter,
16239           merge: transition_merge,
16240           selection: transition_selection,
16241           transition: transition_transition,
16242           call: selection_prototype.call,
16243           nodes: selection_prototype.nodes,
16244           node: selection_prototype.node,
16245           size: selection_prototype.size,
16246           empty: selection_prototype.empty,
16247           each: selection_prototype.each,
16248           on: transition_on,
16249           attr: transition_attr,
16250           attrTween: transition_attrTween,
16251           style: transition_style,
16252           styleTween: transition_styleTween,
16253           text: transition_text,
16254           textTween: transition_textTween,
16255           remove: transition_remove,
16256           tween: transition_tween,
16257           delay: transition_delay,
16258           duration: transition_duration,
16259           ease: transition_ease,
16260           easeVarying: transition_easeVarying,
16261           end: transition_end
16262         }, Symbol.iterator, selection_prototype[Symbol.iterator]);
16263
16264         var linear$1 = function linear(t) {
16265           return +t;
16266         };
16267
16268         function cubicInOut(t) {
16269           return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
16270         }
16271
16272         var defaultTiming = {
16273           time: null,
16274           // Set on use.
16275           delay: 0,
16276           duration: 250,
16277           ease: cubicInOut
16278         };
16279
16280         function inherit(node, id) {
16281           var timing;
16282
16283           while (!(timing = node.__transition) || !(timing = timing[id])) {
16284             if (!(node = node.parentNode)) {
16285               throw new Error("transition ".concat(id, " not found"));
16286             }
16287           }
16288
16289           return timing;
16290         }
16291
16292         function selection_transition (name) {
16293           var id, timing;
16294
16295           if (name instanceof Transition) {
16296             id = name._id, name = name._name;
16297           } else {
16298             id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
16299           }
16300
16301           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16302             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16303               if (node = group[i]) {
16304                 schedule(node, name, id, i, group, timing || inherit(node, id));
16305               }
16306             }
16307           }
16308
16309           return new Transition(groups, this._parents, name, id);
16310         }
16311
16312         selection.prototype.interrupt = selection_interrupt;
16313         selection.prototype.transition = selection_transition;
16314
16315         var constant$3 = (function (x) {
16316           return function () {
16317             return x;
16318           };
16319         });
16320
16321         function ZoomEvent(type, _ref) {
16322           var sourceEvent = _ref.sourceEvent,
16323               target = _ref.target,
16324               transform = _ref.transform,
16325               dispatch = _ref.dispatch;
16326           Object.defineProperties(this, {
16327             type: {
16328               value: type,
16329               enumerable: true,
16330               configurable: true
16331             },
16332             sourceEvent: {
16333               value: sourceEvent,
16334               enumerable: true,
16335               configurable: true
16336             },
16337             target: {
16338               value: target,
16339               enumerable: true,
16340               configurable: true
16341             },
16342             transform: {
16343               value: transform,
16344               enumerable: true,
16345               configurable: true
16346             },
16347             _: {
16348               value: dispatch
16349             }
16350           });
16351         }
16352
16353         function Transform(k, x, y) {
16354           this.k = k;
16355           this.x = x;
16356           this.y = y;
16357         }
16358         Transform.prototype = {
16359           constructor: Transform,
16360           scale: function scale(k) {
16361             return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
16362           },
16363           translate: function translate(x, y) {
16364             return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
16365           },
16366           apply: function apply(point) {
16367             return [point[0] * this.k + this.x, point[1] * this.k + this.y];
16368           },
16369           applyX: function applyX(x) {
16370             return x * this.k + this.x;
16371           },
16372           applyY: function applyY(y) {
16373             return y * this.k + this.y;
16374           },
16375           invert: function invert(location) {
16376             return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
16377           },
16378           invertX: function invertX(x) {
16379             return (x - this.x) / this.k;
16380           },
16381           invertY: function invertY(y) {
16382             return (y - this.y) / this.k;
16383           },
16384           rescaleX: function rescaleX(x) {
16385             return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
16386           },
16387           rescaleY: function rescaleY(y) {
16388             return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
16389           },
16390           toString: function toString() {
16391             return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
16392           }
16393         };
16394         var identity$2 = new Transform(1, 0, 0);
16395
16396         function nopropagation$1(event) {
16397           event.stopImmediatePropagation();
16398         }
16399         function noevent$1 (event) {
16400           event.preventDefault();
16401           event.stopImmediatePropagation();
16402         }
16403
16404         // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
16405
16406         function defaultFilter$1(event) {
16407           return (!event.ctrlKey || event.type === 'wheel') && !event.button;
16408         }
16409
16410         function defaultExtent() {
16411           var e = this;
16412
16413           if (e instanceof SVGElement) {
16414             e = e.ownerSVGElement || e;
16415
16416             if (e.hasAttribute("viewBox")) {
16417               e = e.viewBox.baseVal;
16418               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
16419             }
16420
16421             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
16422           }
16423
16424           return [[0, 0], [e.clientWidth, e.clientHeight]];
16425         }
16426
16427         function defaultTransform() {
16428           return this.__zoom || identity$2;
16429         }
16430
16431         function defaultWheelDelta(event) {
16432           return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
16433         }
16434
16435         function defaultTouchable$1() {
16436           return navigator.maxTouchPoints || "ontouchstart" in this;
16437         }
16438
16439         function defaultConstrain(transform, extent, translateExtent) {
16440           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
16441               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
16442               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
16443               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
16444           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));
16445         }
16446
16447         function d3_zoom () {
16448           var filter = defaultFilter$1,
16449               extent = defaultExtent,
16450               constrain = defaultConstrain,
16451               wheelDelta = defaultWheelDelta,
16452               touchable = defaultTouchable$1,
16453               scaleExtent = [0, Infinity],
16454               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
16455               duration = 250,
16456               interpolate = interpolateZoom,
16457               listeners = dispatch("start", "zoom", "end"),
16458               touchstarting,
16459               touchfirst,
16460               touchending,
16461               touchDelay = 500,
16462               wheelDelay = 150,
16463               clickDistance2 = 0,
16464               tapDistance = 10;
16465
16466           function zoom(selection) {
16467             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)");
16468           }
16469
16470           zoom.transform = function (collection, transform, point, event) {
16471             var selection = collection.selection ? collection.selection() : collection;
16472             selection.property("__zoom", defaultTransform);
16473
16474             if (collection !== selection) {
16475               schedule(collection, transform, point, event);
16476             } else {
16477               selection.interrupt().each(function () {
16478                 gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
16479               });
16480             }
16481           };
16482
16483           zoom.scaleBy = function (selection, k, p, event) {
16484             zoom.scaleTo(selection, function () {
16485               var k0 = this.__zoom.k,
16486                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16487               return k0 * k1;
16488             }, p, event);
16489           };
16490
16491           zoom.scaleTo = function (selection, k, p, event) {
16492             zoom.transform(selection, function () {
16493               var e = extent.apply(this, arguments),
16494                   t0 = this.__zoom,
16495                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p,
16496                   p1 = t0.invert(p0),
16497                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16498               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
16499             }, p, event);
16500           };
16501
16502           zoom.translateBy = function (selection, x, y, event) {
16503             zoom.transform(selection, function () {
16504               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);
16505             }, null, event);
16506           };
16507
16508           zoom.translateTo = function (selection, x, y, p, event) {
16509             zoom.transform(selection, function () {
16510               var e = extent.apply(this, arguments),
16511                   t = this.__zoom,
16512                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
16513               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);
16514             }, p, event);
16515           };
16516
16517           function scale(transform, k) {
16518             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
16519             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
16520           }
16521
16522           function translate(transform, p0, p1) {
16523             var x = p0[0] - p1[0] * transform.k,
16524                 y = p0[1] - p1[1] * transform.k;
16525             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
16526           }
16527
16528           function centroid(extent) {
16529             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
16530           }
16531
16532           function schedule(transition, transform, point, event) {
16533             transition.on("start.zoom", function () {
16534               gesture(this, arguments).event(event).start();
16535             }).on("interrupt.zoom end.zoom", function () {
16536               gesture(this, arguments).event(event).end();
16537             }).tween("zoom", function () {
16538               var that = this,
16539                   args = arguments,
16540                   g = gesture(that, args).event(event),
16541                   e = extent.apply(that, args),
16542                   p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
16543                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
16544                   a = that.__zoom,
16545                   b = typeof transform === "function" ? transform.apply(that, args) : transform,
16546                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
16547               return function (t) {
16548                 if (t === 1) t = b; // Avoid rounding error on end.
16549                 else {
16550                     var l = i(t),
16551                         k = w / l[2];
16552                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
16553                   }
16554                 g.zoom(null, t);
16555               };
16556             });
16557           }
16558
16559           function gesture(that, args, clean) {
16560             return !clean && that.__zooming || new Gesture(that, args);
16561           }
16562
16563           function Gesture(that, args) {
16564             this.that = that;
16565             this.args = args;
16566             this.active = 0;
16567             this.sourceEvent = null;
16568             this.extent = extent.apply(that, args);
16569             this.taps = 0;
16570           }
16571
16572           Gesture.prototype = {
16573             event: function event(_event) {
16574               if (_event) this.sourceEvent = _event;
16575               return this;
16576             },
16577             start: function start() {
16578               if (++this.active === 1) {
16579                 this.that.__zooming = this;
16580                 this.emit("start");
16581               }
16582
16583               return this;
16584             },
16585             zoom: function zoom(key, transform) {
16586               if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
16587               if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
16588               if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
16589               this.that.__zoom = transform;
16590               this.emit("zoom");
16591               return this;
16592             },
16593             end: function end() {
16594               if (--this.active === 0) {
16595                 delete this.that.__zooming;
16596                 this.emit("end");
16597               }
16598
16599               return this;
16600             },
16601             emit: function emit(type) {
16602               var d = select(this.that).datum();
16603               listeners.call(type, this.that, new ZoomEvent(type, {
16604                 sourceEvent: this.sourceEvent,
16605                 target: zoom,
16606                 type: type,
16607                 transform: this.that.__zoom,
16608                 dispatch: listeners
16609               }), d);
16610             }
16611           };
16612
16613           function wheeled(event) {
16614             for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
16615               args[_key - 1] = arguments[_key];
16616             }
16617
16618             if (!filter.apply(this, arguments)) return;
16619             var g = gesture(this, args).event(event),
16620                 t = this.__zoom,
16621                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
16622                 p = pointer(event); // If the mouse is in the same location as before, reuse it.
16623             // If there were recent wheel events, reset the wheel idle timeout.
16624
16625             if (g.wheel) {
16626               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
16627                 g.mouse[1] = t.invert(g.mouse[0] = p);
16628               }
16629
16630               clearTimeout(g.wheel);
16631             } // If this wheel event won’t trigger a transform change, ignore it.
16632             else if (t.k === k) return; // Otherwise, capture the mouse point and location at the start.
16633               else {
16634                   g.mouse = [p, t.invert(p)];
16635                   interrupt(this);
16636                   g.start();
16637                 }
16638
16639             noevent$1(event);
16640             g.wheel = setTimeout(wheelidled, wheelDelay);
16641             g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
16642
16643             function wheelidled() {
16644               g.wheel = null;
16645               g.end();
16646             }
16647           }
16648
16649           function mousedowned(event) {
16650             for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
16651               args[_key2 - 1] = arguments[_key2];
16652             }
16653
16654             if (touchending || !filter.apply(this, arguments)) return;
16655             var g = gesture(this, args, true).event(event),
16656                 v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
16657                 p = pointer(event, currentTarget),
16658                 currentTarget = event.currentTarget,
16659                 x0 = event.clientX,
16660                 y0 = event.clientY;
16661             dragDisable(event.view);
16662             nopropagation$1(event);
16663             g.mouse = [p, this.__zoom.invert(p)];
16664             interrupt(this);
16665             g.start();
16666
16667             function mousemoved(event) {
16668               noevent$1(event);
16669
16670               if (!g.moved) {
16671                 var dx = event.clientX - x0,
16672                     dy = event.clientY - y0;
16673                 g.moved = dx * dx + dy * dy > clickDistance2;
16674               }
16675
16676               g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
16677             }
16678
16679             function mouseupped(event) {
16680               v.on("mousemove.zoom mouseup.zoom", null);
16681               yesdrag(event.view, g.moved);
16682               noevent$1(event);
16683               g.event(event).end();
16684             }
16685           }
16686
16687           function dblclicked(event) {
16688             for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
16689               args[_key3 - 1] = arguments[_key3];
16690             }
16691
16692             if (!filter.apply(this, arguments)) return;
16693             var t0 = this.__zoom,
16694                 p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
16695                 p1 = t0.invert(p0),
16696                 k1 = t0.k * (event.shiftKey ? 0.5 : 2),
16697                 t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
16698             noevent$1(event);
16699             if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);else select(this).call(zoom.transform, t1, p0, event);
16700           }
16701
16702           function touchstarted(event) {
16703             for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
16704               args[_key4 - 1] = arguments[_key4];
16705             }
16706
16707             if (!filter.apply(this, arguments)) return;
16708             var touches = event.touches,
16709                 n = touches.length,
16710                 g = gesture(this, args, event.changedTouches.length === n).event(event),
16711                 started,
16712                 i,
16713                 t,
16714                 p;
16715             nopropagation$1(event);
16716
16717             for (i = 0; i < n; ++i) {
16718               t = touches[i], p = pointer(t, this);
16719               p = [p, this.__zoom.invert(p), t.identifier];
16720               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;
16721             }
16722
16723             if (touchstarting) touchstarting = clearTimeout(touchstarting);
16724
16725             if (started) {
16726               if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function () {
16727                 touchstarting = null;
16728               }, touchDelay);
16729               interrupt(this);
16730               g.start();
16731             }
16732           }
16733
16734           function touchmoved(event) {
16735             if (!this.__zooming) return;
16736
16737             for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
16738               args[_key5 - 1] = arguments[_key5];
16739             }
16740
16741             var g = gesture(this, args).event(event),
16742                 touches = event.changedTouches,
16743                 n = touches.length,
16744                 i,
16745                 t,
16746                 p,
16747                 l;
16748             noevent$1(event);
16749
16750             for (i = 0; i < n; ++i) {
16751               t = touches[i], p = pointer(t, this);
16752               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;
16753             }
16754
16755             t = g.that.__zoom;
16756
16757             if (g.touch1) {
16758               var p0 = g.touch0[0],
16759                   l0 = g.touch0[1],
16760                   p1 = g.touch1[0],
16761                   l1 = g.touch1[1],
16762                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
16763                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
16764               t = scale(t, Math.sqrt(dp / dl));
16765               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
16766               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
16767             } else if (g.touch0) p = g.touch0[0], l = g.touch0[1];else return;
16768
16769             g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
16770           }
16771
16772           function touchended(event) {
16773             for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
16774               args[_key6 - 1] = arguments[_key6];
16775             }
16776
16777             if (!this.__zooming) return;
16778             var g = gesture(this, args).event(event),
16779                 touches = event.changedTouches,
16780                 n = touches.length,
16781                 i,
16782                 t;
16783             nopropagation$1(event);
16784             if (touchending) clearTimeout(touchending);
16785             touchending = setTimeout(function () {
16786               touchending = null;
16787             }, touchDelay);
16788
16789             for (i = 0; i < n; ++i) {
16790               t = touches[i];
16791               if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
16792             }
16793
16794             if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
16795             if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);else {
16796               g.end(); // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
16797
16798               if (g.taps === 2) {
16799                 t = pointer(t, this);
16800
16801                 if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
16802                   var p = select(this).on("dblclick.zoom");
16803                   if (p) p.apply(this, arguments);
16804                 }
16805               }
16806             }
16807           }
16808
16809           zoom.wheelDelta = function (_) {
16810             return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant$3(+_), zoom) : wheelDelta;
16811           };
16812
16813           zoom.filter = function (_) {
16814             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$3(!!_), zoom) : filter;
16815           };
16816
16817           zoom.touchable = function (_) {
16818             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$3(!!_), zoom) : touchable;
16819           };
16820
16821           zoom.extent = function (_) {
16822             return arguments.length ? (extent = typeof _ === "function" ? _ : constant$3([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
16823           };
16824
16825           zoom.scaleExtent = function (_) {
16826             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
16827           };
16828
16829           zoom.translateExtent = function (_) {
16830             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]]];
16831           };
16832
16833           zoom.constrain = function (_) {
16834             return arguments.length ? (constrain = _, zoom) : constrain;
16835           };
16836
16837           zoom.duration = function (_) {
16838             return arguments.length ? (duration = +_, zoom) : duration;
16839           };
16840
16841           zoom.interpolate = function (_) {
16842             return arguments.length ? (interpolate = _, zoom) : interpolate;
16843           };
16844
16845           zoom.on = function () {
16846             var value = listeners.on.apply(listeners, arguments);
16847             return value === listeners ? zoom : value;
16848           };
16849
16850           zoom.clickDistance = function (_) {
16851             return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
16852           };
16853
16854           zoom.tapDistance = function (_) {
16855             return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
16856           };
16857
16858           return zoom;
16859         }
16860
16861         /*
16862             Bypasses features of D3's default projection stream pipeline that are unnecessary:
16863             * Antimeridian clipping
16864             * Spherical rotation
16865             * Resampling
16866         */
16867
16868         function geoRawMercator() {
16869           var project = mercatorRaw;
16870           var k = 512 / Math.PI; // scale
16871
16872           var x = 0;
16873           var y = 0; // translate
16874
16875           var clipExtent = [[0, 0], [0, 0]];
16876
16877           function projection(point) {
16878             point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
16879             return [point[0] * k + x, y - point[1] * k];
16880           }
16881
16882           projection.invert = function (point) {
16883             point = project.invert((point[0] - x) / k, (y - point[1]) / k);
16884             return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
16885           };
16886
16887           projection.scale = function (_) {
16888             if (!arguments.length) return k;
16889             k = +_;
16890             return projection;
16891           };
16892
16893           projection.translate = function (_) {
16894             if (!arguments.length) return [x, y];
16895             x = +_[0];
16896             y = +_[1];
16897             return projection;
16898           };
16899
16900           projection.clipExtent = function (_) {
16901             if (!arguments.length) return clipExtent;
16902             clipExtent = _;
16903             return projection;
16904           };
16905
16906           projection.transform = function (obj) {
16907             if (!arguments.length) return identity$2.translate(x, y).scale(k);
16908             x = +obj.x;
16909             y = +obj.y;
16910             k = +obj.k;
16911             return projection;
16912           };
16913
16914           projection.stream = d3_geoTransform({
16915             point: function point(x, y) {
16916               var vec = projection([x, y]);
16917               this.stream.point(vec[0], vec[1]);
16918             }
16919           }).stream;
16920           return projection;
16921         }
16922
16923         function geoOrthoNormalizedDotProduct(a, b, origin) {
16924           if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
16925             return 1; // coincident points, treat as straight and try to remove
16926           }
16927
16928           return geoVecNormalizedDot(a, b, origin);
16929         }
16930
16931         function geoOrthoFilterDotProduct(dotp, epsilon, lowerThreshold, upperThreshold, allowStraightAngles) {
16932           var val = Math.abs(dotp);
16933
16934           if (val < epsilon) {
16935             return 0; // already orthogonal
16936           } else if (allowStraightAngles && Math.abs(val - 1) < epsilon) {
16937             return 0; // straight angle, which is okay in this case
16938           } else if (val < lowerThreshold || val > upperThreshold) {
16939             return dotp; // can be adjusted
16940           } else {
16941             return null; // ignore vertex
16942           }
16943         }
16944
16945         function geoOrthoCalcScore(points, isClosed, epsilon, threshold) {
16946           var score = 0;
16947           var first = isClosed ? 0 : 1;
16948           var last = isClosed ? points.length : points.length - 1;
16949           var coords = points.map(function (p) {
16950             return p.coord;
16951           });
16952           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
16953           var upperThreshold = Math.cos(threshold * Math.PI / 180);
16954
16955           for (var i = first; i < last; i++) {
16956             var a = coords[(i - 1 + coords.length) % coords.length];
16957             var origin = coords[i];
16958             var b = coords[(i + 1) % coords.length];
16959             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold);
16960             if (dotp === null) continue; // ignore vertex
16961
16962             score = score + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
16963           }
16964
16965           return score;
16966         } // returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner
16967
16968         function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) {
16969           var max = -Infinity;
16970           var first = isClosed ? 0 : 1;
16971           var last = isClosed ? coords.length : coords.length - 1;
16972
16973           for (var i = first; i < last; i++) {
16974             var a = coords[(i - 1 + coords.length) % coords.length];
16975             var origin = coords[i];
16976             var b = coords[(i + 1) % coords.length];
16977             var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
16978             var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
16979             if (angle > 45) angle = 90 - angle;
16980             if (angle >= lessThan) continue;
16981             if (angle > max) max = angle;
16982           }
16983
16984           if (max === -Infinity) return null;
16985           return max;
16986         } // similar to geoOrthoCalcScore, but returns quickly if there is something to do
16987
16988         function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) {
16989           var score = null;
16990           var first = isClosed ? 0 : 1;
16991           var last = isClosed ? coords.length : coords.length - 1;
16992           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
16993           var upperThreshold = Math.cos(threshold * Math.PI / 180);
16994
16995           for (var i = first; i < last; i++) {
16996             var a = coords[(i - 1 + coords.length) % coords.length];
16997             var origin = coords[i];
16998             var b = coords[(i + 1) % coords.length];
16999             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold, allowStraightAngles);
17000             if (dotp === null) continue; // ignore vertex
17001
17002             if (Math.abs(dotp) > 0) return 1; // something to do
17003
17004             score = 0; // already square
17005           }
17006
17007           return score;
17008         }
17009
17010         var onFreeze = internalMetadata.onFreeze;
17011
17012         var nativeFreeze = Object.freeze;
17013         var FAILS_ON_PRIMITIVES$4 = fails(function () { nativeFreeze(1); });
17014
17015         // `Object.freeze` method
17016         // https://tc39.es/ecma262/#sec-object.freeze
17017         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4, sham: !freezing }, {
17018           freeze: function freeze(it) {
17019             return nativeFreeze && isObject(it) ? nativeFreeze(onFreeze(it)) : it;
17020           }
17021         });
17022
17023         // Returns true if a and b have the same elements at the same indices.
17024         function utilArrayIdentical(a, b) {
17025           // an array is always identical to itself
17026           if (a === b) return true;
17027           var i = a.length;
17028           if (i !== b.length) return false;
17029
17030           while (i--) {
17031             if (a[i] !== b[i]) return false;
17032           }
17033
17034           return true;
17035         } // http://2ality.com/2015/01/es6-set-operations.html
17036         // Difference (a \ b): create a set that contains those elements of set a that are not in set b.
17037         // This operation is also sometimes called minus (-).
17038         // var a = [1,2,3];
17039         // var b = [4,3,2];
17040         // utilArrayDifference(a, b)
17041         //   [1]
17042         // utilArrayDifference(b, a)
17043         //   [4]
17044
17045         function utilArrayDifference(a, b) {
17046           var other = new Set(b);
17047           return Array.from(new Set(a)).filter(function (v) {
17048             return !other.has(v);
17049           });
17050         } // Intersection (a ∩ b): create a set that contains those elements of set a that are also in set b.
17051         // var a = [1,2,3];
17052         // var b = [4,3,2];
17053         // utilArrayIntersection(a, b)
17054         //   [2,3]
17055
17056         function utilArrayIntersection(a, b) {
17057           var other = new Set(b);
17058           return Array.from(new Set(a)).filter(function (v) {
17059             return other.has(v);
17060           });
17061         } // Union (a ∪ b): create a set that contains the elements of both set a and set b.
17062         // var a = [1,2,3];
17063         // var b = [4,3,2];
17064         // utilArrayUnion(a, b)
17065         //   [1,2,3,4]
17066
17067         function utilArrayUnion(a, b) {
17068           var result = new Set(a);
17069           b.forEach(function (v) {
17070             result.add(v);
17071           });
17072           return Array.from(result);
17073         } // Returns an Array with all the duplicates removed
17074         // var a = [1,1,2,3,3];
17075         // utilArrayUniq(a)
17076         //   [1,2,3]
17077
17078         function utilArrayUniq(a) {
17079           return Array.from(new Set(a));
17080         } // Splits array into chunks of given chunk size
17081         // var a = [1,2,3,4,5,6,7];
17082         // utilArrayChunk(a, 3);
17083         //   [[1,2,3],[4,5,6],[7]];
17084
17085         function utilArrayChunk(a, chunkSize) {
17086           if (!chunkSize || chunkSize < 0) return [a.slice()];
17087           var result = new Array(Math.ceil(a.length / chunkSize));
17088           return Array.from(result, function (item, i) {
17089             return a.slice(i * chunkSize, i * chunkSize + chunkSize);
17090           });
17091         } // Flattens two level array into a single level
17092         // var a = [[1,2,3],[4,5,6],[7]];
17093         // utilArrayFlatten(a);
17094         //   [1,2,3,4,5,6,7];
17095
17096         function utilArrayFlatten(a) {
17097           return a.reduce(function (acc, val) {
17098             return acc.concat(val);
17099           }, []);
17100         } // Groups the items of the Array according to the given key
17101         // `key` can be passed as a property or as a key function
17102         //
17103         // var pets = [
17104         //     { type: 'Dog', name: 'Spot' },
17105         //     { type: 'Cat', name: 'Tiger' },
17106         //     { type: 'Dog', name: 'Rover' },
17107         //     { type: 'Cat', name: 'Leo' }
17108         // ];
17109         //
17110         // utilArrayGroupBy(pets, 'type')
17111         //   {
17112         //     'Dog': [{type: 'Dog', name: 'Spot'}, {type: 'Dog', name: 'Rover'}],
17113         //     'Cat': [{type: 'Cat', name: 'Tiger'}, {type: 'Cat', name: 'Leo'}]
17114         //   }
17115         //
17116         // utilArrayGroupBy(pets, function(item) { return item.name.length; })
17117         //   {
17118         //     3: [{type: 'Cat', name: 'Leo'}],
17119         //     4: [{type: 'Dog', name: 'Spot'}],
17120         //     5: [{type: 'Cat', name: 'Tiger'}, {type: 'Dog', name: 'Rover'}]
17121         //   }
17122
17123         function utilArrayGroupBy(a, key) {
17124           return a.reduce(function (acc, item) {
17125             var group = typeof key === 'function' ? key(item) : item[key];
17126             (acc[group] = acc[group] || []).push(item);
17127             return acc;
17128           }, {});
17129         } // Returns an Array with all the duplicates removed
17130         // where uniqueness determined by the given key
17131         // `key` can be passed as a property or as a key function
17132         //
17133         // var pets = [
17134         //     { type: 'Dog', name: 'Spot' },
17135         //     { type: 'Cat', name: 'Tiger' },
17136         //     { type: 'Dog', name: 'Rover' },
17137         //     { type: 'Cat', name: 'Leo' }
17138         // ];
17139         //
17140         // utilArrayUniqBy(pets, 'type')
17141         //   [
17142         //     { type: 'Dog', name: 'Spot' },
17143         //     { type: 'Cat', name: 'Tiger' }
17144         //   ]
17145         //
17146         // utilArrayUniqBy(pets, function(item) { return item.name.length; })
17147         //   [
17148         //     { type: 'Dog', name: 'Spot' },
17149         //     { type: 'Cat', name: 'Tiger' },
17150         //     { type: 'Cat', name: 'Leo' }
17151         //   }
17152
17153         function utilArrayUniqBy(a, key) {
17154           var seen = new Set();
17155           return a.reduce(function (acc, item) {
17156             var val = typeof key === 'function' ? key(item) : item[key];
17157
17158             if (val && !seen.has(val)) {
17159               seen.add(val);
17160               acc.push(item);
17161             }
17162
17163             return acc;
17164           }, []);
17165         }
17166
17167         // @@match logic
17168         fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
17169           return [
17170             // `String.prototype.match` method
17171             // https://tc39.es/ecma262/#sec-string.prototype.match
17172             function match(regexp) {
17173               var O = requireObjectCoercible(this);
17174               var matcher = regexp == undefined ? undefined : regexp[MATCH];
17175               return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
17176             },
17177             // `RegExp.prototype[@@match]` method
17178             // https://tc39.es/ecma262/#sec-regexp.prototype-@@match
17179             function (regexp) {
17180               var res = maybeCallNative(nativeMatch, regexp, this);
17181               if (res.done) return res.value;
17182
17183               var rx = anObject(regexp);
17184               var S = String(this);
17185
17186               if (!rx.global) return regexpExecAbstract(rx, S);
17187
17188               var fullUnicode = rx.unicode;
17189               rx.lastIndex = 0;
17190               var A = [];
17191               var n = 0;
17192               var result;
17193               while ((result = regexpExecAbstract(rx, S)) !== null) {
17194                 var matchStr = String(result[0]);
17195                 A[n] = matchStr;
17196                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
17197                 n++;
17198               }
17199               return n === 0 ? null : A;
17200             }
17201           ];
17202         });
17203
17204         var remove$1 = removeDiacritics;
17205         var replacementList = [{
17206           base: ' ',
17207           chars: "\xA0"
17208         }, {
17209           base: '0',
17210           chars: "\u07C0"
17211         }, {
17212           base: 'A',
17213           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"
17214         }, {
17215           base: 'AA',
17216           chars: "\uA732"
17217         }, {
17218           base: 'AE',
17219           chars: "\xC6\u01FC\u01E2"
17220         }, {
17221           base: 'AO',
17222           chars: "\uA734"
17223         }, {
17224           base: 'AU',
17225           chars: "\uA736"
17226         }, {
17227           base: 'AV',
17228           chars: "\uA738\uA73A"
17229         }, {
17230           base: 'AY',
17231           chars: "\uA73C"
17232         }, {
17233           base: 'B',
17234           chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"
17235         }, {
17236           base: 'C',
17237           chars: "\u24B8\uFF23\uA73E\u1E08\u0106C\u0108\u010A\u010C\xC7\u0187\u023B"
17238         }, {
17239           base: 'D',
17240           chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"
17241         }, {
17242           base: 'Dh',
17243           chars: "\xD0"
17244         }, {
17245           base: 'DZ',
17246           chars: "\u01F1\u01C4"
17247         }, {
17248           base: 'Dz',
17249           chars: "\u01F2\u01C5"
17250         }, {
17251           base: 'E',
17252           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"
17253         }, {
17254           base: 'F',
17255           chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"
17256         }, {
17257           base: 'G',
17258           chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"
17259         }, {
17260           base: 'H',
17261           chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
17262         }, {
17263           base: 'I',
17264           chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
17265         }, {
17266           base: 'J',
17267           chars: "\u24BF\uFF2A\u0134\u0248\u0237"
17268         }, {
17269           base: 'K',
17270           chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
17271         }, {
17272           base: 'L',
17273           chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
17274         }, {
17275           base: 'LJ',
17276           chars: "\u01C7"
17277         }, {
17278           base: 'Lj',
17279           chars: "\u01C8"
17280         }, {
17281           base: 'M',
17282           chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"
17283         }, {
17284           base: 'N',
17285           chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"
17286         }, {
17287           base: 'NJ',
17288           chars: "\u01CA"
17289         }, {
17290           base: 'Nj',
17291           chars: "\u01CB"
17292         }, {
17293           base: 'O',
17294           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"
17295         }, {
17296           base: 'OE',
17297           chars: "\u0152"
17298         }, {
17299           base: 'OI',
17300           chars: "\u01A2"
17301         }, {
17302           base: 'OO',
17303           chars: "\uA74E"
17304         }, {
17305           base: 'OU',
17306           chars: "\u0222"
17307         }, {
17308           base: 'P',
17309           chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
17310         }, {
17311           base: 'Q',
17312           chars: "\u24C6\uFF31\uA756\uA758\u024A"
17313         }, {
17314           base: 'R',
17315           chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
17316         }, {
17317           base: 'S',
17318           chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
17319         }, {
17320           base: 'T',
17321           chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
17322         }, {
17323           base: 'Th',
17324           chars: "\xDE"
17325         }, {
17326           base: 'TZ',
17327           chars: "\uA728"
17328         }, {
17329           base: 'U',
17330           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"
17331         }, {
17332           base: 'V',
17333           chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
17334         }, {
17335           base: 'VY',
17336           chars: "\uA760"
17337         }, {
17338           base: 'W',
17339           chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
17340         }, {
17341           base: 'X',
17342           chars: "\u24CD\uFF38\u1E8A\u1E8C"
17343         }, {
17344           base: 'Y',
17345           chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
17346         }, {
17347           base: 'Z',
17348           chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
17349         }, {
17350           base: 'a',
17351           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"
17352         }, {
17353           base: 'aa',
17354           chars: "\uA733"
17355         }, {
17356           base: 'ae',
17357           chars: "\xE6\u01FD\u01E3"
17358         }, {
17359           base: 'ao',
17360           chars: "\uA735"
17361         }, {
17362           base: 'au',
17363           chars: "\uA737"
17364         }, {
17365           base: 'av',
17366           chars: "\uA739\uA73B"
17367         }, {
17368           base: 'ay',
17369           chars: "\uA73D"
17370         }, {
17371           base: 'b',
17372           chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"
17373         }, {
17374           base: 'c',
17375           chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\xE7\u1E09\u0188\u023C\uA73F\u2184"
17376         }, {
17377           base: 'd',
17378           chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"
17379         }, {
17380           base: 'dh',
17381           chars: "\xF0"
17382         }, {
17383           base: 'dz',
17384           chars: "\u01F3\u01C6"
17385         }, {
17386           base: 'e',
17387           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"
17388         }, {
17389           base: 'f',
17390           chars: "\u24D5\uFF46\u1E1F\u0192"
17391         }, {
17392           base: 'ff',
17393           chars: "\uFB00"
17394         }, {
17395           base: 'fi',
17396           chars: "\uFB01"
17397         }, {
17398           base: 'fl',
17399           chars: "\uFB02"
17400         }, {
17401           base: 'ffi',
17402           chars: "\uFB03"
17403         }, {
17404           base: 'ffl',
17405           chars: "\uFB04"
17406         }, {
17407           base: 'g',
17408           chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"
17409         }, {
17410           base: 'h',
17411           chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
17412         }, {
17413           base: 'hv',
17414           chars: "\u0195"
17415         }, {
17416           base: 'i',
17417           chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
17418         }, {
17419           base: 'j',
17420           chars: "\u24D9\uFF4A\u0135\u01F0\u0249"
17421         }, {
17422           base: 'k',
17423           chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
17424         }, {
17425           base: 'l',
17426           chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"
17427         }, {
17428           base: 'lj',
17429           chars: "\u01C9"
17430         }, {
17431           base: 'm',
17432           chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
17433         }, {
17434           base: 'n',
17435           chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"
17436         }, {
17437           base: 'nj',
17438           chars: "\u01CC"
17439         }, {
17440           base: 'o',
17441           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"
17442         }, {
17443           base: 'oe',
17444           chars: "\u0153"
17445         }, {
17446           base: 'oi',
17447           chars: "\u01A3"
17448         }, {
17449           base: 'oo',
17450           chars: "\uA74F"
17451         }, {
17452           base: 'ou',
17453           chars: "\u0223"
17454         }, {
17455           base: 'p',
17456           chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"
17457         }, {
17458           base: 'q',
17459           chars: "\u24E0\uFF51\u024B\uA757\uA759"
17460         }, {
17461           base: 'r',
17462           chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
17463         }, {
17464           base: 's',
17465           chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"
17466         }, {
17467           base: 'ss',
17468           chars: "\xDF"
17469         }, {
17470           base: 't',
17471           chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
17472         }, {
17473           base: 'th',
17474           chars: "\xFE"
17475         }, {
17476           base: 'tz',
17477           chars: "\uA729"
17478         }, {
17479           base: 'u',
17480           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"
17481         }, {
17482           base: 'v',
17483           chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
17484         }, {
17485           base: 'vy',
17486           chars: "\uA761"
17487         }, {
17488           base: 'w',
17489           chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
17490         }, {
17491           base: 'x',
17492           chars: "\u24E7\uFF58\u1E8B\u1E8D"
17493         }, {
17494           base: 'y',
17495           chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
17496         }, {
17497           base: 'z',
17498           chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
17499         }];
17500         var diacriticsMap = {};
17501
17502         for (var i = 0; i < replacementList.length; i += 1) {
17503           var chars = replacementList[i].chars;
17504
17505           for (var j$1 = 0; j$1 < chars.length; j$1 += 1) {
17506             diacriticsMap[chars[j$1]] = replacementList[i].base;
17507           }
17508         }
17509
17510         function removeDiacritics(str) {
17511           return str.replace(/[^\u0000-\u007e]/g, function (c) {
17512             return diacriticsMap[c] || c;
17513           });
17514         }
17515
17516         var replacementList_1 = replacementList;
17517         var diacriticsMap_1 = diacriticsMap;
17518         var diacritics = {
17519           remove: remove$1,
17520           replacementList: replacementList_1,
17521           diacriticsMap: diacriticsMap_1
17522         };
17523
17524         var isArabic_1 = createCommonjsModule(function (module, exports) {
17525
17526           Object.defineProperty(exports, "__esModule", {
17527             value: true
17528           });
17529           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
17530           ];
17531
17532           function isArabic(_char) {
17533             if (_char.length > 1) {
17534               // allow the newer chars?
17535               throw new Error('isArabic works on only one-character strings');
17536             }
17537
17538             var code = _char.charCodeAt(0);
17539
17540             for (var i = 0; i < arabicBlocks.length; i++) {
17541               var block = arabicBlocks[i];
17542
17543               if (code >= block[0] && code <= block[1]) {
17544                 return true;
17545               }
17546             }
17547
17548             return false;
17549           }
17550
17551           exports.isArabic = isArabic;
17552
17553           function isMath(_char2) {
17554             if (_char2.length > 2) {
17555               // allow the newer chars?
17556               throw new Error('isMath works on only one-character strings');
17557             }
17558
17559             var code = _char2.charCodeAt(0);
17560
17561             return code >= 0x660 && code <= 0x66C || code >= 0x6F0 && code <= 0x6F9;
17562           }
17563
17564           exports.isMath = isMath;
17565         });
17566
17567         var unicodeArabic = createCommonjsModule(function (module, exports) {
17568
17569           Object.defineProperty(exports, "__esModule", {
17570             value: true
17571           });
17572           var arabicReference = {
17573             "alef": {
17574               "normal": ["\u0627"],
17575               "madda_above": {
17576                 "normal": ["\u0627\u0653", "\u0622"],
17577                 "isolated": "\uFE81",
17578                 "final": "\uFE82"
17579               },
17580               "hamza_above": {
17581                 "normal": ["\u0627\u0654", "\u0623"],
17582                 "isolated": "\uFE83",
17583                 "final": "\uFE84"
17584               },
17585               "hamza_below": {
17586                 "normal": ["\u0627\u0655", "\u0625"],
17587                 "isolated": "\uFE87",
17588                 "final": "\uFE88"
17589               },
17590               "wasla": {
17591                 "normal": "\u0671",
17592                 "isolated": "\uFB50",
17593                 "final": "\uFB51"
17594               },
17595               "wavy_hamza_above": ["\u0672"],
17596               "wavy_hamza_below": ["\u0627\u065F", "\u0673"],
17597               "high_hamza": ["\u0675", "\u0627\u0674"],
17598               "indic_two_above": ["\u0773"],
17599               "indic_three_above": ["\u0774"],
17600               "fathatan": {
17601                 "normal": ["\u0627\u064B"],
17602                 "final": "\uFD3C",
17603                 "isolated": "\uFD3D"
17604               },
17605               "isolated": "\uFE8D",
17606               "final": "\uFE8E"
17607             },
17608             "beh": {
17609               "normal": ["\u0628"],
17610               "dotless": ["\u066E"],
17611               "three_dots_horizontally_below": ["\u0750"],
17612               "dot_below_three_dots_above": ["\u0751"],
17613               "three_dots_pointing_upwards_below": ["\u0752"],
17614               "three_dots_pointing_upwards_below_two_dots_above": ["\u0753"],
17615               "two_dots_below_dot_above": ["\u0754"],
17616               "inverted_small_v_below": ["\u0755"],
17617               "small_v": ["\u0756"],
17618               "small_v_below": ["\u08A0"],
17619               "hamza_above": ["\u08A1"],
17620               "small_meem_above": ["\u08B6"],
17621               "isolated": "\uFE8F",
17622               "final": "\uFE90",
17623               "initial": "\uFE91",
17624               "medial": "\uFE92"
17625             },
17626             "teh marbuta": {
17627               "normal": ["\u0629"],
17628               "isolated": "\uFE93",
17629               "final": "\uFE94"
17630             },
17631             "teh": {
17632               "normal": ["\u062A"],
17633               "ring": ["\u067C"],
17634               "three_dots_above_downwards": ["\u067D"],
17635               "small_teh_above": ["\u08B8"],
17636               "isolated": "\uFE95",
17637               "final": "\uFE96",
17638               "initial": "\uFE97",
17639               "medial": "\uFE98"
17640             },
17641             "theh": {
17642               "normal": ["\u062B"],
17643               "isolated": "\uFE99",
17644               "final": "\uFE9A",
17645               "initial": "\uFE9B",
17646               "medial": "\uFE9C"
17647             },
17648             "jeem": {
17649               "normal": ["\u062C"],
17650               "two_dots_above": ["\u08A2"],
17651               "isolated": "\uFE9D",
17652               "final": "\uFE9E",
17653               "initial": "\uFE9F",
17654               "medial": "\uFEA0"
17655             },
17656             "hah": {
17657               "normal": ["\u062D"],
17658               "hamza_above": ["\u0681"],
17659               "two_dots_vertical_above": ["\u0682"],
17660               "three_dots_above": ["\u0685"],
17661               "two_dots_above": ["\u0757"],
17662               "three_dots_pointing_upwards_below": ["\u0758"],
17663               "small_tah_below": ["\u076E"],
17664               "small_tah_two_dots": ["\u076F"],
17665               "small_tah_above": ["\u0772"],
17666               "indic_four_below": ["\u077C"],
17667               "isolated": "\uFEA1",
17668               "final": "\uFEA2",
17669               "initial": "\uFEA3",
17670               "medial": "\uFEA4"
17671             },
17672             "khah": {
17673               "normal": ["\u062E"],
17674               "isolated": "\uFEA5",
17675               "final": "\uFEA6",
17676               "initial": "\uFEA7",
17677               "medial": "\uFEA8"
17678             },
17679             "dal": {
17680               "normal": ["\u062F"],
17681               "ring": ["\u0689"],
17682               "dot_below": ["\u068A"],
17683               "dot_below_small_tah": ["\u068B"],
17684               "three_dots_above_downwards": ["\u068F"],
17685               "four_dots_above": ["\u0690"],
17686               "inverted_v": ["\u06EE"],
17687               "two_dots_vertically_below_small_tah": ["\u0759"],
17688               "inverted_small_v_below": ["\u075A"],
17689               "three_dots_below": ["\u08AE"],
17690               "isolated": "\uFEA9",
17691               "final": "\uFEAA"
17692             },
17693             "thal": {
17694               "normal": ["\u0630"],
17695               "isolated": "\uFEAB",
17696               "final": "\uFEAC"
17697             },
17698             "reh": {
17699               "normal": ["\u0631"],
17700               "small_v": ["\u0692"],
17701               "ring": ["\u0693"],
17702               "dot_below": ["\u0694"],
17703               "small_v_below": ["\u0695"],
17704               "dot_below_dot_above": ["\u0696"],
17705               "two_dots_above": ["\u0697"],
17706               "four_dots_above": ["\u0699"],
17707               "inverted_v": ["\u06EF"],
17708               "stroke": ["\u075B"],
17709               "two_dots_vertically_above": ["\u076B"],
17710               "hamza_above": ["\u076C"],
17711               "small_tah_two_dots": ["\u0771"],
17712               "loop": ["\u08AA"],
17713               "small_noon_above": ["\u08B9"],
17714               "isolated": "\uFEAD",
17715               "final": "\uFEAE"
17716             },
17717             "zain": {
17718               "normal": ["\u0632"],
17719               "inverted_v_above": ["\u08B2"],
17720               "isolated": "\uFEAF",
17721               "final": "\uFEB0"
17722             },
17723             "seen": {
17724               "normal": ["\u0633"],
17725               "dot_below_dot_above": ["\u069A"],
17726               "three_dots_below": ["\u069B"],
17727               "three_dots_below_three_dots_above": ["\u069C"],
17728               "four_dots_above": ["\u075C"],
17729               "two_dots_vertically_above": ["\u076D"],
17730               "small_tah_two_dots": ["\u0770"],
17731               "indic_four_above": ["\u077D"],
17732               "inverted_v": ["\u077E"],
17733               "isolated": "\uFEB1",
17734               "final": "\uFEB2",
17735               "initial": "\uFEB3",
17736               "medial": "\uFEB4"
17737             },
17738             "sheen": {
17739               "normal": ["\u0634"],
17740               "dot_below": ["\u06FA"],
17741               "isolated": "\uFEB5",
17742               "final": "\uFEB6",
17743               "initial": "\uFEB7",
17744               "medial": "\uFEB8"
17745             },
17746             "sad": {
17747               "normal": ["\u0635"],
17748               "two_dots_below": ["\u069D"],
17749               "three_dots_above": ["\u069E"],
17750               "three_dots_below": ["\u08AF"],
17751               "isolated": "\uFEB9",
17752               "final": "\uFEBA",
17753               "initial": "\uFEBB",
17754               "medial": "\uFEBC"
17755             },
17756             "dad": {
17757               "normal": ["\u0636"],
17758               "dot_below": ["\u06FB"],
17759               "isolated": "\uFEBD",
17760               "final": "\uFEBE",
17761               "initial": "\uFEBF",
17762               "medial": "\uFEC0"
17763             },
17764             "tah": {
17765               "normal": ["\u0637"],
17766               "three_dots_above": ["\u069F"],
17767               "two_dots_above": ["\u08A3"],
17768               "isolated": "\uFEC1",
17769               "final": "\uFEC2",
17770               "initial": "\uFEC3",
17771               "medial": "\uFEC4"
17772             },
17773             "zah": {
17774               "normal": ["\u0638"],
17775               "isolated": "\uFEC5",
17776               "final": "\uFEC6",
17777               "initial": "\uFEC7",
17778               "medial": "\uFEC8"
17779             },
17780             "ain": {
17781               "normal": ["\u0639"],
17782               "three_dots_above": ["\u06A0"],
17783               "two_dots_above": ["\u075D"],
17784               "three_dots_pointing_downwards_above": ["\u075E"],
17785               "two_dots_vertically_above": ["\u075F"],
17786               "three_dots_below": ["\u08B3"],
17787               "isolated": "\uFEC9",
17788               "final": "\uFECA",
17789               "initial": "\uFECB",
17790               "medial": "\uFECC"
17791             },
17792             "ghain": {
17793               "normal": ["\u063A"],
17794               "dot_below": ["\u06FC"],
17795               "isolated": "\uFECD",
17796               "final": "\uFECE",
17797               "initial": "\uFECF",
17798               "medial": "\uFED0"
17799             },
17800             "feh": {
17801               "normal": ["\u0641"],
17802               "dotless": ["\u06A1"],
17803               "dot_moved_below": ["\u06A2"],
17804               "dot_below": ["\u06A3"],
17805               "three_dots_below": ["\u06A5"],
17806               "two_dots_below": ["\u0760"],
17807               "three_dots_pointing_upwards_below": ["\u0761"],
17808               "dot_below_three_dots_above": ["\u08A4"],
17809               "isolated": "\uFED1",
17810               "final": "\uFED2",
17811               "initial": "\uFED3",
17812               "medial": "\uFED4"
17813             },
17814             "qaf": {
17815               "normal": ["\u0642"],
17816               "dotless": ["\u066F"],
17817               "dot_above": ["\u06A7"],
17818               "three_dots_above": ["\u06A8"],
17819               "dot_below": ["\u08A5"],
17820               "isolated": "\uFED5",
17821               "final": "\uFED6",
17822               "initial": "\uFED7",
17823               "medial": "\uFED8"
17824             },
17825             "kaf": {
17826               "normal": ["\u0643"],
17827               "swash": ["\u06AA"],
17828               "ring": ["\u06AB"],
17829               "dot_above": ["\u06AC"],
17830               "three_dots_below": ["\u06AE"],
17831               "two_dots_above": ["\u077F"],
17832               "dot_below": ["\u08B4"],
17833               "isolated": "\uFED9",
17834               "final": "\uFEDA",
17835               "initial": "\uFEDB",
17836               "medial": "\uFEDC"
17837             },
17838             "lam": {
17839               "normal": ["\u0644"],
17840               "small_v": ["\u06B5"],
17841               "dot_above": ["\u06B6"],
17842               "three_dots_above": ["\u06B7"],
17843               "three_dots_below": ["\u06B8"],
17844               "bar": ["\u076A"],
17845               "double_bar": ["\u08A6"],
17846               "isolated": "\uFEDD",
17847               "final": "\uFEDE",
17848               "initial": "\uFEDF",
17849               "medial": "\uFEE0"
17850             },
17851             "meem": {
17852               "normal": ["\u0645"],
17853               "dot_above": ["\u0765"],
17854               "dot_below": ["\u0766"],
17855               "three_dots_above": ["\u08A7"],
17856               "isolated": "\uFEE1",
17857               "final": "\uFEE2",
17858               "initial": "\uFEE3",
17859               "medial": "\uFEE4"
17860             },
17861             "noon": {
17862               "normal": ["\u0646"],
17863               "dot_below": ["\u06B9"],
17864               "ring": ["\u06BC"],
17865               "three_dots_above": ["\u06BD"],
17866               "two_dots_below": ["\u0767"],
17867               "small_tah": ["\u0768"],
17868               "small_v": ["\u0769"],
17869               "isolated": "\uFEE5",
17870               "final": "\uFEE6",
17871               "initial": "\uFEE7",
17872               "medial": "\uFEE8"
17873             },
17874             "heh": {
17875               "normal": ["\u0647"],
17876               "isolated": "\uFEE9",
17877               "final": "\uFEEA",
17878               "initial": "\uFEEB",
17879               "medial": "\uFEEC"
17880             },
17881             "waw": {
17882               "normal": ["\u0648"],
17883               "hamza_above": {
17884                 "normal": ["\u0624", "\u0648\u0654"],
17885                 "isolated": "\uFE85",
17886                 "final": "\uFE86"
17887               },
17888               "high_hamza": ["\u0676", "\u0648\u0674"],
17889               "ring": ["\u06C4"],
17890               "two_dots_above": ["\u06CA"],
17891               "dot_above": ["\u06CF"],
17892               "indic_two_above": ["\u0778"],
17893               "indic_three_above": ["\u0779"],
17894               "dot_within": ["\u08AB"],
17895               "isolated": "\uFEED",
17896               "final": "\uFEEE"
17897             },
17898             "alef_maksura": {
17899               "normal": ["\u0649"],
17900               "hamza_above": ["\u0626", "\u064A\u0654"],
17901               "initial": "\uFBE8",
17902               "medial": "\uFBE9",
17903               "isolated": "\uFEEF",
17904               "final": "\uFEF0"
17905             },
17906             "yeh": {
17907               "normal": ["\u064A"],
17908               "hamza_above": {
17909                 "normal": ["\u0626", "\u0649\u0654"],
17910                 "isolated": "\uFE89",
17911                 "final": "\uFE8A",
17912                 "initial": "\uFE8B",
17913                 "medial": "\uFE8C"
17914               },
17915               "two_dots_below_hamza_above": ["\u08A8"],
17916               "high_hamza": ["\u0678", "\u064A\u0674"],
17917               "tail": ["\u06CD"],
17918               "small_v": ["\u06CE"],
17919               "three_dots_below": ["\u06D1"],
17920               "two_dots_below_dot_above": ["\u08A9"],
17921               "two_dots_below_small_noon_above": ["\u08BA"],
17922               "isolated": "\uFEF1",
17923               "final": "\uFEF2",
17924               "initial": "\uFEF3",
17925               "medial": "\uFEF4"
17926             },
17927             "tteh": {
17928               "normal": ["\u0679"],
17929               "isolated": "\uFB66",
17930               "final": "\uFB67",
17931               "initial": "\uFB68",
17932               "medial": "\uFB69"
17933             },
17934             "tteheh": {
17935               "normal": ["\u067A"],
17936               "isolated": "\uFB5E",
17937               "final": "\uFB5F",
17938               "initial": "\uFB60",
17939               "medial": "\uFB61"
17940             },
17941             "beeh": {
17942               "normal": ["\u067B"],
17943               "isolated": "\uFB52",
17944               "final": "\uFB53",
17945               "initial": "\uFB54",
17946               "medial": "\uFB55"
17947             },
17948             "peh": {
17949               "normal": ["\u067E"],
17950               "small_meem_above": ["\u08B7"],
17951               "isolated": "\uFB56",
17952               "final": "\uFB57",
17953               "initial": "\uFB58",
17954               "medial": "\uFB59"
17955             },
17956             "teheh": {
17957               "normal": ["\u067F"],
17958               "isolated": "\uFB62",
17959               "final": "\uFB63",
17960               "initial": "\uFB64",
17961               "medial": "\uFB65"
17962             },
17963             "beheh": {
17964               "normal": ["\u0680"],
17965               "isolated": "\uFB5A",
17966               "final": "\uFB5B",
17967               "initial": "\uFB5C",
17968               "medial": "\uFB5D"
17969             },
17970             "nyeh": {
17971               "normal": ["\u0683"],
17972               "isolated": "\uFB76",
17973               "final": "\uFB77",
17974               "initial": "\uFB78",
17975               "medial": "\uFB79"
17976             },
17977             "dyeh": {
17978               "normal": ["\u0684"],
17979               "isolated": "\uFB72",
17980               "final": "\uFB73",
17981               "initial": "\uFB74",
17982               "medial": "\uFB75"
17983             },
17984             "tcheh": {
17985               "normal": ["\u0686"],
17986               "dot_above": ["\u06BF"],
17987               "isolated": "\uFB7A",
17988               "final": "\uFB7B",
17989               "initial": "\uFB7C",
17990               "medial": "\uFB7D"
17991             },
17992             "tcheheh": {
17993               "normal": ["\u0687"],
17994               "isolated": "\uFB7E",
17995               "final": "\uFB7F",
17996               "initial": "\uFB80",
17997               "medial": "\uFB81"
17998             },
17999             "ddal": {
18000               "normal": ["\u0688"],
18001               "isolated": "\uFB88",
18002               "final": "\uFB89"
18003             },
18004             "dahal": {
18005               "normal": ["\u068C"],
18006               "isolated": "\uFB84",
18007               "final": "\uFB85"
18008             },
18009             "ddahal": {
18010               "normal": ["\u068D"],
18011               "isolated": "\uFB82",
18012               "final": "\uFB83"
18013             },
18014             "dul": {
18015               "normal": ["\u068F", "\u068E"],
18016               "isolated": "\uFB86",
18017               "final": "\uFB87"
18018             },
18019             "rreh": {
18020               "normal": ["\u0691"],
18021               "isolated": "\uFB8C",
18022               "final": "\uFB8D"
18023             },
18024             "jeh": {
18025               "normal": ["\u0698"],
18026               "isolated": "\uFB8A",
18027               "final": "\uFB8B"
18028             },
18029             "veh": {
18030               "normal": ["\u06A4"],
18031               "isolated": "\uFB6A",
18032               "final": "\uFB6B",
18033               "initial": "\uFB6C",
18034               "medial": "\uFB6D"
18035             },
18036             "peheh": {
18037               "normal": ["\u06A6"],
18038               "isolated": "\uFB6E",
18039               "final": "\uFB6F",
18040               "initial": "\uFB70",
18041               "medial": "\uFB71"
18042             },
18043             "keheh": {
18044               "normal": ["\u06A9"],
18045               "dot_above": ["\u0762"],
18046               "three_dots_above": ["\u0763"],
18047               "three_dots_pointing_upwards_below": ["\u0764"],
18048               "isolated": "\uFB8E",
18049               "final": "\uFB8F",
18050               "initial": "\uFB90",
18051               "medial": "\uFB91"
18052             },
18053             "ng": {
18054               "normal": ["\u06AD"],
18055               "isolated": "\uFBD3",
18056               "final": "\uFBD4",
18057               "initial": "\uFBD5",
18058               "medial": "\uFBD6"
18059             },
18060             "gaf": {
18061               "normal": ["\u06AF"],
18062               "ring": ["\u06B0"],
18063               "two_dots_below": ["\u06B2"],
18064               "three_dots_above": ["\u06B4"],
18065               "inverted_stroke": ["\u08B0"],
18066               "isolated": "\uFB92",
18067               "final": "\uFB93",
18068               "initial": "\uFB94",
18069               "medial": "\uFB95"
18070             },
18071             "ngoeh": {
18072               "normal": ["\u06B1"],
18073               "isolated": "\uFB9A",
18074               "final": "\uFB9B",
18075               "initial": "\uFB9C",
18076               "medial": "\uFB9D"
18077             },
18078             "gueh": {
18079               "normal": ["\u06B3"],
18080               "isolated": "\uFB96",
18081               "final": "\uFB97",
18082               "initial": "\uFB98",
18083               "medial": "\uFB99"
18084             },
18085             "noon ghunna": {
18086               "normal": ["\u06BA"],
18087               "isolated": "\uFB9E",
18088               "final": "\uFB9F"
18089             },
18090             "rnoon": {
18091               "normal": ["\u06BB"],
18092               "isolated": "\uFBA0",
18093               "final": "\uFBA1",
18094               "initial": "\uFBA2",
18095               "medial": "\uFBA3"
18096             },
18097             "heh doachashmee": {
18098               "normal": ["\u06BE"],
18099               "isolated": "\uFBAA",
18100               "final": "\uFBAB",
18101               "initial": "\uFBAC",
18102               "medial": "\uFBAD"
18103             },
18104             "heh goal": {
18105               "normal": ["\u06C1"],
18106               "hamza_above": ["\u06C1\u0654", "\u06C2"],
18107               "isolated": "\uFBA6",
18108               "final": "\uFBA7",
18109               "initial": "\uFBA8",
18110               "medial": "\uFBA9"
18111             },
18112             "teh marbuta goal": {
18113               "normal": ["\u06C3"]
18114             },
18115             "kirghiz oe": {
18116               "normal": ["\u06C5"],
18117               "isolated": "\uFBE0",
18118               "final": "\uFBE1"
18119             },
18120             "oe": {
18121               "normal": ["\u06C6"],
18122               "isolated": "\uFBD9",
18123               "final": "\uFBDA"
18124             },
18125             "u": {
18126               "normal": ["\u06C7"],
18127               "hamza_above": {
18128                 "normal": ["\u0677", "\u06C7\u0674"],
18129                 "isolated": "\uFBDD"
18130               },
18131               "isolated": "\uFBD7",
18132               "final": "\uFBD8"
18133             },
18134             "yu": {
18135               "normal": ["\u06C8"],
18136               "isolated": "\uFBDB",
18137               "final": "\uFBDC"
18138             },
18139             "kirghiz yu": {
18140               "normal": ["\u06C9"],
18141               "isolated": "\uFBE2",
18142               "final": "\uFBE3"
18143             },
18144             "ve": {
18145               "normal": ["\u06CB"],
18146               "isolated": "\uFBDE",
18147               "final": "\uFBDF"
18148             },
18149             "farsi yeh": {
18150               "normal": ["\u06CC"],
18151               "indic_two_above": ["\u0775"],
18152               "indic_three_above": ["\u0776"],
18153               "indic_four_above": ["\u0777"],
18154               "isolated": "\uFBFC",
18155               "final": "\uFBFD",
18156               "initial": "\uFBFE",
18157               "medial": "\uFBFF"
18158             },
18159             "e": {
18160               "normal": ["\u06D0"],
18161               "isolated": "\uFBE4",
18162               "final": "\uFBE5",
18163               "initial": "\uFBE6",
18164               "medial": "\uFBE7"
18165             },
18166             "yeh barree": {
18167               "normal": ["\u06D2"],
18168               "hamza_above": {
18169                 "normal": ["\u06D2\u0654", "\u06D3"],
18170                 "isolated": "\uFBB0",
18171                 "final": "\uFBB1"
18172               },
18173               "indic_two_above": ["\u077A"],
18174               "indic_three_above": ["\u077B"],
18175               "isolated": "\uFBAE",
18176               "final": "\uFBAF"
18177             },
18178             "ae": {
18179               "normal": ["\u06D5"],
18180               "isolated": "\u06D5",
18181               "final": "\uFEEA",
18182               "yeh_above": {
18183                 "normal": ["\u06C0", "\u06D5\u0654"],
18184                 "isolated": "\uFBA4",
18185                 "final": "\uFBA5"
18186               }
18187             },
18188             "rohingya yeh": {
18189               "normal": ["\u08AC"]
18190             },
18191             "low alef": {
18192               "normal": ["\u08AD"]
18193             },
18194             "straight waw": {
18195               "normal": ["\u08B1"]
18196             },
18197             "african feh": {
18198               "normal": ["\u08BB"]
18199             },
18200             "african qaf": {
18201               "normal": ["\u08BC"]
18202             },
18203             "african noon": {
18204               "normal": ["\u08BD"]
18205             }
18206           };
18207           exports["default"] = arabicReference;
18208         });
18209
18210         var unicodeLigatures = createCommonjsModule(function (module, exports) {
18211
18212           Object.defineProperty(exports, "__esModule", {
18213             value: true
18214           });
18215           var ligatureReference = {
18216             "\u0626\u0627": {
18217               "isolated": "\uFBEA",
18218               "final": "\uFBEB"
18219             },
18220             "\u0626\u06D5": {
18221               "isolated": "\uFBEC",
18222               "final": "\uFBED"
18223             },
18224             "\u0626\u0648": {
18225               "isolated": "\uFBEE",
18226               "final": "\uFBEF"
18227             },
18228             "\u0626\u06C7": {
18229               "isolated": "\uFBF0",
18230               "final": "\uFBF1"
18231             },
18232             "\u0626\u06C6": {
18233               "isolated": "\uFBF2",
18234               "final": "\uFBF3"
18235             },
18236             "\u0626\u06C8": {
18237               "isolated": "\uFBF4",
18238               "final": "\uFBF5"
18239             },
18240             "\u0626\u06D0": {
18241               "isolated": "\uFBF6",
18242               "final": "\uFBF7",
18243               "initial": "\uFBF8"
18244             },
18245             "\u0626\u0649": {
18246               "uighur_kirghiz": {
18247                 "isolated": "\uFBF9",
18248                 "final": "\uFBFA",
18249                 "initial": "\uFBFB"
18250               },
18251               "isolated": "\uFC03",
18252               "final": "\uFC68"
18253             },
18254             "\u0626\u062C": {
18255               "isolated": "\uFC00",
18256               "initial": "\uFC97"
18257             },
18258             "\u0626\u062D": {
18259               "isolated": "\uFC01",
18260               "initial": "\uFC98"
18261             },
18262             "\u0626\u0645": {
18263               "isolated": "\uFC02",
18264               "final": "\uFC66",
18265               "initial": "\uFC9A",
18266               "medial": "\uFCDF"
18267             },
18268             "\u0626\u064A": {
18269               "isolated": "\uFC04",
18270               "final": "\uFC69"
18271             },
18272             "\u0628\u062C": {
18273               "isolated": "\uFC05",
18274               "initial": "\uFC9C"
18275             },
18276             "\u0628\u062D": {
18277               "isolated": "\uFC06",
18278               "initial": "\uFC9D"
18279             },
18280             "\u0628\u062E": {
18281               "isolated": "\uFC07",
18282               "initial": "\uFC9E"
18283             },
18284             "\u0628\u0645": {
18285               "isolated": "\uFC08",
18286               "final": "\uFC6C",
18287               "initial": "\uFC9F",
18288               "medial": "\uFCE1"
18289             },
18290             "\u0628\u0649": {
18291               "isolated": "\uFC09",
18292               "final": "\uFC6E"
18293             },
18294             "\u0628\u064A": {
18295               "isolated": "\uFC0A",
18296               "final": "\uFC6F"
18297             },
18298             "\u062A\u062C": {
18299               "isolated": "\uFC0B",
18300               "initial": "\uFCA1"
18301             },
18302             "\u062A\u062D": {
18303               "isolated": "\uFC0C",
18304               "initial": "\uFCA2"
18305             },
18306             "\u062A\u062E": {
18307               "isolated": "\uFC0D",
18308               "initial": "\uFCA3"
18309             },
18310             "\u062A\u0645": {
18311               "isolated": "\uFC0E",
18312               "final": "\uFC72",
18313               "initial": "\uFCA4",
18314               "medial": "\uFCE3"
18315             },
18316             "\u062A\u0649": {
18317               "isolated": "\uFC0F",
18318               "final": "\uFC74"
18319             },
18320             "\u062A\u064A": {
18321               "isolated": "\uFC10",
18322               "final": "\uFC75"
18323             },
18324             "\u062B\u062C": {
18325               "isolated": "\uFC11"
18326             },
18327             "\u062B\u0645": {
18328               "isolated": "\uFC12",
18329               "final": "\uFC78",
18330               "initial": "\uFCA6",
18331               "medial": "\uFCE5"
18332             },
18333             "\u062B\u0649": {
18334               "isolated": "\uFC13",
18335               "final": "\uFC7A"
18336             },
18337             "\u062B\u0648": {
18338               "isolated": "\uFC14"
18339             },
18340             "\u062C\u062D": {
18341               "isolated": "\uFC15",
18342               "initial": "\uFCA7"
18343             },
18344             "\u062C\u0645": {
18345               "isolated": "\uFC16",
18346               "initial": "\uFCA8"
18347             },
18348             "\u062D\u062C": {
18349               "isolated": "\uFC17",
18350               "initial": "\uFCA9"
18351             },
18352             "\u062D\u0645": {
18353               "isolated": "\uFC18",
18354               "initial": "\uFCAA"
18355             },
18356             "\u062E\u062C": {
18357               "isolated": "\uFC19",
18358               "initial": "\uFCAB"
18359             },
18360             "\u062E\u062D": {
18361               "isolated": "\uFC1A"
18362             },
18363             "\u062E\u0645": {
18364               "isolated": "\uFC1B",
18365               "initial": "\uFCAC"
18366             },
18367             "\u0633\u062C": {
18368               "isolated": "\uFC1C",
18369               "initial": "\uFCAD",
18370               "medial": "\uFD34"
18371             },
18372             "\u0633\u062D": {
18373               "isolated": "\uFC1D",
18374               "initial": "\uFCAE",
18375               "medial": "\uFD35"
18376             },
18377             "\u0633\u062E": {
18378               "isolated": "\uFC1E",
18379               "initial": "\uFCAF",
18380               "medial": "\uFD36"
18381             },
18382             "\u0633\u0645": {
18383               "isolated": "\uFC1F",
18384               "initial": "\uFCB0",
18385               "medial": "\uFCE7"
18386             },
18387             "\u0635\u062D": {
18388               "isolated": "\uFC20",
18389               "initial": "\uFCB1"
18390             },
18391             "\u0635\u0645": {
18392               "isolated": "\uFC21",
18393               "initial": "\uFCB3"
18394             },
18395             "\u0636\u062C": {
18396               "isolated": "\uFC22",
18397               "initial": "\uFCB4"
18398             },
18399             "\u0636\u062D": {
18400               "isolated": "\uFC23",
18401               "initial": "\uFCB5"
18402             },
18403             "\u0636\u062E": {
18404               "isolated": "\uFC24",
18405               "initial": "\uFCB6"
18406             },
18407             "\u0636\u0645": {
18408               "isolated": "\uFC25",
18409               "initial": "\uFCB7"
18410             },
18411             "\u0637\u062D": {
18412               "isolated": "\uFC26",
18413               "initial": "\uFCB8"
18414             },
18415             "\u0637\u0645": {
18416               "isolated": "\uFC27",
18417               "initial": "\uFD33",
18418               "medial": "\uFD3A"
18419             },
18420             "\u0638\u0645": {
18421               "isolated": "\uFC28",
18422               "initial": "\uFCB9",
18423               "medial": "\uFD3B"
18424             },
18425             "\u0639\u062C": {
18426               "isolated": "\uFC29",
18427               "initial": "\uFCBA"
18428             },
18429             "\u0639\u0645": {
18430               "isolated": "\uFC2A",
18431               "initial": "\uFCBB"
18432             },
18433             "\u063A\u062C": {
18434               "isolated": "\uFC2B",
18435               "initial": "\uFCBC"
18436             },
18437             "\u063A\u0645": {
18438               "isolated": "\uFC2C",
18439               "initial": "\uFCBD"
18440             },
18441             "\u0641\u062C": {
18442               "isolated": "\uFC2D",
18443               "initial": "\uFCBE"
18444             },
18445             "\u0641\u062D": {
18446               "isolated": "\uFC2E",
18447               "initial": "\uFCBF"
18448             },
18449             "\u0641\u062E": {
18450               "isolated": "\uFC2F",
18451               "initial": "\uFCC0"
18452             },
18453             "\u0641\u0645": {
18454               "isolated": "\uFC30",
18455               "initial": "\uFCC1"
18456             },
18457             "\u0641\u0649": {
18458               "isolated": "\uFC31",
18459               "final": "\uFC7C"
18460             },
18461             "\u0641\u064A": {
18462               "isolated": "\uFC32",
18463               "final": "\uFC7D"
18464             },
18465             "\u0642\u062D": {
18466               "isolated": "\uFC33",
18467               "initial": "\uFCC2"
18468             },
18469             "\u0642\u0645": {
18470               "isolated": "\uFC34",
18471               "initial": "\uFCC3"
18472             },
18473             "\u0642\u0649": {
18474               "isolated": "\uFC35",
18475               "final": "\uFC7E"
18476             },
18477             "\u0642\u064A": {
18478               "isolated": "\uFC36",
18479               "final": "\uFC7F"
18480             },
18481             "\u0643\u0627": {
18482               "isolated": "\uFC37",
18483               "final": "\uFC80"
18484             },
18485             "\u0643\u062C": {
18486               "isolated": "\uFC38",
18487               "initial": "\uFCC4"
18488             },
18489             "\u0643\u062D": {
18490               "isolated": "\uFC39",
18491               "initial": "\uFCC5"
18492             },
18493             "\u0643\u062E": {
18494               "isolated": "\uFC3A",
18495               "initial": "\uFCC6"
18496             },
18497             "\u0643\u0644": {
18498               "isolated": "\uFC3B",
18499               "final": "\uFC81",
18500               "initial": "\uFCC7",
18501               "medial": "\uFCEB"
18502             },
18503             "\u0643\u0645": {
18504               "isolated": "\uFC3C",
18505               "final": "\uFC82",
18506               "initial": "\uFCC8",
18507               "medial": "\uFCEC"
18508             },
18509             "\u0643\u0649": {
18510               "isolated": "\uFC3D",
18511               "final": "\uFC83"
18512             },
18513             "\u0643\u064A": {
18514               "isolated": "\uFC3E",
18515               "final": "\uFC84"
18516             },
18517             "\u0644\u062C": {
18518               "isolated": "\uFC3F",
18519               "initial": "\uFCC9"
18520             },
18521             "\u0644\u062D": {
18522               "isolated": "\uFC40",
18523               "initial": "\uFCCA"
18524             },
18525             "\u0644\u062E": {
18526               "isolated": "\uFC41",
18527               "initial": "\uFCCB"
18528             },
18529             "\u0644\u0645": {
18530               "isolated": "\uFC42",
18531               "final": "\uFC85",
18532               "initial": "\uFCCC",
18533               "medial": "\uFCED"
18534             },
18535             "\u0644\u0649": {
18536               "isolated": "\uFC43",
18537               "final": "\uFC86"
18538             },
18539             "\u0644\u064A": {
18540               "isolated": "\uFC44",
18541               "final": "\uFC87"
18542             },
18543             "\u0645\u062C": {
18544               "isolated": "\uFC45",
18545               "initial": "\uFCCE"
18546             },
18547             "\u0645\u062D": {
18548               "isolated": "\uFC46",
18549               "initial": "\uFCCF"
18550             },
18551             "\u0645\u062E": {
18552               "isolated": "\uFC47",
18553               "initial": "\uFCD0"
18554             },
18555             "\u0645\u0645": {
18556               "isolated": "\uFC48",
18557               "final": "\uFC89",
18558               "initial": "\uFCD1"
18559             },
18560             "\u0645\u0649": {
18561               "isolated": "\uFC49"
18562             },
18563             "\u0645\u064A": {
18564               "isolated": "\uFC4A"
18565             },
18566             "\u0646\u062C": {
18567               "isolated": "\uFC4B",
18568               "initial": "\uFCD2"
18569             },
18570             "\u0646\u062D": {
18571               "isolated": "\uFC4C",
18572               "initial": "\uFCD3"
18573             },
18574             "\u0646\u062E": {
18575               "isolated": "\uFC4D",
18576               "initial": "\uFCD4"
18577             },
18578             "\u0646\u0645": {
18579               "isolated": "\uFC4E",
18580               "final": "\uFC8C",
18581               "initial": "\uFCD5",
18582               "medial": "\uFCEE"
18583             },
18584             "\u0646\u0649": {
18585               "isolated": "\uFC4F",
18586               "final": "\uFC8E"
18587             },
18588             "\u0646\u064A": {
18589               "isolated": "\uFC50",
18590               "final": "\uFC8F"
18591             },
18592             "\u0647\u062C": {
18593               "isolated": "\uFC51",
18594               "initial": "\uFCD7"
18595             },
18596             "\u0647\u0645": {
18597               "isolated": "\uFC52",
18598               "initial": "\uFCD8"
18599             },
18600             "\u0647\u0649": {
18601               "isolated": "\uFC53"
18602             },
18603             "\u0647\u064A": {
18604               "isolated": "\uFC54"
18605             },
18606             "\u064A\u062C": {
18607               "isolated": "\uFC55",
18608               "initial": "\uFCDA"
18609             },
18610             "\u064A\u062D": {
18611               "isolated": "\uFC56",
18612               "initial": "\uFCDB"
18613             },
18614             "\u064A\u062E": {
18615               "isolated": "\uFC57",
18616               "initial": "\uFCDC"
18617             },
18618             "\u064A\u0645": {
18619               "isolated": "\uFC58",
18620               "final": "\uFC93",
18621               "initial": "\uFCDD",
18622               "medial": "\uFCF0"
18623             },
18624             "\u064A\u0649": {
18625               "isolated": "\uFC59",
18626               "final": "\uFC95"
18627             },
18628             "\u064A\u064A": {
18629               "isolated": "\uFC5A",
18630               "final": "\uFC96"
18631             },
18632             "\u0630\u0670": {
18633               "isolated": "\uFC5B"
18634             },
18635             "\u0631\u0670": {
18636               "isolated": "\uFC5C"
18637             },
18638             "\u0649\u0670": {
18639               "isolated": "\uFC5D",
18640               "final": "\uFC90"
18641             },
18642             "\u064C\u0651": {
18643               "isolated": "\uFC5E"
18644             },
18645             "\u064D\u0651": {
18646               "isolated": "\uFC5F"
18647             },
18648             "\u064E\u0651": {
18649               "isolated": "\uFC60"
18650             },
18651             "\u064F\u0651": {
18652               "isolated": "\uFC61"
18653             },
18654             "\u0650\u0651": {
18655               "isolated": "\uFC62"
18656             },
18657             "\u0651\u0670": {
18658               "isolated": "\uFC63"
18659             },
18660             "\u0626\u0631": {
18661               "final": "\uFC64"
18662             },
18663             "\u0626\u0632": {
18664               "final": "\uFC65"
18665             },
18666             "\u0626\u0646": {
18667               "final": "\uFC67"
18668             },
18669             "\u0628\u0631": {
18670               "final": "\uFC6A"
18671             },
18672             "\u0628\u0632": {
18673               "final": "\uFC6B"
18674             },
18675             "\u0628\u0646": {
18676               "final": "\uFC6D"
18677             },
18678             "\u062A\u0631": {
18679               "final": "\uFC70"
18680             },
18681             "\u062A\u0632": {
18682               "final": "\uFC71"
18683             },
18684             "\u062A\u0646": {
18685               "final": "\uFC73"
18686             },
18687             "\u062B\u0631": {
18688               "final": "\uFC76"
18689             },
18690             "\u062B\u0632": {
18691               "final": "\uFC77"
18692             },
18693             "\u062B\u0646": {
18694               "final": "\uFC79"
18695             },
18696             "\u062B\u064A": {
18697               "final": "\uFC7B"
18698             },
18699             "\u0645\u0627": {
18700               "final": "\uFC88"
18701             },
18702             "\u0646\u0631": {
18703               "final": "\uFC8A"
18704             },
18705             "\u0646\u0632": {
18706               "final": "\uFC8B"
18707             },
18708             "\u0646\u0646": {
18709               "final": "\uFC8D"
18710             },
18711             "\u064A\u0631": {
18712               "final": "\uFC91"
18713             },
18714             "\u064A\u0632": {
18715               "final": "\uFC92"
18716             },
18717             "\u064A\u0646": {
18718               "final": "\uFC94"
18719             },
18720             "\u0626\u062E": {
18721               "initial": "\uFC99"
18722             },
18723             "\u0626\u0647": {
18724               "initial": "\uFC9B",
18725               "medial": "\uFCE0"
18726             },
18727             "\u0628\u0647": {
18728               "initial": "\uFCA0",
18729               "medial": "\uFCE2"
18730             },
18731             "\u062A\u0647": {
18732               "initial": "\uFCA5",
18733               "medial": "\uFCE4"
18734             },
18735             "\u0635\u062E": {
18736               "initial": "\uFCB2"
18737             },
18738             "\u0644\u0647": {
18739               "initial": "\uFCCD"
18740             },
18741             "\u0646\u0647": {
18742               "initial": "\uFCD6",
18743               "medial": "\uFCEF"
18744             },
18745             "\u0647\u0670": {
18746               "initial": "\uFCD9"
18747             },
18748             "\u064A\u0647": {
18749               "initial": "\uFCDE",
18750               "medial": "\uFCF1"
18751             },
18752             "\u062B\u0647": {
18753               "medial": "\uFCE6"
18754             },
18755             "\u0633\u0647": {
18756               "medial": "\uFCE8",
18757               "initial": "\uFD31"
18758             },
18759             "\u0634\u0645": {
18760               "medial": "\uFCE9",
18761               "isolated": "\uFD0C",
18762               "final": "\uFD28",
18763               "initial": "\uFD30"
18764             },
18765             "\u0634\u0647": {
18766               "medial": "\uFCEA",
18767               "initial": "\uFD32"
18768             },
18769             "\u0640\u064E\u0651": {
18770               "medial": "\uFCF2"
18771             },
18772             "\u0640\u064F\u0651": {
18773               "medial": "\uFCF3"
18774             },
18775             "\u0640\u0650\u0651": {
18776               "medial": "\uFCF4"
18777             },
18778             "\u0637\u0649": {
18779               "isolated": "\uFCF5",
18780               "final": "\uFD11"
18781             },
18782             "\u0637\u064A": {
18783               "isolated": "\uFCF6",
18784               "final": "\uFD12"
18785             },
18786             "\u0639\u0649": {
18787               "isolated": "\uFCF7",
18788               "final": "\uFD13"
18789             },
18790             "\u0639\u064A": {
18791               "isolated": "\uFCF8",
18792               "final": "\uFD14"
18793             },
18794             "\u063A\u0649": {
18795               "isolated": "\uFCF9",
18796               "final": "\uFD15"
18797             },
18798             "\u063A\u064A": {
18799               "isolated": "\uFCFA",
18800               "final": "\uFD16"
18801             },
18802             "\u0633\u0649": {
18803               "isolated": "\uFCFB"
18804             },
18805             "\u0633\u064A": {
18806               "isolated": "\uFCFC",
18807               "final": "\uFD18"
18808             },
18809             "\u0634\u0649": {
18810               "isolated": "\uFCFD",
18811               "final": "\uFD19"
18812             },
18813             "\u0634\u064A": {
18814               "isolated": "\uFCFE",
18815               "final": "\uFD1A"
18816             },
18817             "\u062D\u0649": {
18818               "isolated": "\uFCFF",
18819               "final": "\uFD1B"
18820             },
18821             "\u062D\u064A": {
18822               "isolated": "\uFD00",
18823               "final": "\uFD1C"
18824             },
18825             "\u062C\u0649": {
18826               "isolated": "\uFD01",
18827               "final": "\uFD1D"
18828             },
18829             "\u062C\u064A": {
18830               "isolated": "\uFD02",
18831               "final": "\uFD1E"
18832             },
18833             "\u062E\u0649": {
18834               "isolated": "\uFD03",
18835               "final": "\uFD1F"
18836             },
18837             "\u062E\u064A": {
18838               "isolated": "\uFD04",
18839               "final": "\uFD20"
18840             },
18841             "\u0635\u0649": {
18842               "isolated": "\uFD05",
18843               "final": "\uFD21"
18844             },
18845             "\u0635\u064A": {
18846               "isolated": "\uFD06",
18847               "final": "\uFD22"
18848             },
18849             "\u0636\u0649": {
18850               "isolated": "\uFD07",
18851               "final": "\uFD23"
18852             },
18853             "\u0636\u064A": {
18854               "isolated": "\uFD08",
18855               "final": "\uFD24"
18856             },
18857             "\u0634\u062C": {
18858               "isolated": "\uFD09",
18859               "final": "\uFD25",
18860               "initial": "\uFD2D",
18861               "medial": "\uFD37"
18862             },
18863             "\u0634\u062D": {
18864               "isolated": "\uFD0A",
18865               "final": "\uFD26",
18866               "initial": "\uFD2E",
18867               "medial": "\uFD38"
18868             },
18869             "\u0634\u062E": {
18870               "isolated": "\uFD0B",
18871               "final": "\uFD27",
18872               "initial": "\uFD2F",
18873               "medial": "\uFD39"
18874             },
18875             "\u0634\u0631": {
18876               "isolated": "\uFD0D",
18877               "final": "\uFD29"
18878             },
18879             "\u0633\u0631": {
18880               "isolated": "\uFD0E",
18881               "final": "\uFD2A"
18882             },
18883             "\u0635\u0631": {
18884               "isolated": "\uFD0F",
18885               "final": "\uFD2B"
18886             },
18887             "\u0636\u0631": {
18888               "isolated": "\uFD10",
18889               "final": "\uFD2C"
18890             },
18891             "\u0633\u0639": {
18892               "final": "\uFD17"
18893             },
18894             "\u062A\u062C\u0645": {
18895               "initial": "\uFD50"
18896             },
18897             "\u062A\u062D\u062C": {
18898               "final": "\uFD51",
18899               "initial": "\uFD52"
18900             },
18901             "\u062A\u062D\u0645": {
18902               "initial": "\uFD53"
18903             },
18904             "\u062A\u062E\u0645": {
18905               "initial": "\uFD54"
18906             },
18907             "\u062A\u0645\u062C": {
18908               "initial": "\uFD55"
18909             },
18910             "\u062A\u0645\u062D": {
18911               "initial": "\uFD56"
18912             },
18913             "\u062A\u0645\u062E": {
18914               "initial": "\uFD57"
18915             },
18916             "\u062C\u0645\u062D": {
18917               "final": "\uFD58",
18918               "initial": "\uFD59"
18919             },
18920             "\u062D\u0645\u064A": {
18921               "final": "\uFD5A"
18922             },
18923             "\u062D\u0645\u0649": {
18924               "final": "\uFD5B"
18925             },
18926             "\u0633\u062D\u062C": {
18927               "initial": "\uFD5C"
18928             },
18929             "\u0633\u062C\u062D": {
18930               "initial": "\uFD5D"
18931             },
18932             "\u0633\u062C\u0649": {
18933               "final": "\uFD5E"
18934             },
18935             "\u0633\u0645\u062D": {
18936               "final": "\uFD5F",
18937               "initial": "\uFD60"
18938             },
18939             "\u0633\u0645\u062C": {
18940               "initial": "\uFD61"
18941             },
18942             "\u0633\u0645\u0645": {
18943               "final": "\uFD62",
18944               "initial": "\uFD63"
18945             },
18946             "\u0635\u062D\u062D": {
18947               "final": "\uFD64",
18948               "initial": "\uFD65"
18949             },
18950             "\u0635\u0645\u0645": {
18951               "final": "\uFD66",
18952               "initial": "\uFDC5"
18953             },
18954             "\u0634\u062D\u0645": {
18955               "final": "\uFD67",
18956               "initial": "\uFD68"
18957             },
18958             "\u0634\u062C\u064A": {
18959               "final": "\uFD69"
18960             },
18961             "\u0634\u0645\u062E": {
18962               "final": "\uFD6A",
18963               "initial": "\uFD6B"
18964             },
18965             "\u0634\u0645\u0645": {
18966               "final": "\uFD6C",
18967               "initial": "\uFD6D"
18968             },
18969             "\u0636\u062D\u0649": {
18970               "final": "\uFD6E"
18971             },
18972             "\u0636\u062E\u0645": {
18973               "final": "\uFD6F",
18974               "initial": "\uFD70"
18975             },
18976             "\u0636\u0645\u062D": {
18977               "final": "\uFD71"
18978             },
18979             "\u0637\u0645\u062D": {
18980               "initial": "\uFD72"
18981             },
18982             "\u0637\u0645\u0645": {
18983               "initial": "\uFD73"
18984             },
18985             "\u0637\u0645\u064A": {
18986               "final": "\uFD74"
18987             },
18988             "\u0639\u062C\u0645": {
18989               "final": "\uFD75",
18990               "initial": "\uFDC4"
18991             },
18992             "\u0639\u0645\u0645": {
18993               "final": "\uFD76",
18994               "initial": "\uFD77"
18995             },
18996             "\u0639\u0645\u0649": {
18997               "final": "\uFD78"
18998             },
18999             "\u063A\u0645\u0645": {
19000               "final": "\uFD79"
19001             },
19002             "\u063A\u0645\u064A": {
19003               "final": "\uFD7A"
19004             },
19005             "\u063A\u0645\u0649": {
19006               "final": "\uFD7B"
19007             },
19008             "\u0641\u062E\u0645": {
19009               "final": "\uFD7C",
19010               "initial": "\uFD7D"
19011             },
19012             "\u0642\u0645\u062D": {
19013               "final": "\uFD7E",
19014               "initial": "\uFDB4"
19015             },
19016             "\u0642\u0645\u0645": {
19017               "final": "\uFD7F"
19018             },
19019             "\u0644\u062D\u0645": {
19020               "final": "\uFD80",
19021               "initial": "\uFDB5"
19022             },
19023             "\u0644\u062D\u064A": {
19024               "final": "\uFD81"
19025             },
19026             "\u0644\u062D\u0649": {
19027               "final": "\uFD82"
19028             },
19029             "\u0644\u062C\u062C": {
19030               "initial": "\uFD83",
19031               "final": "\uFD84"
19032             },
19033             "\u0644\u062E\u0645": {
19034               "final": "\uFD85",
19035               "initial": "\uFD86"
19036             },
19037             "\u0644\u0645\u062D": {
19038               "final": "\uFD87",
19039               "initial": "\uFD88"
19040             },
19041             "\u0645\u062D\u062C": {
19042               "initial": "\uFD89"
19043             },
19044             "\u0645\u062D\u0645": {
19045               "initial": "\uFD8A"
19046             },
19047             "\u0645\u062D\u064A": {
19048               "final": "\uFD8B"
19049             },
19050             "\u0645\u062C\u062D": {
19051               "initial": "\uFD8C"
19052             },
19053             "\u0645\u062C\u0645": {
19054               "initial": "\uFD8D"
19055             },
19056             "\u0645\u062E\u062C": {
19057               "initial": "\uFD8E"
19058             },
19059             "\u0645\u062E\u0645": {
19060               "initial": "\uFD8F"
19061             },
19062             "\u0645\u062C\u062E": {
19063               "initial": "\uFD92"
19064             },
19065             "\u0647\u0645\u062C": {
19066               "initial": "\uFD93"
19067             },
19068             "\u0647\u0645\u0645": {
19069               "initial": "\uFD94"
19070             },
19071             "\u0646\u062D\u0645": {
19072               "initial": "\uFD95"
19073             },
19074             "\u0646\u062D\u0649": {
19075               "final": "\uFD96"
19076             },
19077             "\u0646\u062C\u0645": {
19078               "final": "\uFD97",
19079               "initial": "\uFD98"
19080             },
19081             "\u0646\u062C\u0649": {
19082               "final": "\uFD99"
19083             },
19084             "\u0646\u0645\u064A": {
19085               "final": "\uFD9A"
19086             },
19087             "\u0646\u0645\u0649": {
19088               "final": "\uFD9B"
19089             },
19090             "\u064A\u0645\u0645": {
19091               "final": "\uFD9C",
19092               "initial": "\uFD9D"
19093             },
19094             "\u0628\u062E\u064A": {
19095               "final": "\uFD9E"
19096             },
19097             "\u062A\u062C\u064A": {
19098               "final": "\uFD9F"
19099             },
19100             "\u062A\u062C\u0649": {
19101               "final": "\uFDA0"
19102             },
19103             "\u062A\u062E\u064A": {
19104               "final": "\uFDA1"
19105             },
19106             "\u062A\u062E\u0649": {
19107               "final": "\uFDA2"
19108             },
19109             "\u062A\u0645\u064A": {
19110               "final": "\uFDA3"
19111             },
19112             "\u062A\u0645\u0649": {
19113               "final": "\uFDA4"
19114             },
19115             "\u062C\u0645\u064A": {
19116               "final": "\uFDA5"
19117             },
19118             "\u062C\u062D\u0649": {
19119               "final": "\uFDA6"
19120             },
19121             "\u062C\u0645\u0649": {
19122               "final": "\uFDA7"
19123             },
19124             "\u0633\u062E\u0649": {
19125               "final": "\uFDA8"
19126             },
19127             "\u0635\u062D\u064A": {
19128               "final": "\uFDA9"
19129             },
19130             "\u0634\u062D\u064A": {
19131               "final": "\uFDAA"
19132             },
19133             "\u0636\u062D\u064A": {
19134               "final": "\uFDAB"
19135             },
19136             "\u0644\u062C\u064A": {
19137               "final": "\uFDAC"
19138             },
19139             "\u0644\u0645\u064A": {
19140               "final": "\uFDAD"
19141             },
19142             "\u064A\u062D\u064A": {
19143               "final": "\uFDAE"
19144             },
19145             "\u064A\u062C\u064A": {
19146               "final": "\uFDAF"
19147             },
19148             "\u064A\u0645\u064A": {
19149               "final": "\uFDB0"
19150             },
19151             "\u0645\u0645\u064A": {
19152               "final": "\uFDB1"
19153             },
19154             "\u0642\u0645\u064A": {
19155               "final": "\uFDB2"
19156             },
19157             "\u0646\u062D\u064A": {
19158               "final": "\uFDB3"
19159             },
19160             "\u0639\u0645\u064A": {
19161               "final": "\uFDB6"
19162             },
19163             "\u0643\u0645\u064A": {
19164               "final": "\uFDB7"
19165             },
19166             "\u0646\u062C\u062D": {
19167               "initial": "\uFDB8",
19168               "final": "\uFDBD"
19169             },
19170             "\u0645\u062E\u064A": {
19171               "final": "\uFDB9"
19172             },
19173             "\u0644\u062C\u0645": {
19174               "initial": "\uFDBA",
19175               "final": "\uFDBC"
19176             },
19177             "\u0643\u0645\u0645": {
19178               "final": "\uFDBB",
19179               "initial": "\uFDC3"
19180             },
19181             "\u062C\u062D\u064A": {
19182               "final": "\uFDBE"
19183             },
19184             "\u062D\u062C\u064A": {
19185               "final": "\uFDBF"
19186             },
19187             "\u0645\u062C\u064A": {
19188               "final": "\uFDC0"
19189             },
19190             "\u0641\u0645\u064A": {
19191               "final": "\uFDC1"
19192             },
19193             "\u0628\u062D\u064A": {
19194               "final": "\uFDC2"
19195             },
19196             "\u0633\u062E\u064A": {
19197               "final": "\uFDC6"
19198             },
19199             "\u0646\u062C\u064A": {
19200               "final": "\uFDC7"
19201             },
19202             "\u0644\u0622": {
19203               "isolated": "\uFEF5",
19204               "final": "\uFEF6"
19205             },
19206             "\u0644\u0623": {
19207               "isolated": "\uFEF7",
19208               "final": "\uFEF8"
19209             },
19210             "\u0644\u0625": {
19211               "isolated": "\uFEF9",
19212               "final": "\uFEFA"
19213             },
19214             "\u0644\u0627": {
19215               "isolated": "\uFEFB",
19216               "final": "\uFEFC"
19217             },
19218             "words": {
19219               "\u0635\u0644\u06D2": "\uFDF0",
19220               "\u0642\u0644\u06D2": "\uFDF1",
19221               "\u0627\u0644\u0644\u0647": "\uFDF2",
19222               "\u0627\u0643\u0628\u0631": "\uFDF3",
19223               "\u0645\u062D\u0645\u062F": "\uFDF4",
19224               "\u0635\u0644\u0639\u0645": "\uFDF5",
19225               "\u0631\u0633\u0648\u0644": "\uFDF6",
19226               "\u0639\u0644\u064A\u0647": "\uFDF7",
19227               "\u0648\u0633\u0644\u0645": "\uFDF8",
19228               "\u0635\u0644\u0649": "\uFDF9",
19229               "\u0635\u0644\u0649\u0627\u0644\u0644\u0647\u0639\u0644\u064A\u0647\u0648\u0633\u0644\u0645": "\uFDFA",
19230               "\u062C\u0644\u062C\u0644\u0627\u0644\u0647": "\uFDFB",
19231               "\u0631\u06CC\u0627\u0644": "\uFDFC"
19232             }
19233           };
19234           exports["default"] = ligatureReference;
19235         });
19236
19237         var reference = createCommonjsModule(function (module, exports) {
19238
19239           Object.defineProperty(exports, "__esModule", {
19240             value: true
19241           });
19242           var letterList = Object.keys(unicodeArabic["default"]);
19243           exports.letterList = letterList;
19244           var ligatureList = Object.keys(unicodeLigatures["default"]);
19245           exports.ligatureList = ligatureList;
19246           var ligatureWordList = Object.keys(unicodeLigatures["default"].words);
19247           exports.ligatureWordList = ligatureWordList;
19248           var lams = "\u0644\u06B5\u06B6\u06B7\u06B8";
19249           exports.lams = lams;
19250           var alefs = "\u0627\u0622\u0623\u0625\u0671\u0672\u0673\u0675\u0773\u0774";
19251           exports.alefs = alefs; // for (var l = 1; l < lams.length; l++) {
19252           //   console.log('-');
19253           //   for (var a = 0; a < alefs.length; a++) {
19254           //     console.log(a + ': ' + lams[l] + alefs[a]);
19255           //   }
19256           // }
19257
19258           var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
19259           exports.tashkeel = tashkeel;
19260
19261           function addToTashkeel(start, finish) {
19262             for (var i = start; i <= finish; i++) {
19263               exports.tashkeel = tashkeel += String.fromCharCode(i);
19264             }
19265           }
19266
19267           addToTashkeel(0x0610, 0x061A);
19268           addToTashkeel(0x064B, 0x065F);
19269           addToTashkeel(0x06D6, 0x06DC);
19270           addToTashkeel(0x06E0, 0x06E4);
19271           addToTashkeel(0x06EA, 0x06ED);
19272           addToTashkeel(0x08D3, 0x08E1);
19273           addToTashkeel(0x08E3, 0x08FF);
19274           addToTashkeel(0xFE70, 0xFE7F);
19275           var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
19276           exports.lineBreakers = lineBreakers;
19277
19278           function addToLineBreakers(start, finish) {
19279             for (var i = start; i <= finish; i++) {
19280               exports.lineBreakers = lineBreakers += String.fromCharCode(i);
19281             }
19282           }
19283
19284           addToLineBreakers(0x0600, 0x061F); // it's OK to include tashkeel in this range as it is ignored
19285
19286           addToLineBreakers(0x0621, 0x0625);
19287           addToLineBreakers(0x062F, 0x0632);
19288           addToLineBreakers(0x0660, 0x066D); // numerals, math
19289
19290           addToLineBreakers(0x0671, 0x0677);
19291           addToLineBreakers(0x0688, 0x0699);
19292           addToLineBreakers(0x06C3, 0x06CB);
19293           addToLineBreakers(0x06D2, 0x06F9);
19294           addToLineBreakers(0x0759, 0x075B);
19295           addToLineBreakers(0x08AA, 0x08AE);
19296           addToLineBreakers(0xFB50, 0xFDFD); // presentation forms look like they could connect, but never do
19297           // Presentation Forms A includes diacritics but they are meant to stand alone
19298
19299           addToLineBreakers(0xFE80, 0xFEFC); // presentation forms look like they could connect, but never do
19300           // numerals, math
19301
19302           addToLineBreakers(0x10E60, 0x10E7F);
19303           addToLineBreakers(0x1EC70, 0x1ECBF);
19304           addToLineBreakers(0x1EE00, 0x1EEFF);
19305         });
19306
19307         var GlyphSplitter_1 = createCommonjsModule(function (module, exports) {
19308
19309           Object.defineProperty(exports, "__esModule", {
19310             value: true
19311           });
19312
19313           function GlyphSplitter(word) {
19314             var letters = [];
19315             var lastLetter = '';
19316             word.split('').forEach(function (letter) {
19317               if (isArabic_1.isArabic(letter)) {
19318                 if (reference.tashkeel.indexOf(letter) > -1) {
19319                   letters[letters.length - 1] += letter;
19320                 } else if (lastLetter.length && (reference.lams.indexOf(lastLetter) === 0 && reference.alefs.indexOf(letter) > -1 || reference.lams.indexOf(lastLetter) > 0 && reference.alefs.indexOf(letter) === 0)) {
19321                   // valid LA forms
19322                   letters[letters.length - 1] += letter;
19323                 } else {
19324                   letters.push(letter);
19325                 }
19326               } else {
19327                 letters.push(letter);
19328               }
19329
19330               if (reference.tashkeel.indexOf(letter) === -1) {
19331                 lastLetter = letter;
19332               }
19333             });
19334             return letters;
19335           }
19336
19337           exports.GlyphSplitter = GlyphSplitter;
19338         });
19339
19340         var BaselineSplitter_1 = createCommonjsModule(function (module, exports) {
19341
19342           Object.defineProperty(exports, "__esModule", {
19343             value: true
19344           });
19345
19346           function BaselineSplitter(word) {
19347             var letters = [];
19348             var lastLetter = '';
19349             word.split('').forEach(function (letter) {
19350               if (isArabic_1.isArabic(letter) && isArabic_1.isArabic(lastLetter)) {
19351                 if (lastLetter.length && reference.tashkeel.indexOf(letter) > -1) {
19352                   letters[letters.length - 1] += letter;
19353                 } else if (reference.lineBreakers.indexOf(lastLetter) > -1) {
19354                   letters.push(letter);
19355                 } else {
19356                   letters[letters.length - 1] += letter;
19357                 }
19358               } else {
19359                 letters.push(letter);
19360               }
19361
19362               if (reference.tashkeel.indexOf(letter) === -1) {
19363                 // don't allow tashkeel to hide line break
19364                 lastLetter = letter;
19365               }
19366             });
19367             return letters;
19368           }
19369
19370           exports.BaselineSplitter = BaselineSplitter;
19371         });
19372
19373         var Normalization = createCommonjsModule(function (module, exports) {
19374
19375           Object.defineProperty(exports, "__esModule", {
19376             value: true
19377           });
19378
19379           function Normal(word, breakPresentationForm) {
19380             // default is to turn initial/isolated/medial/final presentation form to generic
19381             if (typeof breakPresentationForm === 'undefined') {
19382               breakPresentationForm = true;
19383             }
19384
19385             var returnable = '';
19386             word.split('').forEach(function (letter) {
19387               if (!isArabic_1.isArabic(letter)) {
19388                 returnable += letter;
19389                 return;
19390               }
19391
19392               for (var w = 0; w < reference.letterList.length; w++) {
19393                 // ok so we are checking this potential lettertron
19394                 var letterForms = unicodeArabic["default"][reference.letterList[w]];
19395                 var versions = Object.keys(letterForms);
19396
19397                 for (var v = 0; v < versions.length; v++) {
19398                   var localVersion = letterForms[versions[v]];
19399
19400                   if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19401                     // look at this embedded object
19402                     var embeddedForms = Object.keys(localVersion);
19403
19404                     for (var ef = 0; ef < embeddedForms.length; ef++) {
19405                       var form = localVersion[embeddedForms[ef]];
19406
19407                       if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19408                         // match
19409                         // console.log('embedded match');
19410                         if (form === letter) {
19411                           // match exact
19412                           if (breakPresentationForm && localVersion['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(embeddedForms[ef]) > -1) {
19413                             // replace presentation form
19414                             // console.log('keeping normal form of the letter');
19415                             if (_typeof(localVersion['normal']) === 'object') {
19416                               returnable += localVersion['normal'][0];
19417                             } else {
19418                               returnable += localVersion['normal'];
19419                             }
19420
19421                             return;
19422                           } // console.log('keeping this letter');
19423
19424
19425                           returnable += letter;
19426                           return;
19427                         } else if (_typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19428                           // match
19429                           returnable += form[0]; // console.log('added the first letter from the same array');
19430
19431                           return;
19432                         }
19433                       }
19434                     }
19435                   } else if (localVersion === letter) {
19436                     // match exact
19437                     if (breakPresentationForm && letterForms['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(versions[v]) > -1) {
19438                       // replace presentation form
19439                       // console.log('keeping normal form of the letter');
19440                       if (_typeof(letterForms['normal']) === 'object') {
19441                         returnable += letterForms['normal'][0];
19442                       } else {
19443                         returnable += letterForms['normal'];
19444                       }
19445
19446                       return;
19447                     } // console.log('keeping this letter');
19448
19449
19450                     returnable += letter;
19451                     return;
19452                   } else if (_typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19453                     // match
19454                     returnable += localVersion[0]; // console.log('added the first letter from the same array');
19455
19456                     return;
19457                   }
19458                 }
19459               } // try ligatures
19460
19461
19462               for (var v2 = 0; v2 < reference.ligatureList.length; v2++) {
19463                 var normalForm = reference.ligatureList[v2];
19464
19465                 if (normalForm !== 'words') {
19466                   var ligForms = Object.keys(unicodeLigatures["default"][normalForm]);
19467
19468                   for (var f = 0; f < ligForms.length; f++) {
19469                     if (unicodeLigatures["default"][normalForm][ligForms[f]] === letter) {
19470                       returnable += normalForm;
19471                       return;
19472                     }
19473                   }
19474                 }
19475               } // try words ligatures
19476
19477
19478               for (var v3 = 0; v3 < reference.ligatureWordList.length; v3++) {
19479                 var _normalForm = reference.ligatureWordList[v3];
19480
19481                 if (unicodeLigatures["default"].words[_normalForm] === letter) {
19482                   returnable += _normalForm;
19483                   return;
19484                 }
19485               }
19486
19487               returnable += letter; // console.log('kept the letter')
19488             });
19489             return returnable;
19490           }
19491
19492           exports.Normal = Normal;
19493         });
19494
19495         var CharShaper_1 = createCommonjsModule(function (module, exports) {
19496
19497           Object.defineProperty(exports, "__esModule", {
19498             value: true
19499           });
19500
19501           function CharShaper(letter, form) {
19502             if (!isArabic_1.isArabic(letter)) {
19503               // fail not Arabic
19504               throw new Error('Not Arabic');
19505             }
19506
19507             if (letter === "\u0621") {
19508               // hamza alone
19509               return "\u0621";
19510             }
19511
19512             for (var w = 0; w < reference.letterList.length; w++) {
19513               // ok so we are checking this potential lettertron
19514               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19515               var versions = Object.keys(letterForms);
19516
19517               for (var v = 0; v < versions.length; v++) {
19518                 var localVersion = letterForms[versions[v]];
19519
19520                 if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19521                   if (versions.indexOf(form) > -1) {
19522                     return letterForms[form];
19523                   }
19524                 } else if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19525                   // check embedded
19526                   var embeddedVersions = Object.keys(localVersion);
19527
19528                   for (var ev = 0; ev < embeddedVersions.length; ev++) {
19529                     if (localVersion[embeddedVersions[ev]] === letter || _typeof(localVersion[embeddedVersions[ev]]) === 'object' && localVersion[embeddedVersions[ev]].indexOf && localVersion[embeddedVersions[ev]].indexOf(letter) > -1) {
19530                       if (embeddedVersions.indexOf(form) > -1) {
19531                         return localVersion[form];
19532                       }
19533                     }
19534                   }
19535                 }
19536               }
19537             }
19538           }
19539
19540           exports.CharShaper = CharShaper;
19541         });
19542
19543         var WordShaper_1 = createCommonjsModule(function (module, exports) {
19544
19545           Object.defineProperty(exports, "__esModule", {
19546             value: true
19547           });
19548
19549           function WordShaper(word) {
19550             var state = 'initial';
19551             var output = '';
19552
19553             for (var w = 0; w < word.length; w++) {
19554               var nextLetter = ' ';
19555
19556               for (var nxw = w + 1; nxw < word.length; nxw++) {
19557                 if (!isArabic_1.isArabic(word[nxw])) {
19558                   break;
19559                 }
19560
19561                 if (reference.tashkeel.indexOf(word[nxw]) === -1) {
19562                   nextLetter = word[nxw];
19563                   break;
19564                 }
19565               }
19566
19567               if (!isArabic_1.isArabic(word[w]) || isArabic_1.isMath(word[w])) {
19568                 // space or other non-Arabic
19569                 output += word[w];
19570                 state = 'initial';
19571               } else if (reference.tashkeel.indexOf(word[w]) > -1) {
19572                 // tashkeel - add without changing state
19573                 output += word[w];
19574               } else if (nextLetter === ' ' || // last Arabic letter in this word
19575               reference.lineBreakers.indexOf(word[w]) > -1) {
19576                 // the current letter is known to break lines
19577                 output += CharShaper_1.CharShaper(word[w], state === 'initial' ? 'isolated' : 'final');
19578                 state = 'initial';
19579               } else if (reference.lams.indexOf(word[w]) > -1 && reference.alefs.indexOf(nextLetter) > -1) {
19580                 // LA letters - advance an additional letter after this
19581                 output += unicodeLigatures["default"][word[w] + nextLetter][state === 'initial' ? 'isolated' : 'final'];
19582
19583                 while (word[w] !== nextLetter) {
19584                   w++;
19585                 }
19586
19587                 state = 'initial';
19588               } else {
19589                 output += CharShaper_1.CharShaper(word[w], state);
19590                 state = 'medial';
19591               }
19592             }
19593
19594             return output;
19595           }
19596
19597           exports.WordShaper = WordShaper;
19598         });
19599
19600         var ParentLetter_1 = createCommonjsModule(function (module, exports) {
19601
19602           Object.defineProperty(exports, "__esModule", {
19603             value: true
19604           });
19605
19606           function ParentLetter(letter) {
19607             if (!isArabic_1.isArabic(letter)) {
19608               throw new Error('Not an Arabic letter');
19609             }
19610
19611             for (var w = 0; w < reference.letterList.length; w++) {
19612               // ok so we are checking this potential lettertron
19613               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19614               var versions = Object.keys(letterForms);
19615
19616               for (var v = 0; v < versions.length; v++) {
19617                 var localVersion = letterForms[versions[v]];
19618
19619                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19620                   // look at this embedded object
19621                   var embeddedForms = Object.keys(localVersion);
19622
19623                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19624                     var form = localVersion[embeddedForms[ef]];
19625
19626                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19627                       // match
19628                       return localVersion;
19629                     }
19630                   }
19631                 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19632                   // match
19633                   return letterForms;
19634                 }
19635               }
19636
19637               return null;
19638             }
19639           }
19640
19641           exports.ParentLetter = ParentLetter;
19642
19643           function GrandparentLetter(letter) {
19644             if (!isArabic_1.isArabic(letter)) {
19645               throw new Error('Not an Arabic letter');
19646             }
19647
19648             for (var w = 0; w < reference.letterList.length; w++) {
19649               // ok so we are checking this potential lettertron
19650               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19651               var versions = Object.keys(letterForms);
19652
19653               for (var v = 0; v < versions.length; v++) {
19654                 var localVersion = letterForms[versions[v]];
19655
19656                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19657                   // look at this embedded object
19658                   var embeddedForms = Object.keys(localVersion);
19659
19660                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19661                     var form = localVersion[embeddedForms[ef]];
19662
19663                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19664                       // match
19665                       return letterForms;
19666                     }
19667                   }
19668                 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19669                   // match
19670                   return letterForms;
19671                 }
19672               }
19673
19674               return null;
19675             }
19676           }
19677
19678           exports.GrandparentLetter = GrandparentLetter;
19679         });
19680
19681         var lib = createCommonjsModule(function (module, exports) {
19682
19683           Object.defineProperty(exports, "__esModule", {
19684             value: true
19685           });
19686           exports.isArabic = isArabic_1.isArabic;
19687           exports.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
19688           exports.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
19689           exports.Normal = Normalization.Normal;
19690           exports.CharShaper = CharShaper_1.CharShaper;
19691           exports.WordShaper = WordShaper_1.WordShaper;
19692           exports.ParentLetter = ParentLetter_1.ParentLetter;
19693           exports.GrandparentLetter = ParentLetter_1.GrandparentLetter;
19694         });
19695
19696         var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u07BF\u08A0–\u08BF]/;
19697         function fixRTLTextForSvg(inputText) {
19698           var ret = '',
19699               rtlBuffer = [];
19700           var arabicRegex = /[\u0600-\u06FF]/g;
19701           var arabicDiacritics = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06ED]/g;
19702           var arabicMath = /[\u0660-\u066C\u06F0-\u06F9]+/g;
19703           var thaanaVowel = /[\u07A6-\u07B0]/;
19704           var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/; // Arabic word shaping
19705
19706           if (arabicRegex.test(inputText)) {
19707             inputText = lib.WordShaper(inputText);
19708           }
19709
19710           for (var n = 0; n < inputText.length; n++) {
19711             var c = inputText[n];
19712
19713             if (arabicMath.test(c)) {
19714               // Arabic numbers go LTR
19715               ret += rtlBuffer.reverse().join('');
19716               rtlBuffer = [c];
19717             } else {
19718               if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
19719                 ret += rtlBuffer.reverse().join('');
19720                 rtlBuffer = [];
19721               }
19722
19723               if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
19724                 rtlBuffer[rtlBuffer.length - 1] += c;
19725               } else if (rtlRegex.test(c) // include Arabic presentation forms
19726               || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
19727                 rtlBuffer.push(c);
19728               } else if (c === ' ' && rtlBuffer.length) {
19729                 // whitespace within RTL text
19730                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
19731               } else {
19732                 // non-RTL character
19733                 ret += rtlBuffer.reverse().join('') + c;
19734                 rtlBuffer = [];
19735               }
19736             }
19737           }
19738
19739           ret += rtlBuffer.reverse().join('');
19740           return ret;
19741         }
19742
19743         var propertyIsEnumerable = objectPropertyIsEnumerable.f;
19744
19745         // `Object.{ entries, values }` methods implementation
19746         var createMethod$5 = function (TO_ENTRIES) {
19747           return function (it) {
19748             var O = toIndexedObject(it);
19749             var keys = objectKeys(O);
19750             var length = keys.length;
19751             var i = 0;
19752             var result = [];
19753             var key;
19754             while (length > i) {
19755               key = keys[i++];
19756               if (!descriptors || propertyIsEnumerable.call(O, key)) {
19757                 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
19758               }
19759             }
19760             return result;
19761           };
19762         };
19763
19764         var objectToArray = {
19765           // `Object.entries` method
19766           // https://tc39.es/ecma262/#sec-object.entries
19767           entries: createMethod$5(true),
19768           // `Object.values` method
19769           // https://tc39.es/ecma262/#sec-object.values
19770           values: createMethod$5(false)
19771         };
19772
19773         var $values = objectToArray.values;
19774
19775         // `Object.values` method
19776         // https://tc39.es/ecma262/#sec-object.values
19777         _export({ target: 'Object', stat: true }, {
19778           values: function values(O) {
19779             return $values(O);
19780           }
19781         });
19782
19783         // https://github.com/openstreetmap/iD/issues/772
19784         // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
19785         var _storage;
19786
19787         try {
19788           _storage = localStorage;
19789         } catch (e) {} // eslint-disable-line no-empty
19790
19791
19792         _storage = _storage || function () {
19793           var s = {};
19794           return {
19795             getItem: function getItem(k) {
19796               return s[k];
19797             },
19798             setItem: function setItem(k, v) {
19799               return s[k] = v;
19800             },
19801             removeItem: function removeItem(k) {
19802               return delete s[k];
19803             }
19804           };
19805         }(); //
19806         // corePreferences is an interface for persisting basic key-value strings
19807         // within and between iD sessions on the same site.
19808         //
19809
19810
19811         function corePreferences(k, v) {
19812           try {
19813             if (arguments.length === 1) return _storage.getItem(k);else if (v === null) _storage.removeItem(k);else _storage.setItem(k, v);
19814           } catch (e) {
19815             /* eslint-disable no-console */
19816             if (typeof console !== 'undefined') {
19817               console.error('localStorage quota exceeded');
19818             }
19819             /* eslint-enable no-console */
19820
19821           }
19822         }
19823
19824         function responseText(response) {
19825           if (!response.ok) throw new Error(response.status + " " + response.statusText);
19826           return response.text();
19827         }
19828
19829         function d3_text (input, init) {
19830           return fetch(input, init).then(responseText);
19831         }
19832
19833         function responseJson(response) {
19834           if (!response.ok) throw new Error(response.status + " " + response.statusText);
19835           if (response.status === 204 || response.status === 205) return;
19836           return response.json();
19837         }
19838
19839         function d3_json (input, init) {
19840           return fetch(input, init).then(responseJson);
19841         }
19842
19843         function parser(type) {
19844           return function (input, init) {
19845             return d3_text(input, init).then(function (text) {
19846               return new DOMParser().parseFromString(text, type);
19847             });
19848           };
19849         }
19850
19851         var d3_xml = parser("application/xml");
19852         var svg = parser("image/svg+xml");
19853
19854         var _mainFileFetcher = coreFileFetcher(); // singleton
19855         // coreFileFetcher asynchronously fetches data from JSON files
19856         //
19857
19858         function coreFileFetcher() {
19859           var _this = {};
19860           var _inflight = {};
19861           var _fileMap = {
19862             'address_formats': 'data/address_formats.min.json',
19863             'deprecated': 'data/deprecated.min.json',
19864             'discarded': 'data/discarded.min.json',
19865             'imagery': 'data/imagery.min.json',
19866             'intro_graph': 'data/intro_graph.min.json',
19867             'keepRight': 'data/keepRight.min.json',
19868             'languages': 'data/languages.min.json',
19869             'locales': 'data/locales.min.json',
19870             'nsi_brands': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@4/dist/brands.min.json',
19871             'nsi_filters': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@4/dist/filters.min.json',
19872             'oci_features': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/features.min.json',
19873             'oci_resources': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/resources.min.json',
19874             'preset_categories': 'data/preset_categories.min.json',
19875             'preset_defaults': 'data/preset_defaults.min.json',
19876             'preset_fields': 'data/preset_fields.min.json',
19877             'preset_presets': 'data/preset_presets.min.json',
19878             'phone_formats': 'data/phone_formats.min.json',
19879             'qa_data': 'data/qa_data.min.json',
19880             'shortcuts': 'data/shortcuts.min.json',
19881             'territory_languages': 'data/territory_languages.min.json',
19882             'wmf_sitematrix': 'https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json'
19883           };
19884           var _cachedData = {}; // expose the cache; useful for tests
19885
19886           _this.cache = function () {
19887             return _cachedData;
19888           }; // Returns a Promise to fetch data
19889           // (resolved with the data if we have it already)
19890
19891
19892           _this.get = function (which) {
19893             if (_cachedData[which]) {
19894               return Promise.resolve(_cachedData[which]);
19895             }
19896
19897             var file = _fileMap[which];
19898
19899             var url = file && _this.asset(file);
19900
19901             if (!url) {
19902               return Promise.reject("Unknown data file for \"".concat(which, "\""));
19903             }
19904
19905             var prom = _inflight[url];
19906
19907             if (!prom) {
19908               _inflight[url] = prom = d3_json(url).then(function (result) {
19909                 delete _inflight[url];
19910
19911                 if (!result) {
19912                   throw new Error("No data loaded for \"".concat(which, "\""));
19913                 }
19914
19915                 _cachedData[which] = result;
19916                 return result;
19917               })["catch"](function (err) {
19918                 delete _inflight[url];
19919                 throw err;
19920               });
19921             }
19922
19923             return prom;
19924           }; // Accessor for the file map
19925
19926
19927           _this.fileMap = function (val) {
19928             if (!arguments.length) return _fileMap;
19929             _fileMap = val;
19930             return _this;
19931           };
19932
19933           var _assetPath = '';
19934
19935           _this.assetPath = function (val) {
19936             if (!arguments.length) return _assetPath;
19937             _assetPath = val;
19938             return _this;
19939           };
19940
19941           var _assetMap = {};
19942
19943           _this.assetMap = function (val) {
19944             if (!arguments.length) return _assetMap;
19945             _assetMap = val;
19946             return _this;
19947           };
19948
19949           _this.asset = function (val) {
19950             if (/^http(s)?:\/\//i.test(val)) return val;
19951             var filename = _assetPath + val;
19952             return _assetMap[filename] || filename;
19953           };
19954
19955           return _this;
19956         }
19957
19958         var $findIndex$1 = arrayIteration.findIndex;
19959
19960
19961         var FIND_INDEX = 'findIndex';
19962         var SKIPS_HOLES$1 = true;
19963
19964         // Shouldn't skip holes
19965         if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES$1 = false; });
19966
19967         // `Array.prototype.findIndex` method
19968         // https://tc39.es/ecma262/#sec-array.prototype.findindex
19969         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 }, {
19970           findIndex: function findIndex(callbackfn /* , that = undefined */) {
19971             return $findIndex$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
19972           }
19973         });
19974
19975         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
19976         addToUnscopables(FIND_INDEX);
19977
19978         var $includes$1 = arrayIncludes.includes;
19979
19980
19981         // `Array.prototype.includes` method
19982         // https://tc39.es/ecma262/#sec-array.prototype.includes
19983         _export({ target: 'Array', proto: true }, {
19984           includes: function includes(el /* , fromIndex = 0 */) {
19985             return $includes$1(this, el, arguments.length > 1 ? arguments[1] : undefined);
19986           }
19987         });
19988
19989         // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
19990         addToUnscopables('includes');
19991
19992         var notARegexp = function (it) {
19993           if (isRegexp(it)) {
19994             throw TypeError("The method doesn't accept regular expressions");
19995           } return it;
19996         };
19997
19998         var MATCH$2 = wellKnownSymbol('match');
19999
20000         var correctIsRegexpLogic = function (METHOD_NAME) {
20001           var regexp = /./;
20002           try {
20003             '/./'[METHOD_NAME](regexp);
20004           } catch (error1) {
20005             try {
20006               regexp[MATCH$2] = false;
20007               return '/./'[METHOD_NAME](regexp);
20008             } catch (error2) { /* empty */ }
20009           } return false;
20010         };
20011
20012         // `String.prototype.includes` method
20013         // https://tc39.es/ecma262/#sec-string.prototype.includes
20014         _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {
20015           includes: function includes(searchString /* , position = 0 */) {
20016             return !!~String(requireObjectCoercible(this))
20017               .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
20018           }
20019         });
20020
20021         var _detected;
20022
20023         function utilDetect(refresh) {
20024           if (_detected && !refresh) return _detected;
20025           _detected = {};
20026           var ua = navigator.userAgent;
20027           var m = null;
20028           /* Browser */
20029
20030           m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
20031
20032           if (m !== null) {
20033             _detected.browser = m[1];
20034             _detected.version = m[2];
20035           }
20036
20037           if (!_detected.browser) {
20038             m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
20039
20040             if (m !== null) {
20041               _detected.browser = 'msie';
20042               _detected.version = m[1];
20043             }
20044           }
20045
20046           if (!_detected.browser) {
20047             m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
20048
20049             if (m !== null) {
20050               _detected.browser = 'Opera';
20051               _detected.version = m[2];
20052             }
20053           }
20054
20055           if (!_detected.browser) {
20056             m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
20057
20058             if (m !== null) {
20059               _detected.browser = m[1];
20060               _detected.version = m[2];
20061               m = ua.match(/version\/([\.\d]+)/i);
20062               if (m !== null) _detected.version = m[1];
20063             }
20064           }
20065
20066           if (!_detected.browser) {
20067             _detected.browser = navigator.appName;
20068             _detected.version = navigator.appVersion;
20069           } // keep major.minor version only..
20070
20071
20072           _detected.version = _detected.version.split(/\W/).slice(0, 2).join('.'); // detect other browser capabilities
20073           // Legacy Opera has incomplete svg style support. See #715
20074
20075           _detected.opera = _detected.browser.toLowerCase() === 'opera' && parseFloat(_detected.version) < 15;
20076
20077           if (_detected.browser.toLowerCase() === 'msie') {
20078             _detected.ie = true;
20079             _detected.browser = 'Internet Explorer';
20080             _detected.support = parseFloat(_detected.version) >= 11;
20081           } else {
20082             _detected.ie = false;
20083             _detected.support = true;
20084           }
20085
20086           _detected.filedrop = window.FileReader && 'ondrop' in window;
20087           _detected.download = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
20088           _detected.cssfilters = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
20089           /* Platform */
20090
20091           if (/Win/.test(ua)) {
20092             _detected.os = 'win';
20093             _detected.platform = 'Windows';
20094           } else if (/Mac/.test(ua)) {
20095             _detected.os = 'mac';
20096             _detected.platform = 'Macintosh';
20097           } else if (/X11/.test(ua) || /Linux/.test(ua)) {
20098             _detected.os = 'linux';
20099             _detected.platform = 'Linux';
20100           } else {
20101             _detected.os = 'win';
20102             _detected.platform = 'Unknown';
20103           }
20104
20105           _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
20106           // so assume any "mac" with multitouch is actually iOS
20107           navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
20108           /* Locale */
20109           // An array of locales requested by the browser in priority order.
20110
20111           _detected.browserLocales = Array.from(new Set( // remove duplicates
20112           [navigator.language].concat(navigator.languages || []).concat([// old property for backwards compatibility
20113           navigator.userLanguage]) // remove any undefined values
20114           .filter(Boolean)));
20115           /* Host */
20116
20117           var loc = window.top.location;
20118           var origin = loc.origin;
20119
20120           if (!origin) {
20121             // for unpatched IE11
20122             origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port : '');
20123           }
20124
20125           _detected.host = origin + loc.pathname;
20126           return _detected;
20127         }
20128
20129         // `Number.MAX_SAFE_INTEGER` constant
20130         // https://tc39.es/ecma262/#sec-number.max_safe_integer
20131         _export({ target: 'Number', stat: true }, {
20132           MAX_SAFE_INTEGER: 0x1FFFFFFFFFFFFF
20133         });
20134
20135         var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
20136         var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
20137         var defineProperty$9 = objectDefineProperty.f;
20138         var trim$2 = stringTrim.trim;
20139
20140         var NUMBER = 'Number';
20141         var NativeNumber = global_1[NUMBER];
20142         var NumberPrototype = NativeNumber.prototype;
20143
20144         // Opera ~12 has broken Object#toString
20145         var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER;
20146
20147         // `ToNumber` abstract operation
20148         // https://tc39.es/ecma262/#sec-tonumber
20149         var toNumber = function (argument) {
20150           var it = toPrimitive(argument, false);
20151           var first, third, radix, maxCode, digits, length, index, code;
20152           if (typeof it == 'string' && it.length > 2) {
20153             it = trim$2(it);
20154             first = it.charCodeAt(0);
20155             if (first === 43 || first === 45) {
20156               third = it.charCodeAt(2);
20157               if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
20158             } else if (first === 48) {
20159               switch (it.charCodeAt(1)) {
20160                 case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
20161                 case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
20162                 default: return +it;
20163               }
20164               digits = it.slice(2);
20165               length = digits.length;
20166               for (index = 0; index < length; index++) {
20167                 code = digits.charCodeAt(index);
20168                 // parseInt parses a string to a first unavailable symbol
20169                 // but ToNumber should return NaN if a string contains unavailable symbols
20170                 if (code < 48 || code > maxCode) return NaN;
20171               } return parseInt(digits, radix);
20172             }
20173           } return +it;
20174         };
20175
20176         // `Number` constructor
20177         // https://tc39.es/ecma262/#sec-number-constructor
20178         if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
20179           var NumberWrapper = function Number(value) {
20180             var it = arguments.length < 1 ? 0 : value;
20181             var dummy = this;
20182             return dummy instanceof NumberWrapper
20183               // check on 1..constructor(foo) case
20184               && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER)
20185                 ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it);
20186           };
20187           for (var keys$3 = descriptors ? getOwnPropertyNames$2(NativeNumber) : (
20188             // ES3:
20189             'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
20190             // ES2015 (in case, if modules with ES2015 Number statics required before):
20191             'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
20192             'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,' +
20193             // ESNext
20194             'fromString,range'
20195           ).split(','), j$2 = 0, key$1; keys$3.length > j$2; j$2++) {
20196             if (has(NativeNumber, key$1 = keys$3[j$2]) && !has(NumberWrapper, key$1)) {
20197               defineProperty$9(NumberWrapper, key$1, getOwnPropertyDescriptor$3(NativeNumber, key$1));
20198             }
20199           }
20200           NumberWrapper.prototype = NumberPrototype;
20201           NumberPrototype.constructor = NumberWrapper;
20202           redefine(global_1, NUMBER, NumberWrapper);
20203         }
20204
20205         var aesJs = createCommonjsModule(function (module, exports) {
20206           /*! MIT License. Copyright 2015-2018 Richard Moore <me@ricmoo.com>. See LICENSE.txt. */
20207           (function (root) {
20208
20209             function checkInt(value) {
20210               return parseInt(value) === value;
20211             }
20212
20213             function checkInts(arrayish) {
20214               if (!checkInt(arrayish.length)) {
20215                 return false;
20216               }
20217
20218               for (var i = 0; i < arrayish.length; i++) {
20219                 if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
20220                   return false;
20221                 }
20222               }
20223
20224               return true;
20225             }
20226
20227             function coerceArray(arg, copy) {
20228               // ArrayBuffer view
20229               if (arg.buffer && arg.name === 'Uint8Array') {
20230                 if (copy) {
20231                   if (arg.slice) {
20232                     arg = arg.slice();
20233                   } else {
20234                     arg = Array.prototype.slice.call(arg);
20235                   }
20236                 }
20237
20238                 return arg;
20239               } // It's an array; check it is a valid representation of a byte
20240
20241
20242               if (Array.isArray(arg)) {
20243                 if (!checkInts(arg)) {
20244                   throw new Error('Array contains invalid value: ' + arg);
20245                 }
20246
20247                 return new Uint8Array(arg);
20248               } // Something else, but behaves like an array (maybe a Buffer? Arguments?)
20249
20250
20251               if (checkInt(arg.length) && checkInts(arg)) {
20252                 return new Uint8Array(arg);
20253               }
20254
20255               throw new Error('unsupported array-like object');
20256             }
20257
20258             function createArray(length) {
20259               return new Uint8Array(length);
20260             }
20261
20262             function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
20263               if (sourceStart != null || sourceEnd != null) {
20264                 if (sourceArray.slice) {
20265                   sourceArray = sourceArray.slice(sourceStart, sourceEnd);
20266                 } else {
20267                   sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
20268                 }
20269               }
20270
20271               targetArray.set(sourceArray, targetStart);
20272             }
20273
20274             var convertUtf8 = function () {
20275               function toBytes(text) {
20276                 var result = [],
20277                     i = 0;
20278                 text = encodeURI(text);
20279
20280                 while (i < text.length) {
20281                   var c = text.charCodeAt(i++); // if it is a % sign, encode the following 2 bytes as a hex value
20282
20283                   if (c === 37) {
20284                     result.push(parseInt(text.substr(i, 2), 16));
20285                     i += 2; // otherwise, just the actual byte
20286                   } else {
20287                     result.push(c);
20288                   }
20289                 }
20290
20291                 return coerceArray(result);
20292               }
20293
20294               function fromBytes(bytes) {
20295                 var result = [],
20296                     i = 0;
20297
20298                 while (i < bytes.length) {
20299                   var c = bytes[i];
20300
20301                   if (c < 128) {
20302                     result.push(String.fromCharCode(c));
20303                     i++;
20304                   } else if (c > 191 && c < 224) {
20305                     result.push(String.fromCharCode((c & 0x1f) << 6 | bytes[i + 1] & 0x3f));
20306                     i += 2;
20307                   } else {
20308                     result.push(String.fromCharCode((c & 0x0f) << 12 | (bytes[i + 1] & 0x3f) << 6 | bytes[i + 2] & 0x3f));
20309                     i += 3;
20310                   }
20311                 }
20312
20313                 return result.join('');
20314               }
20315
20316               return {
20317                 toBytes: toBytes,
20318                 fromBytes: fromBytes
20319               };
20320             }();
20321
20322             var convertHex = function () {
20323               function toBytes(text) {
20324                 var result = [];
20325
20326                 for (var i = 0; i < text.length; i += 2) {
20327                   result.push(parseInt(text.substr(i, 2), 16));
20328                 }
20329
20330                 return result;
20331               } // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
20332
20333
20334               var Hex = '0123456789abcdef';
20335
20336               function fromBytes(bytes) {
20337                 var result = [];
20338
20339                 for (var i = 0; i < bytes.length; i++) {
20340                   var v = bytes[i];
20341                   result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
20342                 }
20343
20344                 return result.join('');
20345               }
20346
20347               return {
20348                 toBytes: toBytes,
20349                 fromBytes: fromBytes
20350               };
20351             }(); // Number of rounds by keysize
20352
20353
20354             var numberOfRounds = {
20355               16: 10,
20356               24: 12,
20357               32: 14
20358             }; // Round constant words
20359
20360             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)
20361
20362             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];
20363             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
20364
20365             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];
20366             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];
20367             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];
20368             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
20369
20370             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];
20371             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];
20372             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];
20373             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
20374
20375             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];
20376             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];
20377             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];
20378             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];
20379
20380             function convertToInt32(bytes) {
20381               var result = [];
20382
20383               for (var i = 0; i < bytes.length; i += 4) {
20384                 result.push(bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]);
20385               }
20386
20387               return result;
20388             }
20389
20390             var AES = function AES(key) {
20391               if (!(this instanceof AES)) {
20392                 throw Error('AES must be instanitated with `new`');
20393               }
20394
20395               Object.defineProperty(this, 'key', {
20396                 value: coerceArray(key, true)
20397               });
20398
20399               this._prepare();
20400             };
20401
20402             AES.prototype._prepare = function () {
20403               var rounds = numberOfRounds[this.key.length];
20404
20405               if (rounds == null) {
20406                 throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
20407               } // encryption round keys
20408
20409
20410               this._Ke = []; // decryption round keys
20411
20412               this._Kd = [];
20413
20414               for (var i = 0; i <= rounds; i++) {
20415                 this._Ke.push([0, 0, 0, 0]);
20416
20417                 this._Kd.push([0, 0, 0, 0]);
20418               }
20419
20420               var roundKeyCount = (rounds + 1) * 4;
20421               var KC = this.key.length / 4; // convert the key into ints
20422
20423               var tk = convertToInt32(this.key); // copy values into round key arrays
20424
20425               var index;
20426
20427               for (var i = 0; i < KC; i++) {
20428                 index = i >> 2;
20429                 this._Ke[index][i % 4] = tk[i];
20430                 this._Kd[rounds - index][i % 4] = tk[i];
20431               } // key expansion (fips-197 section 5.2)
20432
20433
20434               var rconpointer = 0;
20435               var t = KC,
20436                   tt;
20437
20438               while (t < roundKeyCount) {
20439                 tt = tk[KC - 1];
20440                 tk[0] ^= S[tt >> 16 & 0xFF] << 24 ^ S[tt >> 8 & 0xFF] << 16 ^ S[tt & 0xFF] << 8 ^ S[tt >> 24 & 0xFF] ^ rcon[rconpointer] << 24;
20441                 rconpointer += 1; // key expansion (for non-256 bit)
20442
20443                 if (KC != 8) {
20444                   for (var i = 1; i < KC; i++) {
20445                     tk[i] ^= tk[i - 1];
20446                   } // key expansion for 256-bit keys is "slightly different" (fips-197)
20447
20448                 } else {
20449                   for (var i = 1; i < KC / 2; i++) {
20450                     tk[i] ^= tk[i - 1];
20451                   }
20452
20453                   tt = tk[KC / 2 - 1];
20454                   tk[KC / 2] ^= S[tt & 0xFF] ^ S[tt >> 8 & 0xFF] << 8 ^ S[tt >> 16 & 0xFF] << 16 ^ S[tt >> 24 & 0xFF] << 24;
20455
20456                   for (var i = KC / 2 + 1; i < KC; i++) {
20457                     tk[i] ^= tk[i - 1];
20458                   }
20459                 } // copy values into round key arrays
20460
20461
20462                 var i = 0,
20463                     r,
20464                     c;
20465
20466                 while (i < KC && t < roundKeyCount) {
20467                   r = t >> 2;
20468                   c = t % 4;
20469                   this._Ke[r][c] = tk[i];
20470                   this._Kd[rounds - r][c] = tk[i++];
20471                   t++;
20472                 }
20473               } // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
20474
20475
20476               for (var r = 1; r < rounds; r++) {
20477                 for (var c = 0; c < 4; c++) {
20478                   tt = this._Kd[r][c];
20479                   this._Kd[r][c] = U1[tt >> 24 & 0xFF] ^ U2[tt >> 16 & 0xFF] ^ U3[tt >> 8 & 0xFF] ^ U4[tt & 0xFF];
20480                 }
20481               }
20482             };
20483
20484             AES.prototype.encrypt = function (plaintext) {
20485               if (plaintext.length != 16) {
20486                 throw new Error('invalid plaintext size (must be 16 bytes)');
20487               }
20488
20489               var rounds = this._Ke.length - 1;
20490               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
20491
20492               var t = convertToInt32(plaintext);
20493
20494               for (var i = 0; i < 4; i++) {
20495                 t[i] ^= this._Ke[0][i];
20496               } // apply round transforms
20497
20498
20499               for (var r = 1; r < rounds; r++) {
20500                 for (var i = 0; i < 4; i++) {
20501                   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];
20502                 }
20503
20504                 t = a.slice();
20505               } // the last round is special
20506
20507
20508               var result = createArray(16),
20509                   tt;
20510
20511               for (var i = 0; i < 4; i++) {
20512                 tt = this._Ke[rounds][i];
20513                 result[4 * i] = (S[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
20514                 result[4 * i + 1] = (S[t[(i + 1) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
20515                 result[4 * i + 2] = (S[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
20516                 result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
20517               }
20518
20519               return result;
20520             };
20521
20522             AES.prototype.decrypt = function (ciphertext) {
20523               if (ciphertext.length != 16) {
20524                 throw new Error('invalid ciphertext size (must be 16 bytes)');
20525               }
20526
20527               var rounds = this._Kd.length - 1;
20528               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
20529
20530               var t = convertToInt32(ciphertext);
20531
20532               for (var i = 0; i < 4; i++) {
20533                 t[i] ^= this._Kd[0][i];
20534               } // apply round transforms
20535
20536
20537               for (var r = 1; r < rounds; r++) {
20538                 for (var i = 0; i < 4; i++) {
20539                   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];
20540                 }
20541
20542                 t = a.slice();
20543               } // the last round is special
20544
20545
20546               var result = createArray(16),
20547                   tt;
20548
20549               for (var i = 0; i < 4; i++) {
20550                 tt = this._Kd[rounds][i];
20551                 result[4 * i] = (Si[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
20552                 result[4 * i + 1] = (Si[t[(i + 3) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
20553                 result[4 * i + 2] = (Si[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
20554                 result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
20555               }
20556
20557               return result;
20558             };
20559             /**
20560              *  Mode Of Operation - Electonic Codebook (ECB)
20561              */
20562
20563
20564             var ModeOfOperationECB = function ModeOfOperationECB(key) {
20565               if (!(this instanceof ModeOfOperationECB)) {
20566                 throw Error('AES must be instanitated with `new`');
20567               }
20568
20569               this.description = "Electronic Code Block";
20570               this.name = "ecb";
20571               this._aes = new AES(key);
20572             };
20573
20574             ModeOfOperationECB.prototype.encrypt = function (plaintext) {
20575               plaintext = coerceArray(plaintext);
20576
20577               if (plaintext.length % 16 !== 0) {
20578                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
20579               }
20580
20581               var ciphertext = createArray(plaintext.length);
20582               var block = createArray(16);
20583
20584               for (var i = 0; i < plaintext.length; i += 16) {
20585                 copyArray(plaintext, block, 0, i, i + 16);
20586                 block = this._aes.encrypt(block);
20587                 copyArray(block, ciphertext, i);
20588               }
20589
20590               return ciphertext;
20591             };
20592
20593             ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
20594               ciphertext = coerceArray(ciphertext);
20595
20596               if (ciphertext.length % 16 !== 0) {
20597                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
20598               }
20599
20600               var plaintext = createArray(ciphertext.length);
20601               var block = createArray(16);
20602
20603               for (var i = 0; i < ciphertext.length; i += 16) {
20604                 copyArray(ciphertext, block, 0, i, i + 16);
20605                 block = this._aes.decrypt(block);
20606                 copyArray(block, plaintext, i);
20607               }
20608
20609               return plaintext;
20610             };
20611             /**
20612              *  Mode Of Operation - Cipher Block Chaining (CBC)
20613              */
20614
20615
20616             var ModeOfOperationCBC = function ModeOfOperationCBC(key, iv) {
20617               if (!(this instanceof ModeOfOperationCBC)) {
20618                 throw Error('AES must be instanitated with `new`');
20619               }
20620
20621               this.description = "Cipher Block Chaining";
20622               this.name = "cbc";
20623
20624               if (!iv) {
20625                 iv = createArray(16);
20626               } else if (iv.length != 16) {
20627                 throw new Error('invalid initialation vector size (must be 16 bytes)');
20628               }
20629
20630               this._lastCipherblock = coerceArray(iv, true);
20631               this._aes = new AES(key);
20632             };
20633
20634             ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
20635               plaintext = coerceArray(plaintext);
20636
20637               if (plaintext.length % 16 !== 0) {
20638                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
20639               }
20640
20641               var ciphertext = createArray(plaintext.length);
20642               var block = createArray(16);
20643
20644               for (var i = 0; i < plaintext.length; i += 16) {
20645                 copyArray(plaintext, block, 0, i, i + 16);
20646
20647                 for (var j = 0; j < 16; j++) {
20648                   block[j] ^= this._lastCipherblock[j];
20649                 }
20650
20651                 this._lastCipherblock = this._aes.encrypt(block);
20652                 copyArray(this._lastCipherblock, ciphertext, i);
20653               }
20654
20655               return ciphertext;
20656             };
20657
20658             ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
20659               ciphertext = coerceArray(ciphertext);
20660
20661               if (ciphertext.length % 16 !== 0) {
20662                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
20663               }
20664
20665               var plaintext = createArray(ciphertext.length);
20666               var block = createArray(16);
20667
20668               for (var i = 0; i < ciphertext.length; i += 16) {
20669                 copyArray(ciphertext, block, 0, i, i + 16);
20670                 block = this._aes.decrypt(block);
20671
20672                 for (var j = 0; j < 16; j++) {
20673                   plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
20674                 }
20675
20676                 copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
20677               }
20678
20679               return plaintext;
20680             };
20681             /**
20682              *  Mode Of Operation - Cipher Feedback (CFB)
20683              */
20684
20685
20686             var ModeOfOperationCFB = function ModeOfOperationCFB(key, iv, segmentSize) {
20687               if (!(this instanceof ModeOfOperationCFB)) {
20688                 throw Error('AES must be instanitated with `new`');
20689               }
20690
20691               this.description = "Cipher Feedback";
20692               this.name = "cfb";
20693
20694               if (!iv) {
20695                 iv = createArray(16);
20696               } else if (iv.length != 16) {
20697                 throw new Error('invalid initialation vector size (must be 16 size)');
20698               }
20699
20700               if (!segmentSize) {
20701                 segmentSize = 1;
20702               }
20703
20704               this.segmentSize = segmentSize;
20705               this._shiftRegister = coerceArray(iv, true);
20706               this._aes = new AES(key);
20707             };
20708
20709             ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
20710               if (plaintext.length % this.segmentSize != 0) {
20711                 throw new Error('invalid plaintext size (must be segmentSize bytes)');
20712               }
20713
20714               var encrypted = coerceArray(plaintext, true);
20715               var xorSegment;
20716
20717               for (var i = 0; i < encrypted.length; i += this.segmentSize) {
20718                 xorSegment = this._aes.encrypt(this._shiftRegister);
20719
20720                 for (var j = 0; j < this.segmentSize; j++) {
20721                   encrypted[i + j] ^= xorSegment[j];
20722                 } // Shift the register
20723
20724
20725                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
20726                 copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
20727               }
20728
20729               return encrypted;
20730             };
20731
20732             ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
20733               if (ciphertext.length % this.segmentSize != 0) {
20734                 throw new Error('invalid ciphertext size (must be segmentSize bytes)');
20735               }
20736
20737               var plaintext = coerceArray(ciphertext, true);
20738               var xorSegment;
20739
20740               for (var i = 0; i < plaintext.length; i += this.segmentSize) {
20741                 xorSegment = this._aes.encrypt(this._shiftRegister);
20742
20743                 for (var j = 0; j < this.segmentSize; j++) {
20744                   plaintext[i + j] ^= xorSegment[j];
20745                 } // Shift the register
20746
20747
20748                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
20749                 copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
20750               }
20751
20752               return plaintext;
20753             };
20754             /**
20755              *  Mode Of Operation - Output Feedback (OFB)
20756              */
20757
20758
20759             var ModeOfOperationOFB = function ModeOfOperationOFB(key, iv) {
20760               if (!(this instanceof ModeOfOperationOFB)) {
20761                 throw Error('AES must be instanitated with `new`');
20762               }
20763
20764               this.description = "Output Feedback";
20765               this.name = "ofb";
20766
20767               if (!iv) {
20768                 iv = createArray(16);
20769               } else if (iv.length != 16) {
20770                 throw new Error('invalid initialation vector size (must be 16 bytes)');
20771               }
20772
20773               this._lastPrecipher = coerceArray(iv, true);
20774               this._lastPrecipherIndex = 16;
20775               this._aes = new AES(key);
20776             };
20777
20778             ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
20779               var encrypted = coerceArray(plaintext, true);
20780
20781               for (var i = 0; i < encrypted.length; i++) {
20782                 if (this._lastPrecipherIndex === 16) {
20783                   this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
20784                   this._lastPrecipherIndex = 0;
20785                 }
20786
20787                 encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
20788               }
20789
20790               return encrypted;
20791             }; // Decryption is symetric
20792
20793
20794             ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
20795             /**
20796              *  Counter object for CTR common mode of operation
20797              */
20798
20799             var Counter = function Counter(initialValue) {
20800               if (!(this instanceof Counter)) {
20801                 throw Error('Counter must be instanitated with `new`');
20802               } // We allow 0, but anything false-ish uses the default 1
20803
20804
20805               if (initialValue !== 0 && !initialValue) {
20806                 initialValue = 1;
20807               }
20808
20809               if (typeof initialValue === 'number') {
20810                 this._counter = createArray(16);
20811                 this.setValue(initialValue);
20812               } else {
20813                 this.setBytes(initialValue);
20814               }
20815             };
20816
20817             Counter.prototype.setValue = function (value) {
20818               if (typeof value !== 'number' || parseInt(value) != value) {
20819                 throw new Error('invalid counter value (must be an integer)');
20820               } // We cannot safely handle numbers beyond the safe range for integers
20821
20822
20823               if (value > Number.MAX_SAFE_INTEGER) {
20824                 throw new Error('integer value out of safe range');
20825               }
20826
20827               for (var index = 15; index >= 0; --index) {
20828                 this._counter[index] = value % 256;
20829                 value = parseInt(value / 256);
20830               }
20831             };
20832
20833             Counter.prototype.setBytes = function (bytes) {
20834               bytes = coerceArray(bytes, true);
20835
20836               if (bytes.length != 16) {
20837                 throw new Error('invalid counter bytes size (must be 16 bytes)');
20838               }
20839
20840               this._counter = bytes;
20841             };
20842
20843             Counter.prototype.increment = function () {
20844               for (var i = 15; i >= 0; i--) {
20845                 if (this._counter[i] === 255) {
20846                   this._counter[i] = 0;
20847                 } else {
20848                   this._counter[i]++;
20849                   break;
20850                 }
20851               }
20852             };
20853             /**
20854              *  Mode Of Operation - Counter (CTR)
20855              */
20856
20857
20858             var ModeOfOperationCTR = function ModeOfOperationCTR(key, counter) {
20859               if (!(this instanceof ModeOfOperationCTR)) {
20860                 throw Error('AES must be instanitated with `new`');
20861               }
20862
20863               this.description = "Counter";
20864               this.name = "ctr";
20865
20866               if (!(counter instanceof Counter)) {
20867                 counter = new Counter(counter);
20868               }
20869
20870               this._counter = counter;
20871               this._remainingCounter = null;
20872               this._remainingCounterIndex = 16;
20873               this._aes = new AES(key);
20874             };
20875
20876             ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
20877               var encrypted = coerceArray(plaintext, true);
20878
20879               for (var i = 0; i < encrypted.length; i++) {
20880                 if (this._remainingCounterIndex === 16) {
20881                   this._remainingCounter = this._aes.encrypt(this._counter._counter);
20882                   this._remainingCounterIndex = 0;
20883
20884                   this._counter.increment();
20885                 }
20886
20887                 encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
20888               }
20889
20890               return encrypted;
20891             }; // Decryption is symetric
20892
20893
20894             ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; ///////////////////////
20895             // Padding
20896             // See:https://tools.ietf.org/html/rfc2315
20897
20898             function pkcs7pad(data) {
20899               data = coerceArray(data, true);
20900               var padder = 16 - data.length % 16;
20901               var result = createArray(data.length + padder);
20902               copyArray(data, result);
20903
20904               for (var i = data.length; i < result.length; i++) {
20905                 result[i] = padder;
20906               }
20907
20908               return result;
20909             }
20910
20911             function pkcs7strip(data) {
20912               data = coerceArray(data, true);
20913
20914               if (data.length < 16) {
20915                 throw new Error('PKCS#7 invalid length');
20916               }
20917
20918               var padder = data[data.length - 1];
20919
20920               if (padder > 16) {
20921                 throw new Error('PKCS#7 padding byte out of range');
20922               }
20923
20924               var length = data.length - padder;
20925
20926               for (var i = 0; i < padder; i++) {
20927                 if (data[length + i] !== padder) {
20928                   throw new Error('PKCS#7 invalid padding byte');
20929                 }
20930               }
20931
20932               var result = createArray(length);
20933               copyArray(data, result, 0, 0, length);
20934               return result;
20935             } ///////////////////////
20936             // Exporting
20937             // The block cipher
20938
20939
20940             var aesjs = {
20941               AES: AES,
20942               Counter: Counter,
20943               ModeOfOperation: {
20944                 ecb: ModeOfOperationECB,
20945                 cbc: ModeOfOperationCBC,
20946                 cfb: ModeOfOperationCFB,
20947                 ofb: ModeOfOperationOFB,
20948                 ctr: ModeOfOperationCTR
20949               },
20950               utils: {
20951                 hex: convertHex,
20952                 utf8: convertUtf8
20953               },
20954               padding: {
20955                 pkcs7: {
20956                   pad: pkcs7pad,
20957                   strip: pkcs7strip
20958                 }
20959               },
20960               _arrayTest: {
20961                 coerceArray: coerceArray,
20962                 createArray: createArray,
20963                 copyArray: copyArray
20964               }
20965             }; // node.js
20966
20967             {
20968               module.exports = aesjs; // RequireJS/AMD
20969               // http://www.requirejs.org/docs/api.html
20970               // https://github.com/amdjs/amdjs-api/wiki/AMD
20971             }
20972           })();
20973         });
20974
20975         // We can use keys that are 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes).
20976         // To generate a random key:  window.crypto.getRandomValues(new Uint8Array(16));
20977         // This default signing key is built into iD and can be used to mask/unmask sensitive values.
20978
20979         var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
20980         function utilAesEncrypt(text, key) {
20981           key = key || DEFAULT_128;
20982           var textBytes = aesJs.utils.utf8.toBytes(text);
20983           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
20984           var encryptedBytes = aesCtr.encrypt(textBytes);
20985           var encryptedHex = aesJs.utils.hex.fromBytes(encryptedBytes);
20986           return encryptedHex;
20987         }
20988         function utilAesDecrypt(encryptedHex, key) {
20989           key = key || DEFAULT_128;
20990           var encryptedBytes = aesJs.utils.hex.toBytes(encryptedHex);
20991           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
20992           var decryptedBytes = aesCtr.decrypt(encryptedBytes);
20993           var text = aesJs.utils.utf8.fromBytes(decryptedBytes);
20994           return text;
20995         }
20996
20997         function utilCleanTags(tags) {
20998           var out = {};
20999
21000           for (var k in tags) {
21001             if (!k) continue;
21002             var v = tags[k];
21003
21004             if (v !== undefined) {
21005               out[k] = cleanValue(k, v);
21006             }
21007           }
21008
21009           return out;
21010
21011           function cleanValue(k, v) {
21012             function keepSpaces(k) {
21013               return /_hours|_times|:conditional$/.test(k);
21014             }
21015
21016             function skip(k) {
21017               return /^(description|note|fixme)$/.test(k);
21018             }
21019
21020             if (skip(k)) return v;
21021             var cleaned = v.split(';').map(function (s) {
21022               return s.trim();
21023             }).join(keepSpaces(k) ? '; ' : ';'); // The code below is not intended to validate websites and emails.
21024             // It is only intended to prevent obvious copy-paste errors. (#2323)
21025             // clean website- and email-like tags
21026
21027             if (k.indexOf('website') !== -1 || k.indexOf('email') !== -1 || cleaned.indexOf('http') === 0) {
21028               cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
21029             }
21030
21031             return cleaned;
21032           }
21033         }
21034
21035         // Like selection.property('value', ...), but avoids no-op value sets,
21036         // which can result in layout/repaint thrashing in some situations.
21037         function utilGetSetValue(selection, value) {
21038           function d3_selection_value(value) {
21039             function valueNull() {
21040               delete this.value;
21041             }
21042
21043             function valueConstant() {
21044               if (this.value !== value) {
21045                 this.value = value;
21046               }
21047             }
21048
21049             function valueFunction() {
21050               var x = value.apply(this, arguments);
21051
21052               if (x === null || x === undefined) {
21053                 delete this.value;
21054               } else if (this.value !== x) {
21055                 this.value = x;
21056               }
21057             }
21058
21059             return value === null || value === undefined ? valueNull : typeof value === 'function' ? valueFunction : valueConstant;
21060           }
21061
21062           if (arguments.length === 1) {
21063             return selection.property('value');
21064           }
21065
21066           return selection.each(d3_selection_value(value));
21067         }
21068
21069         function utilKeybinding(namespace) {
21070           var _keybindings = {};
21071
21072           function testBindings(d3_event, isCapturing) {
21073             var didMatch = false;
21074             var bindings = Object.keys(_keybindings).map(function (id) {
21075               return _keybindings[id];
21076             });
21077             var i, binding; // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
21078             // so we don't strictly match on the shift key, but we prioritize
21079             // shifted keybindings first, and fallback to unshifted only if no match.
21080             // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
21081             // priority match shifted keybindings first
21082
21083             for (i = 0; i < bindings.length; i++) {
21084               binding = bindings[i];
21085               if (!binding.event.modifiers.shiftKey) continue; // no shift
21086
21087               if (!!binding.capture !== isCapturing) continue;
21088
21089               if (matches(d3_event, binding, true)) {
21090                 binding.callback(d3_event);
21091                 didMatch = true; // match a max of one binding per event
21092
21093                 break;
21094               }
21095             }
21096
21097             if (didMatch) return; // then unshifted keybindings
21098
21099             for (i = 0; i < bindings.length; i++) {
21100               binding = bindings[i];
21101               if (binding.event.modifiers.shiftKey) continue; // shift
21102
21103               if (!!binding.capture !== isCapturing) continue;
21104
21105               if (matches(d3_event, binding, false)) {
21106                 binding.callback(d3_event);
21107                 break;
21108               }
21109             }
21110
21111             function matches(d3_event, binding, testShift) {
21112               var event = d3_event;
21113               var isMatch = false;
21114               var tryKeyCode = true; // Prefer a match on `KeyboardEvent.key`
21115
21116               if (event.key !== undefined) {
21117                 tryKeyCode = event.key.charCodeAt(0) > 255; // outside ISO-Latin-1
21118
21119                 isMatch = true;
21120
21121                 if (binding.event.key === undefined) {
21122                   isMatch = false;
21123                 } else if (Array.isArray(binding.event.key)) {
21124                   if (binding.event.key.map(function (s) {
21125                     return s.toLowerCase();
21126                   }).indexOf(event.key.toLowerCase()) === -1) isMatch = false;
21127                 } else {
21128                   if (event.key.toLowerCase() !== binding.event.key.toLowerCase()) isMatch = false;
21129                 }
21130               } // Fallback match on `KeyboardEvent.keyCode`, can happen if:
21131               // - browser doesn't support `KeyboardEvent.key`
21132               // - `KeyboardEvent.key` is outside ISO-Latin-1 range (cyrillic?)
21133
21134
21135               if (!isMatch && tryKeyCode) {
21136                 isMatch = event.keyCode === binding.event.keyCode;
21137               }
21138
21139               if (!isMatch) return false; // test modifier keys
21140
21141               if (!(event.ctrlKey && event.altKey)) {
21142                 // if both are set, assume AltGr and skip it - #4096
21143                 if (event.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
21144                 if (event.altKey !== binding.event.modifiers.altKey) return false;
21145               }
21146
21147               if (event.metaKey !== binding.event.modifiers.metaKey) return false;
21148               if (testShift && event.shiftKey !== binding.event.modifiers.shiftKey) return false;
21149               return true;
21150             }
21151           }
21152
21153           function capture(d3_event) {
21154             testBindings(d3_event, true);
21155           }
21156
21157           function bubble(d3_event) {
21158             var tagName = select(d3_event.target).node().tagName;
21159
21160             if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
21161               return;
21162             }
21163
21164             testBindings(d3_event, false);
21165           }
21166
21167           function keybinding(selection) {
21168             selection = selection || select(document);
21169             selection.on('keydown.capture.' + namespace, capture, true);
21170             selection.on('keydown.bubble.' + namespace, bubble, false);
21171             return keybinding;
21172           } // was: keybinding.off()
21173
21174
21175           keybinding.unbind = function (selection) {
21176             _keybindings = [];
21177             selection = selection || select(document);
21178             selection.on('keydown.capture.' + namespace, null);
21179             selection.on('keydown.bubble.' + namespace, null);
21180             return keybinding;
21181           };
21182
21183           keybinding.clear = function () {
21184             _keybindings = {};
21185             return keybinding;
21186           }; // Remove one or more keycode bindings.
21187
21188
21189           keybinding.off = function (codes, capture) {
21190             var arr = utilArrayUniq([].concat(codes));
21191
21192             for (var i = 0; i < arr.length; i++) {
21193               var id = arr[i] + (capture ? '-capture' : '-bubble');
21194               delete _keybindings[id];
21195             }
21196
21197             return keybinding;
21198           }; // Add one or more keycode bindings.
21199
21200
21201           keybinding.on = function (codes, callback, capture) {
21202             if (typeof callback !== 'function') {
21203               return keybinding.off(codes, capture);
21204             }
21205
21206             var arr = utilArrayUniq([].concat(codes));
21207
21208             for (var i = 0; i < arr.length; i++) {
21209               var id = arr[i] + (capture ? '-capture' : '-bubble');
21210               var binding = {
21211                 id: id,
21212                 capture: capture,
21213                 callback: callback,
21214                 event: {
21215                   key: undefined,
21216                   // preferred
21217                   keyCode: 0,
21218                   // fallback
21219                   modifiers: {
21220                     shiftKey: false,
21221                     ctrlKey: false,
21222                     altKey: false,
21223                     metaKey: false
21224                   }
21225                 }
21226               };
21227
21228               if (_keybindings[id]) {
21229                 console.warn('warning: duplicate keybinding for "' + id + '"'); // eslint-disable-line no-console
21230               }
21231
21232               _keybindings[id] = binding;
21233               var matches = arr[i].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
21234
21235               for (var j = 0; j < matches.length; j++) {
21236                 // Normalise matching errors
21237                 if (matches[j] === '++') matches[j] = '+';
21238
21239                 if (matches[j] in utilKeybinding.modifierCodes) {
21240                   var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j]]];
21241                   binding.event.modifiers[prop] = true;
21242                 } else {
21243                   binding.event.key = utilKeybinding.keys[matches[j]] || matches[j];
21244
21245                   if (matches[j] in utilKeybinding.keyCodes) {
21246                     binding.event.keyCode = utilKeybinding.keyCodes[matches[j]];
21247                   }
21248                 }
21249               }
21250             }
21251
21252             return keybinding;
21253           };
21254
21255           return keybinding;
21256         }
21257         /*
21258          * See https://github.com/keithamus/jwerty
21259          */
21260
21261         utilKeybinding.modifierCodes = {
21262           // Shift key, ⇧
21263           '⇧': 16,
21264           shift: 16,
21265           // CTRL key, on Mac: ⌃
21266           '⌃': 17,
21267           ctrl: 17,
21268           // ALT key, on Mac: ⌥ (Alt)
21269           '⌥': 18,
21270           alt: 18,
21271           option: 18,
21272           // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
21273           '⌘': 91,
21274           meta: 91,
21275           cmd: 91,
21276           'super': 91,
21277           win: 91
21278         };
21279         utilKeybinding.modifierProperties = {
21280           16: 'shiftKey',
21281           17: 'ctrlKey',
21282           18: 'altKey',
21283           91: 'metaKey'
21284         };
21285         utilKeybinding.plusKeys = ['plus', 'ffplus', '=', 'ffequals', '≠', '±'];
21286         utilKeybinding.minusKeys = ['_', '-', 'ffminus', 'dash', '–', '—'];
21287         utilKeybinding.keys = {
21288           // Backspace key, on Mac: ⌫ (Backspace)
21289           '⌫': 'Backspace',
21290           backspace: 'Backspace',
21291           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
21292           '⇥': 'Tab',
21293           '⇆': 'Tab',
21294           tab: 'Tab',
21295           // Return key, ↩
21296           '↩': 'Enter',
21297           '↵': 'Enter',
21298           '⏎': 'Enter',
21299           'return': 'Enter',
21300           enter: 'Enter',
21301           '⌅': 'Enter',
21302           // Pause/Break key
21303           'pause': 'Pause',
21304           'pause-break': 'Pause',
21305           // Caps Lock key, ⇪
21306           '⇪': 'CapsLock',
21307           caps: 'CapsLock',
21308           'caps-lock': 'CapsLock',
21309           // Escape key, on Mac: ⎋, on Windows: Esc
21310           '⎋': ['Escape', 'Esc'],
21311           escape: ['Escape', 'Esc'],
21312           esc: ['Escape', 'Esc'],
21313           // Space key
21314           space: [' ', 'Spacebar'],
21315           // Page-Up key, or pgup, on Mac: ↖
21316           '↖': 'PageUp',
21317           pgup: 'PageUp',
21318           'page-up': 'PageUp',
21319           // Page-Down key, or pgdown, on Mac: ↘
21320           '↘': 'PageDown',
21321           pgdown: 'PageDown',
21322           'page-down': 'PageDown',
21323           // END key, on Mac: ⇟
21324           '⇟': 'End',
21325           end: 'End',
21326           // HOME key, on Mac: ⇞
21327           '⇞': 'Home',
21328           home: 'Home',
21329           // Insert key, or ins
21330           ins: 'Insert',
21331           insert: 'Insert',
21332           // Delete key, on Mac: ⌦ (Delete)
21333           '⌦': ['Delete', 'Del'],
21334           del: ['Delete', 'Del'],
21335           'delete': ['Delete', 'Del'],
21336           // Left Arrow Key, or ←
21337           '←': ['ArrowLeft', 'Left'],
21338           left: ['ArrowLeft', 'Left'],
21339           'arrow-left': ['ArrowLeft', 'Left'],
21340           // Up Arrow Key, or ↑
21341           '↑': ['ArrowUp', 'Up'],
21342           up: ['ArrowUp', 'Up'],
21343           'arrow-up': ['ArrowUp', 'Up'],
21344           // Right Arrow Key, or →
21345           '→': ['ArrowRight', 'Right'],
21346           right: ['ArrowRight', 'Right'],
21347           'arrow-right': ['ArrowRight', 'Right'],
21348           // Up Arrow Key, or ↓
21349           '↓': ['ArrowDown', 'Down'],
21350           down: ['ArrowDown', 'Down'],
21351           'arrow-down': ['ArrowDown', 'Down'],
21352           // odities, stuff for backward compatibility (browsers and code):
21353           // Num-Multiply, or *
21354           '*': ['*', 'Multiply'],
21355           star: ['*', 'Multiply'],
21356           asterisk: ['*', 'Multiply'],
21357           multiply: ['*', 'Multiply'],
21358           // Num-Plus or +
21359           '+': ['+', 'Add'],
21360           'plus': ['+', 'Add'],
21361           // Num-Subtract, or -
21362           '-': ['-', 'Subtract'],
21363           subtract: ['-', 'Subtract'],
21364           'dash': ['-', 'Subtract'],
21365           // Semicolon
21366           semicolon: ';',
21367           // = or equals
21368           equals: '=',
21369           // Comma, or ,
21370           comma: ',',
21371           // Period, or ., or full-stop
21372           period: '.',
21373           'full-stop': '.',
21374           // Slash, or /, or forward-slash
21375           slash: '/',
21376           'forward-slash': '/',
21377           // Tick, or `, or back-quote
21378           tick: '`',
21379           'back-quote': '`',
21380           // Open bracket, or [
21381           'open-bracket': '[',
21382           // Back slash, or \
21383           'back-slash': '\\',
21384           // Close backet, or ]
21385           'close-bracket': ']',
21386           // Apostrophe, or Quote, or '
21387           quote: '\'',
21388           apostrophe: '\'',
21389           // NUMPAD 0-9
21390           'num-0': '0',
21391           'num-1': '1',
21392           'num-2': '2',
21393           'num-3': '3',
21394           'num-4': '4',
21395           'num-5': '5',
21396           'num-6': '6',
21397           'num-7': '7',
21398           'num-8': '8',
21399           'num-9': '9',
21400           // F1-F25
21401           f1: 'F1',
21402           f2: 'F2',
21403           f3: 'F3',
21404           f4: 'F4',
21405           f5: 'F5',
21406           f6: 'F6',
21407           f7: 'F7',
21408           f8: 'F8',
21409           f9: 'F9',
21410           f10: 'F10',
21411           f11: 'F11',
21412           f12: 'F12',
21413           f13: 'F13',
21414           f14: 'F14',
21415           f15: 'F15',
21416           f16: 'F16',
21417           f17: 'F17',
21418           f18: 'F18',
21419           f19: 'F19',
21420           f20: 'F20',
21421           f21: 'F21',
21422           f22: 'F22',
21423           f23: 'F23',
21424           f24: 'F24',
21425           f25: 'F25'
21426         };
21427         utilKeybinding.keyCodes = {
21428           // Backspace key, on Mac: ⌫ (Backspace)
21429           '⌫': 8,
21430           backspace: 8,
21431           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
21432           '⇥': 9,
21433           '⇆': 9,
21434           tab: 9,
21435           // Return key, ↩
21436           '↩': 13,
21437           '↵': 13,
21438           '⏎': 13,
21439           'return': 13,
21440           enter: 13,
21441           '⌅': 13,
21442           // Pause/Break key
21443           'pause': 19,
21444           'pause-break': 19,
21445           // Caps Lock key, ⇪
21446           '⇪': 20,
21447           caps: 20,
21448           'caps-lock': 20,
21449           // Escape key, on Mac: ⎋, on Windows: Esc
21450           '⎋': 27,
21451           escape: 27,
21452           esc: 27,
21453           // Space key
21454           space: 32,
21455           // Page-Up key, or pgup, on Mac: ↖
21456           '↖': 33,
21457           pgup: 33,
21458           'page-up': 33,
21459           // Page-Down key, or pgdown, on Mac: ↘
21460           '↘': 34,
21461           pgdown: 34,
21462           'page-down': 34,
21463           // END key, on Mac: ⇟
21464           '⇟': 35,
21465           end: 35,
21466           // HOME key, on Mac: ⇞
21467           '⇞': 36,
21468           home: 36,
21469           // Insert key, or ins
21470           ins: 45,
21471           insert: 45,
21472           // Delete key, on Mac: ⌦ (Delete)
21473           '⌦': 46,
21474           del: 46,
21475           'delete': 46,
21476           // Left Arrow Key, or ←
21477           '←': 37,
21478           left: 37,
21479           'arrow-left': 37,
21480           // Up Arrow Key, or ↑
21481           '↑': 38,
21482           up: 38,
21483           'arrow-up': 38,
21484           // Right Arrow Key, or →
21485           '→': 39,
21486           right: 39,
21487           'arrow-right': 39,
21488           // Up Arrow Key, or ↓
21489           '↓': 40,
21490           down: 40,
21491           'arrow-down': 40,
21492           // odities, printing characters that come out wrong:
21493           // Firefox Equals
21494           'ffequals': 61,
21495           // Num-Multiply, or *
21496           '*': 106,
21497           star: 106,
21498           asterisk: 106,
21499           multiply: 106,
21500           // Num-Plus or +
21501           '+': 107,
21502           'plus': 107,
21503           // Num-Subtract, or -
21504           '-': 109,
21505           subtract: 109,
21506           // Firefox Plus
21507           'ffplus': 171,
21508           // Firefox Minus
21509           'ffminus': 173,
21510           // Semicolon
21511           ';': 186,
21512           semicolon: 186,
21513           // = or equals
21514           '=': 187,
21515           'equals': 187,
21516           // Comma, or ,
21517           ',': 188,
21518           comma: 188,
21519           // Dash / Underscore key
21520           'dash': 189,
21521           // Period, or ., or full-stop
21522           '.': 190,
21523           period: 190,
21524           'full-stop': 190,
21525           // Slash, or /, or forward-slash
21526           '/': 191,
21527           slash: 191,
21528           'forward-slash': 191,
21529           // Tick, or `, or back-quote
21530           '`': 192,
21531           tick: 192,
21532           'back-quote': 192,
21533           // Open bracket, or [
21534           '[': 219,
21535           'open-bracket': 219,
21536           // Back slash, or \
21537           '\\': 220,
21538           'back-slash': 220,
21539           // Close backet, or ]
21540           ']': 221,
21541           'close-bracket': 221,
21542           // Apostrophe, or Quote, or '
21543           '\'': 222,
21544           quote: 222,
21545           apostrophe: 222
21546         }; // NUMPAD 0-9
21547
21548         var i$1 = 95,
21549             n = 0;
21550
21551         while (++i$1 < 106) {
21552           utilKeybinding.keyCodes['num-' + n] = i$1;
21553           ++n;
21554         } // 0-9
21555
21556
21557         i$1 = 47;
21558         n = 0;
21559
21560         while (++i$1 < 58) {
21561           utilKeybinding.keyCodes[n] = i$1;
21562           ++n;
21563         } // F1-F25
21564
21565
21566         i$1 = 111;
21567         n = 1;
21568
21569         while (++i$1 < 136) {
21570           utilKeybinding.keyCodes['f' + n] = i$1;
21571           ++n;
21572         } // a-z
21573
21574
21575         i$1 = 64;
21576
21577         while (++i$1 < 91) {
21578           utilKeybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
21579         }
21580
21581         function utilObjectOmit(obj, omitKeys) {
21582           return Object.keys(obj).reduce(function (result, key) {
21583             if (omitKeys.indexOf(key) === -1) {
21584               result[key] = obj[key]; // keep
21585             }
21586
21587             return result;
21588           }, {});
21589         }
21590
21591         // Copies a variable number of methods from source to target.
21592         function utilRebind(target, source) {
21593           var i = 1,
21594               n = arguments.length,
21595               method;
21596
21597           while (++i < n) {
21598             target[method = arguments[i]] = d3_rebind(target, source, source[method]);
21599           }
21600
21601           return target;
21602         } // Method is assumed to be a standard D3 getter-setter:
21603         // If passed with no arguments, gets the value.
21604         // If passed with arguments, sets the value and returns the target.
21605
21606         function d3_rebind(target, source, method) {
21607           return function () {
21608             var value = method.apply(source, arguments);
21609             return value === source ? target : value;
21610           };
21611         }
21612
21613         // A per-domain session mutex backed by a cookie and dead man's
21614         // switch. If the session crashes, the mutex will auto-release
21615         // after 5 seconds.
21616         // This accepts a string and returns an object that complies with utilSessionMutexType
21617         function utilSessionMutex(name) {
21618           var mutex = {};
21619           var intervalID;
21620
21621           function renew() {
21622             var expires = new Date();
21623             expires.setSeconds(expires.getSeconds() + 5);
21624             document.cookie = name + '=1; expires=' + expires.toUTCString() + '; sameSite=strict';
21625           }
21626
21627           mutex.lock = function () {
21628             if (intervalID) return true;
21629             var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
21630             if (cookie) return false;
21631             renew();
21632             intervalID = window.setInterval(renew, 4000);
21633             return true;
21634           };
21635
21636           mutex.unlock = function () {
21637             if (!intervalID) return;
21638             document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict';
21639             clearInterval(intervalID);
21640             intervalID = null;
21641           };
21642
21643           mutex.locked = function () {
21644             return !!intervalID;
21645           };
21646
21647           return mutex;
21648         }
21649
21650         function utilTiler() {
21651           var _size = [256, 256];
21652           var _scale = 256;
21653           var _tileSize = 256;
21654           var _zoomExtent = [0, 20];
21655           var _translate = [_size[0] / 2, _size[1] / 2];
21656           var _margin = 0;
21657           var _skipNullIsland = false;
21658
21659           function clamp(num, min, max) {
21660             return Math.max(min, Math.min(num, max));
21661           }
21662
21663           function nearNullIsland(tile) {
21664             var x = tile[0];
21665             var y = tile[1];
21666             var z = tile[2];
21667
21668             if (z >= 7) {
21669               var center = Math.pow(2, z - 1);
21670               var width = Math.pow(2, z - 6);
21671               var min = center - width / 2;
21672               var max = center + width / 2 - 1;
21673               return x >= min && x <= max && y >= min && y <= max;
21674             }
21675
21676             return false;
21677           }
21678
21679           function tiler() {
21680             var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
21681             var z0 = clamp(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
21682             var tileMin = 0;
21683             var tileMax = Math.pow(2, z0) - 1;
21684             var log2ts = Math.log(_tileSize) * Math.LOG2E;
21685             var k = Math.pow(2, z - z0 + log2ts);
21686             var origin = [(_translate[0] - _scale / 2) / k, (_translate[1] - _scale / 2) / k];
21687             var cols = range(clamp(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1));
21688             var rows = range(clamp(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1));
21689             var tiles = [];
21690
21691             for (var i = 0; i < rows.length; i++) {
21692               var y = rows[i];
21693
21694               for (var j = 0; j < cols.length; j++) {
21695                 var x = cols[j];
21696
21697                 if (i >= _margin && i <= rows.length - _margin && j >= _margin && j <= cols.length - _margin) {
21698                   tiles.unshift([x, y, z0]); // tiles in view at beginning
21699                 } else {
21700                   tiles.push([x, y, z0]); // tiles in margin at the end
21701                 }
21702               }
21703             }
21704
21705             tiles.translate = origin;
21706             tiles.scale = k;
21707             return tiles;
21708           }
21709           /**
21710            * getTiles() returns an array of tiles that cover the map view
21711            */
21712
21713
21714           tiler.getTiles = function (projection) {
21715             var origin = [projection.scale() * Math.PI - projection.translate()[0], projection.scale() * Math.PI - projection.translate()[1]];
21716             this.size(projection.clipExtent()[1]).scale(projection.scale() * 2 * Math.PI).translate(projection.translate());
21717             var tiles = tiler();
21718             var ts = tiles.scale;
21719             return tiles.map(function (tile) {
21720               if (_skipNullIsland && nearNullIsland(tile)) {
21721                 return false;
21722               }
21723
21724               var x = tile[0] * ts - origin[0];
21725               var y = tile[1] * ts - origin[1];
21726               return {
21727                 id: tile.toString(),
21728                 xyz: tile,
21729                 extent: geoExtent(projection.invert([x, y + ts]), projection.invert([x + ts, y]))
21730               };
21731             }).filter(Boolean);
21732           };
21733           /**
21734            * getGeoJSON() returns a FeatureCollection for debugging tiles
21735            */
21736
21737
21738           tiler.getGeoJSON = function (projection) {
21739             var features = tiler.getTiles(projection).map(function (tile) {
21740               return {
21741                 type: 'Feature',
21742                 properties: {
21743                   id: tile.id,
21744                   name: tile.id
21745                 },
21746                 geometry: {
21747                   type: 'Polygon',
21748                   coordinates: [tile.extent.polygon()]
21749                 }
21750               };
21751             });
21752             return {
21753               type: 'FeatureCollection',
21754               features: features
21755             };
21756           };
21757
21758           tiler.tileSize = function (val) {
21759             if (!arguments.length) return _tileSize;
21760             _tileSize = val;
21761             return tiler;
21762           };
21763
21764           tiler.zoomExtent = function (val) {
21765             if (!arguments.length) return _zoomExtent;
21766             _zoomExtent = val;
21767             return tiler;
21768           };
21769
21770           tiler.size = function (val) {
21771             if (!arguments.length) return _size;
21772             _size = val;
21773             return tiler;
21774           };
21775
21776           tiler.scale = function (val) {
21777             if (!arguments.length) return _scale;
21778             _scale = val;
21779             return tiler;
21780           };
21781
21782           tiler.translate = function (val) {
21783             if (!arguments.length) return _translate;
21784             _translate = val;
21785             return tiler;
21786           }; // number to extend the rows/columns beyond those covering the viewport
21787
21788
21789           tiler.margin = function (val) {
21790             if (!arguments.length) return _margin;
21791             _margin = +val;
21792             return tiler;
21793           };
21794
21795           tiler.skipNullIsland = function (val) {
21796             if (!arguments.length) return _skipNullIsland;
21797             _skipNullIsland = val;
21798             return tiler;
21799           };
21800
21801           return tiler;
21802         }
21803
21804         function utilTriggerEvent(target, type) {
21805           target.each(function () {
21806             var evt = document.createEvent('HTMLEvents');
21807             evt.initEvent(type, true, true);
21808             this.dispatchEvent(evt);
21809           });
21810         }
21811
21812         var _mainLocalizer = coreLocalizer(); // singleton
21813
21814
21815         var _t = _mainLocalizer.t;
21816         // coreLocalizer manages language and locale parameters including translated strings
21817         //
21818
21819         function coreLocalizer() {
21820           var localizer = {};
21821           var _dataLanguages = {}; // `_dataLocales` is an object containing all _supported_ locale codes -> language info.
21822           // * `rtl` - right-to-left or left-to-right text direction
21823           // * `pct` - the percent of strings translated; 1 = 100%, full coverage
21824           //
21825           // {
21826           // en: { rtl: false, pct: {…} },
21827           // de: { rtl: false, pct: {…} },
21828           // …
21829           // }
21830
21831           var _dataLocales = {}; // `localeStrings` is an object containing all _loaded_ locale codes -> string data.
21832           // {
21833           // en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
21834           // de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
21835           // …
21836           // }
21837
21838           var _localeStrings = {}; // the current locale
21839
21840           var _localeCode = 'en-US'; // `_localeCodes` must contain `_localeCode` first, optionally followed by fallbacks
21841
21842           var _localeCodes = ['en-US', 'en'];
21843           var _languageCode = 'en';
21844           var _textDirection = 'ltr';
21845           var _usesMetric = false;
21846           var _languageNames = {};
21847           var _scriptNames = {}; // getters for the current locale parameters
21848
21849           localizer.localeCode = function () {
21850             return _localeCode;
21851           };
21852
21853           localizer.localeCodes = function () {
21854             return _localeCodes;
21855           };
21856
21857           localizer.languageCode = function () {
21858             return _languageCode;
21859           };
21860
21861           localizer.textDirection = function () {
21862             return _textDirection;
21863           };
21864
21865           localizer.usesMetric = function () {
21866             return _usesMetric;
21867           };
21868
21869           localizer.languageNames = function () {
21870             return _languageNames;
21871           };
21872
21873           localizer.scriptNames = function () {
21874             return _scriptNames;
21875           }; // The client app may want to manually set the locale, regardless of the
21876           // settings provided by the browser
21877
21878
21879           var _preferredLocaleCodes = [];
21880
21881           localizer.preferredLocaleCodes = function (codes) {
21882             if (!arguments.length) return _preferredLocaleCodes;
21883
21884             if (typeof codes === 'string') {
21885               // be generous and accept delimited strings as input
21886               _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
21887             } else {
21888               _preferredLocaleCodes = codes;
21889             }
21890
21891             return localizer;
21892           };
21893
21894           var _loadPromise;
21895
21896           localizer.ensureLoaded = function () {
21897             if (_loadPromise) return _loadPromise;
21898             return _loadPromise = Promise.all([// load the list of languages
21899             _mainFileFetcher.get('languages'), // load the list of supported locales
21900             _mainFileFetcher.get('locales')]).then(function (results) {
21901               _dataLanguages = results[0];
21902               _dataLocales = results[1];
21903             }).then(function () {
21904               var requestedLocales = (_preferredLocaleCodes || []). // List of locales preferred by the browser in priority order.
21905               concat(utilDetect().browserLocales) // fallback to English since it's the only guaranteed complete language
21906               .concat(['en']);
21907
21908               _localeCodes = localesToUseFrom(requestedLocales); // Run iD in the highest-priority locale; the rest are fallbacks
21909
21910               _localeCode = _localeCodes[0]; // Will always return the index for `en` if nothing else
21911
21912               var fullCoverageIndex = _localeCodes.findIndex(function (locale) {
21913                 return _dataLocales[locale].pct === 1;
21914               }); // We only need to load locales up until we find one with full coverage
21915
21916
21917               var loadStringsPromises = _localeCodes.slice(0, fullCoverageIndex + 1).map(function (code) {
21918                 return localizer.loadLocale(code);
21919               });
21920
21921               return Promise.all(loadStringsPromises);
21922             }).then(function () {
21923               updateForCurrentLocale();
21924             })["catch"](function (err) {
21925               return console.error(err);
21926             }); // eslint-disable-line
21927           }; // Returns the locales from `requestedLocales` supported by iD that we should use
21928
21929
21930           function localesToUseFrom(requestedLocales) {
21931             var supportedLocales = _dataLocales;
21932             var toUse = [];
21933
21934             for (var i in requestedLocales) {
21935               var locale = requestedLocales[i];
21936               if (supportedLocales[locale]) toUse.push(locale);
21937
21938               if (locale.includes('-')) {
21939                 // Full locale ('es-ES'), add fallback to the base ('es')
21940                 var langPart = locale.split('-')[0];
21941                 if (supportedLocales[langPart]) toUse.push(langPart);
21942               }
21943             } // remove duplicates
21944
21945
21946             return utilArrayUniq(toUse);
21947           }
21948
21949           function updateForCurrentLocale() {
21950             if (!_localeCode) return;
21951             _languageCode = _localeCode.split('-')[0];
21952             var currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
21953             var hash = utilStringQs(window.location.hash);
21954
21955             if (hash.rtl === 'true') {
21956               _textDirection = 'rtl';
21957             } else if (hash.rtl === 'false') {
21958               _textDirection = 'ltr';
21959             } else {
21960               _textDirection = currentData && currentData.rtl ? 'rtl' : 'ltr';
21961             }
21962
21963             var locale = _localeCode;
21964             if (locale.toLowerCase() === 'en-us') locale = 'en';
21965             _languageNames = _localeStrings[locale].languageNames;
21966             _scriptNames = _localeStrings[locale].scriptNames;
21967             _usesMetric = _localeCode.slice(-3).toLowerCase() !== '-us';
21968           }
21969           /* Locales */
21970           // Returns a Promise to load the strings for the requested locale
21971
21972
21973           localizer.loadLocale = function (requested) {
21974             if (!_dataLocales) {
21975               return Promise.reject('loadLocale called before init');
21976             }
21977
21978             var locale = requested; // US English is the default
21979
21980             if (locale.toLowerCase() === 'en-us') locale = 'en';
21981
21982             if (!_dataLocales[locale]) {
21983               return Promise.reject("Unsupported locale: ".concat(requested));
21984             }
21985
21986             if (_localeStrings[locale]) {
21987               // already loaded
21988               return Promise.resolve(locale);
21989             }
21990
21991             var fileMap = _mainFileFetcher.fileMap();
21992             var key = "locale_".concat(locale);
21993             fileMap[key] = "locales/".concat(locale, ".json");
21994             return _mainFileFetcher.get(key).then(function (d) {
21995               _localeStrings[locale] = d[locale];
21996               return locale;
21997             });
21998           };
21999
22000           localizer.pluralRule = function (number) {
22001             return pluralRule(number, _localeCode);
22002           }; // Returns the plural rule for the given `number` with the given `localeCode`.
22003           // One of: `zero`, `one`, `two`, `few`, `many`, `other`
22004
22005
22006           function pluralRule(number, localeCode) {
22007             // modern browsers have this functionality built-in
22008             var rules = 'Intl' in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
22009
22010             if (rules) {
22011               return rules.select(number);
22012             } // fallback to basic one/other, as in English
22013
22014
22015             if (number === 1) return 'one';
22016             return 'other';
22017           }
22018           /**
22019           * Try to find that string in `locale` or the current `_localeCode` matching
22020           * the given `stringId`. If no string can be found in the requested locale,
22021           * we'll recurse down all the `_localeCodes` until one is found.
22022           *
22023           * @param  {string}   stringId      string identifier
22024           * @param  {object?}  replacements  token replacements and default string
22025           * @param  {string?}  locale        locale to use (defaults to currentLocale)
22026           * @return {string?}  localized string
22027           */
22028
22029
22030           localizer.tInfo = function (stringId, replacements, locale) {
22031             locale = locale || _localeCode;
22032             var path = stringId.split('.').map(function (s) {
22033               return s.replace(/<TX_DOT>/g, '.');
22034             }).reverse();
22035             var stringsKey = locale; // US English is the default
22036
22037             if (stringsKey.toLowerCase() === 'en-us') stringsKey = 'en';
22038             var result = _localeStrings[stringsKey];
22039
22040             while (result !== undefined && path.length) {
22041               result = result[path.pop()];
22042             }
22043
22044             if (result !== undefined) {
22045               if (replacements) {
22046                 if (_typeof(result) === 'object' && Object.keys(result).length) {
22047                   // If plural forms are provided, dig one level deeper based on the
22048                   // first numeric token replacement provided.
22049                   var number = Object.values(replacements).find(function (value) {
22050                     return typeof value === 'number';
22051                   });
22052
22053                   if (number !== undefined) {
22054                     var rule = pluralRule(number, locale);
22055
22056                     if (result[rule]) {
22057                       result = result[rule];
22058                     } else {
22059                       // We're pretty sure this should be a plural but no string
22060                       // could be found for the given rule. Just pick the first
22061                       // string and hope it makes sense.
22062                       result = Object.values(result)[0];
22063                     }
22064                   }
22065                 }
22066
22067                 if (typeof result === 'string') {
22068                   for (var key in replacements) {
22069                     var value = replacements[key];
22070
22071                     if (typeof value === 'number' && value.toLocaleString) {
22072                       // format numbers for the locale
22073                       value = value.toLocaleString(locale, {
22074                         style: 'decimal',
22075                         useGrouping: true,
22076                         minimumFractionDigits: 0
22077                       });
22078                     }
22079
22080                     var token = "{".concat(key, "}");
22081                     var regex = new RegExp(token, 'g');
22082                     result = result.replace(regex, value);
22083                   }
22084                 }
22085               }
22086
22087               if (typeof result === 'string') {
22088                 // found a localized string!
22089                 return {
22090                   text: result,
22091                   locale: locale
22092                 };
22093               }
22094             } // no localized string found...
22095             // attempt to fallback to a lower-priority language
22096
22097
22098             var index = _localeCodes.indexOf(locale);
22099
22100             if (index >= 0 && index < _localeCodes.length - 1) {
22101               // eventually this will be 'en' or another locale with 100% coverage
22102               var fallback = _localeCodes[index + 1];
22103               return localizer.tInfo(stringId, replacements, fallback);
22104             }
22105
22106             if (replacements && 'default' in replacements) {
22107               // Fallback to a default value if one is specified in `replacements`
22108               return {
22109                 text: replacements["default"],
22110                 locale: null
22111               };
22112             }
22113
22114             var missing = "Missing ".concat(locale, " translation: ").concat(stringId);
22115             if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
22116
22117             return {
22118               text: missing,
22119               locale: 'en'
22120             };
22121           }; // Returns only the localized text, discarding the locale info
22122
22123
22124           localizer.t = function (stringId, replacements, locale) {
22125             return localizer.tInfo(stringId, replacements, locale).text;
22126           }; // Returns the localized text wrapped in an HTML element encoding the locale info
22127
22128
22129           localizer.t.html = function (stringId, replacements, locale) {
22130             var info = localizer.tInfo(stringId, replacements, locale); // text may be empty or undefined if `replacements.default` is
22131
22132             return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
22133           };
22134
22135           localizer.htmlForLocalizedText = function (text, localeCode) {
22136             return "<span class=\"localized-text\" lang=\"".concat(localeCode || 'unknown', "\">").concat(text, "</span>");
22137           };
22138
22139           localizer.languageName = function (code, options) {
22140             if (_languageNames[code]) {
22141               // name in locale language
22142               // e.g. "German"
22143               return _languageNames[code];
22144             } // sometimes we only want the local name
22145
22146
22147             if (options && options.localOnly) return null;
22148             var langInfo = _dataLanguages[code];
22149
22150             if (langInfo) {
22151               if (langInfo.nativeName) {
22152                 // name in native language
22153                 // e.g. "Deutsch (de)"
22154                 return localizer.t('translate.language_and_code', {
22155                   language: langInfo.nativeName,
22156                   code: code
22157                 });
22158               } else if (langInfo.base && langInfo.script) {
22159                 var base = langInfo.base; // the code of the language this is based on
22160
22161                 if (_languageNames[base]) {
22162                   // base language name in locale language
22163                   var scriptCode = langInfo.script;
22164                   var script = _scriptNames[scriptCode] || scriptCode; // e.g. "Serbian (Cyrillic)"
22165
22166                   return localizer.t('translate.language_and_code', {
22167                     language: _languageNames[base],
22168                     code: script
22169                   });
22170                 } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
22171                   // e.g. "српски (sr-Cyrl)"
22172                   return localizer.t('translate.language_and_code', {
22173                     language: _dataLanguages[base].nativeName,
22174                     code: code
22175                   });
22176                 }
22177               }
22178             }
22179
22180             return code; // if not found, use the code
22181           };
22182
22183           return localizer;
22184         }
22185
22186         // `presetCollection` is a wrapper around an `Array` of presets `collection`,
22187         // and decorated with some extra methods for searching and matching geometry
22188         //
22189
22190         function presetCollection(collection) {
22191           var MAXRESULTS = 50;
22192           var _this = {};
22193           var _memo = {};
22194           _this.collection = collection;
22195
22196           _this.item = function (id) {
22197             if (_memo[id]) return _memo[id];
22198
22199             var found = _this.collection.find(function (d) {
22200               return d.id === id;
22201             });
22202
22203             if (found) _memo[id] = found;
22204             return found;
22205           };
22206
22207           _this.index = function (id) {
22208             return _this.collection.findIndex(function (d) {
22209               return d.id === id;
22210             });
22211           };
22212
22213           _this.matchGeometry = function (geometry) {
22214             return presetCollection(_this.collection.filter(function (d) {
22215               return d.matchGeometry(geometry);
22216             }));
22217           };
22218
22219           _this.matchAllGeometry = function (geometries) {
22220             return presetCollection(_this.collection.filter(function (d) {
22221               return d && d.matchAllGeometry(geometries);
22222             }));
22223           };
22224
22225           _this.matchAnyGeometry = function (geometries) {
22226             return presetCollection(_this.collection.filter(function (d) {
22227               return geometries.some(function (geom) {
22228                 return d.matchGeometry(geom);
22229               });
22230             }));
22231           };
22232
22233           _this.fallback = function (geometry) {
22234             var id = geometry;
22235             if (id === 'vertex') id = 'point';
22236             return _this.item(id);
22237           };
22238
22239           _this.search = function (value, geometry, countryCode) {
22240             if (!value) return _this;
22241             value = value.toLowerCase().trim(); // match at name beginning or just after a space (e.g. "office" -> match "Law Office")
22242
22243             function leading(a) {
22244               var index = a.indexOf(value);
22245               return index === 0 || a[index - 1] === ' ';
22246             } // match at name beginning only
22247
22248
22249             function leadingStrict(a) {
22250               var index = a.indexOf(value);
22251               return index === 0;
22252             }
22253
22254             function sortNames(a, b) {
22255               var aCompare = (a.suggestion ? a.originalName : a.name()).toLowerCase();
22256               var bCompare = (b.suggestion ? b.originalName : b.name()).toLowerCase(); // priority if search string matches preset name exactly - #4325
22257
22258               if (value === aCompare) return -1;
22259               if (value === bCompare) return 1; // priority for higher matchScore
22260
22261               var i = b.originalScore - a.originalScore;
22262               if (i !== 0) return i; // priority if search string appears earlier in preset name
22263
22264               i = aCompare.indexOf(value) - bCompare.indexOf(value);
22265               if (i !== 0) return i; // priority for shorter preset names
22266
22267               return aCompare.length - bCompare.length;
22268             }
22269
22270             var pool = _this.collection;
22271
22272             if (countryCode) {
22273               pool = pool.filter(function (a) {
22274                 if (a.countryCodes && a.countryCodes.indexOf(countryCode) === -1) return false;
22275                 if (a.notCountryCodes && a.notCountryCodes.indexOf(countryCode) !== -1) return false;
22276                 return true;
22277               });
22278             }
22279
22280             var searchable = pool.filter(function (a) {
22281               return a.searchable !== false && a.suggestion !== true;
22282             });
22283             var suggestions = pool.filter(function (a) {
22284               return a.suggestion === true;
22285             }); // matches value to preset.name
22286
22287             var leading_name = searchable.filter(function (a) {
22288               return leading(a.name().toLowerCase());
22289             }).sort(sortNames); // matches value to preset suggestion name (original name is unhyphenated)
22290
22291             var leading_suggestions = suggestions.filter(function (a) {
22292               return leadingStrict(a.originalName.toLowerCase());
22293             }).sort(sortNames); // matches value to preset.terms values
22294
22295             var leading_terms = searchable.filter(function (a) {
22296               return (a.terms() || []).some(leading);
22297             }); // matches value to preset.tags values
22298
22299             var leading_tag_values = searchable.filter(function (a) {
22300               return Object.values(a.tags || {}).filter(function (val) {
22301                 return val !== '*';
22302               }).some(leading);
22303             }); // finds close matches to value in preset.name
22304
22305             var similar_name = searchable.map(function (a) {
22306               return {
22307                 preset: a,
22308                 dist: utilEditDistance(value, a.name())
22309               };
22310             }).filter(function (a) {
22311               return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
22312             }).sort(function (a, b) {
22313               return a.dist - b.dist;
22314             }).map(function (a) {
22315               return a.preset;
22316             }); // finds close matches to value to preset suggestion name (original name is unhyphenated)
22317
22318             var similar_suggestions = suggestions.map(function (a) {
22319               return {
22320                 preset: a,
22321                 dist: utilEditDistance(value, a.originalName.toLowerCase())
22322               };
22323             }).filter(function (a) {
22324               return a.dist + Math.min(value.length - a.preset.originalName.length, 0) < 1;
22325             }).sort(function (a, b) {
22326               return a.dist - b.dist;
22327             }).map(function (a) {
22328               return a.preset;
22329             }); // finds close matches to value in preset.terms
22330
22331             var similar_terms = searchable.filter(function (a) {
22332               return (a.terms() || []).some(function (b) {
22333                 return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
22334               });
22335             });
22336             var results = leading_name.concat(leading_suggestions, leading_terms, leading_tag_values, similar_name, similar_suggestions, similar_terms).slice(0, MAXRESULTS - 1);
22337
22338             if (geometry) {
22339               if (typeof geometry === 'string') {
22340                 results.push(_this.fallback(geometry));
22341               } else {
22342                 geometry.forEach(function (geom) {
22343                   return results.push(_this.fallback(geom));
22344                 });
22345               }
22346             }
22347
22348             return presetCollection(utilArrayUniq(results));
22349           };
22350
22351           return _this;
22352         }
22353
22354         // `presetCategory` builds a `presetCollection` of member presets,
22355         // decorated with some extra methods for searching and matching geometry
22356         //
22357
22358         function presetCategory(categoryID, category, all) {
22359           var _this = Object.assign({}, category); // shallow copy
22360
22361
22362           _this.id = categoryID;
22363           _this.members = presetCollection(category.members.map(function (presetID) {
22364             return all.item(presetID);
22365           }).filter(Boolean));
22366           _this.geometry = _this.members.collection.reduce(function (acc, preset) {
22367             for (var i in preset.geometry) {
22368               var geometry = preset.geometry[i];
22369
22370               if (acc.indexOf(geometry) === -1) {
22371                 acc.push(geometry);
22372               }
22373             }
22374
22375             return acc;
22376           }, []);
22377
22378           _this.matchGeometry = function (geom) {
22379             return _this.geometry.indexOf(geom) >= 0;
22380           };
22381
22382           _this.matchAllGeometry = function (geometries) {
22383             return _this.members.collection.some(function (preset) {
22384               return preset.matchAllGeometry(geometries);
22385             });
22386           };
22387
22388           _this.matchScore = function () {
22389             return -1;
22390           };
22391
22392           _this.name = function () {
22393             return _t("presets.categories.".concat(categoryID, ".name"), {
22394               'default': categoryID
22395             });
22396           };
22397
22398           _this.nameLabel = function () {
22399             return _t.html("presets.categories.".concat(categoryID, ".name"), {
22400               'default': categoryID
22401             });
22402           };
22403
22404           _this.terms = function () {
22405             return [];
22406           };
22407
22408           return _this;
22409         }
22410
22411         // `presetField` decorates a given `field` Object
22412         // with some extra methods for searching and matching geometry
22413         //
22414
22415         function presetField(fieldID, field) {
22416           var _this = Object.assign({}, field); // shallow copy
22417
22418
22419           _this.id = fieldID; // for use in classes, element ids, css selectors
22420
22421           _this.safeid = utilSafeClassName(fieldID);
22422
22423           _this.matchGeometry = function (geom) {
22424             return !_this.geometry || _this.geometry.indexOf(geom) !== -1;
22425           };
22426
22427           _this.matchAllGeometry = function (geometries) {
22428             return !_this.geometry || geometries.every(function (geom) {
22429               return _this.geometry.indexOf(geom) !== -1;
22430             });
22431           };
22432
22433           _this.t = function (scope, options) {
22434             return _t("presets.fields.".concat(fieldID, ".").concat(scope), options);
22435           };
22436
22437           _this.t.html = function (scope, options) {
22438             return _t.html("presets.fields.".concat(fieldID, ".").concat(scope), options);
22439           };
22440
22441           _this.title = function () {
22442             return _this.overrideLabel || _this.t('label', {
22443               'default': fieldID
22444             });
22445           };
22446
22447           _this.label = function () {
22448             return _this.overrideLabel || _this.t.html('label', {
22449               'default': fieldID
22450             });
22451           };
22452
22453           var _placeholder = _this.placeholder;
22454
22455           _this.placeholder = function () {
22456             return _this.t('placeholder', {
22457               'default': _placeholder
22458             });
22459           };
22460
22461           _this.originalTerms = (_this.terms || []).join();
22462
22463           _this.terms = function () {
22464             return _this.t('terms', {
22465               'default': _this.originalTerms
22466             }).toLowerCase().trim().split(/\s*,+\s*/);
22467           };
22468
22469           _this.increment = _this.type === 'number' ? _this.increment || 1 : undefined;
22470           return _this;
22471         }
22472
22473         // `Array.prototype.lastIndexOf` method
22474         // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
22475         _export({ target: 'Array', proto: true, forced: arrayLastIndexOf !== [].lastIndexOf }, {
22476           lastIndexOf: arrayLastIndexOf
22477         });
22478
22479         // `presetPreset` decorates a given `preset` Object
22480         // with some extra methods for searching and matching geometry
22481         //
22482
22483         function presetPreset(presetID, preset, addable, allFields, allPresets) {
22484           allFields = allFields || {};
22485           allPresets = allPresets || {};
22486
22487           var _this = Object.assign({}, preset); // shallow copy
22488
22489
22490           var _addable = addable || false;
22491
22492           var _resolvedFields; // cache
22493
22494
22495           var _resolvedMoreFields; // cache
22496
22497
22498           _this.id = presetID;
22499           _this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
22500
22501           _this.originalTerms = (_this.terms || []).join();
22502           _this.originalName = _this.name || '';
22503           _this.originalScore = _this.matchScore || 1;
22504           _this.originalReference = _this.reference || {};
22505           _this.originalFields = _this.fields || [];
22506           _this.originalMoreFields = _this.moreFields || [];
22507
22508           _this.fields = function () {
22509             return _resolvedFields || (_resolvedFields = resolve('fields'));
22510           };
22511
22512           _this.moreFields = function () {
22513             return _resolvedMoreFields || (_resolvedMoreFields = resolve('moreFields'));
22514           };
22515
22516           _this.resetFields = function () {
22517             return _resolvedFields = _resolvedMoreFields = null;
22518           };
22519
22520           _this.tags = _this.tags || {};
22521           _this.addTags = _this.addTags || _this.tags;
22522           _this.removeTags = _this.removeTags || _this.addTags;
22523           _this.geometry = _this.geometry || [];
22524
22525           _this.matchGeometry = function (geom) {
22526             return _this.geometry.indexOf(geom) >= 0;
22527           };
22528
22529           _this.matchAllGeometry = function (geoms) {
22530             return geoms.every(_this.matchGeometry);
22531           };
22532
22533           _this.matchScore = function (entityTags) {
22534             var tags = _this.tags;
22535             var seen = {};
22536             var score = 0; // match on tags
22537
22538             for (var k in tags) {
22539               seen[k] = true;
22540
22541               if (entityTags[k] === tags[k]) {
22542                 score += _this.originalScore;
22543               } else if (tags[k] === '*' && k in entityTags) {
22544                 score += _this.originalScore / 2;
22545               } else {
22546                 return -1;
22547               }
22548             } // boost score for additional matches in addTags - #6802
22549
22550
22551             var addTags = _this.addTags;
22552
22553             for (var _k in addTags) {
22554               if (!seen[_k] && entityTags[_k] === addTags[_k]) {
22555                 score += _this.originalScore;
22556               }
22557             }
22558
22559             return score;
22560           };
22561
22562           _this.t = function (scope, options) {
22563             var textID = "presets.presets.".concat(presetID, ".").concat(scope);
22564             return _t(textID, options);
22565           };
22566
22567           _this.t.html = function (scope, options) {
22568             var textID = "presets.presets.".concat(presetID, ".").concat(scope);
22569             return _t.html(textID, options);
22570           };
22571
22572           _this.name = function () {
22573             return _this.t('name', {
22574               'default': _this.originalName
22575             });
22576           };
22577
22578           _this.nameLabel = function () {
22579             return _this.t.html('name', {
22580               'default': _this.originalName
22581             });
22582           };
22583
22584           _this.subtitle = function () {
22585             if (_this.suggestion) {
22586               var path = presetID.split('/');
22587               path.pop(); // remove brand name
22588
22589               return _t('presets.presets.' + path.join('/') + '.name');
22590             }
22591
22592             return null;
22593           };
22594
22595           _this.subtitleLabel = function () {
22596             if (_this.suggestion) {
22597               var path = presetID.split('/');
22598               path.pop(); // remove brand name
22599
22600               return _t.html('presets.presets.' + path.join('/') + '.name');
22601             }
22602
22603             return null;
22604           };
22605
22606           _this.terms = function () {
22607             return _this.t('terms', {
22608               'default': _this.originalTerms
22609             }).toLowerCase().trim().split(/\s*,+\s*/);
22610           };
22611
22612           _this.isFallback = function () {
22613             var tagCount = Object.keys(_this.tags).length;
22614             return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty('area');
22615           };
22616
22617           _this.addable = function (val) {
22618             if (!arguments.length) return _addable;
22619             _addable = val;
22620             return _this;
22621           };
22622
22623           _this.reference = function () {
22624             // Lookup documentation on Wikidata...
22625             var qid = _this.tags.wikidata || _this.tags['brand:wikidata'] || _this.tags['operator:wikidata'];
22626
22627             if (qid) {
22628               return {
22629                 qid: qid
22630               };
22631             } // Lookup documentation on OSM Wikibase...
22632
22633
22634             var key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
22635             var value = _this.originalReference.value || _this.tags[key];
22636
22637             if (value === '*') {
22638               return {
22639                 key: key
22640               };
22641             } else {
22642               return {
22643                 key: key,
22644                 value: value
22645               };
22646             }
22647           };
22648
22649           _this.unsetTags = function (tags, geometry, skipFieldDefaults) {
22650             tags = utilObjectOmit(tags, Object.keys(_this.removeTags));
22651
22652             if (geometry && !skipFieldDefaults) {
22653               _this.fields().forEach(function (field) {
22654                 if (field.matchGeometry(geometry) && field.key && field["default"] === tags[field.key]) {
22655                   delete tags[field.key];
22656                 }
22657               });
22658             }
22659
22660             delete tags.area;
22661             return tags;
22662           };
22663
22664           _this.setTags = function (tags, geometry, skipFieldDefaults) {
22665             var addTags = _this.addTags;
22666             tags = Object.assign({}, tags); // shallow copy
22667
22668             for (var k in addTags) {
22669               if (addTags[k] === '*') {
22670                 tags[k] = 'yes';
22671               } else {
22672                 tags[k] = addTags[k];
22673               }
22674             } // Add area=yes if necessary.
22675             // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
22676             // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
22677             // 2. chosen preset doesn't have a key in osmAreaKeys (`railway=station`)
22678
22679
22680             if (!addTags.hasOwnProperty('area')) {
22681               delete tags.area;
22682
22683               if (geometry === 'area') {
22684                 var needsAreaTag = true;
22685
22686                 if (_this.geometry.indexOf('line') === -1) {
22687                   for (var _k2 in addTags) {
22688                     if (_k2 in osmAreaKeys) {
22689                       needsAreaTag = false;
22690                       break;
22691                     }
22692                   }
22693                 }
22694
22695                 if (needsAreaTag) {
22696                   tags.area = 'yes';
22697                 }
22698               }
22699             }
22700
22701             if (geometry && !skipFieldDefaults) {
22702               _this.fields().forEach(function (field) {
22703                 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field["default"]) {
22704                   tags[field.key] = field["default"];
22705                 }
22706               });
22707             }
22708
22709             return tags;
22710           }; // For a preset without fields, use the fields of the parent preset.
22711           // Replace {preset} placeholders with the fields of the specified presets.
22712
22713
22714           function resolve(which) {
22715             var fieldIDs = which === 'fields' ? _this.originalFields : _this.originalMoreFields;
22716             var resolved = [];
22717             fieldIDs.forEach(function (fieldID) {
22718               var match = fieldID.match(/\{(.*)\}/);
22719
22720               if (match !== null) {
22721                 // a presetID wrapped in braces {}
22722                 resolved = resolved.concat(inheritFields(match[1], which));
22723               } else if (allFields[fieldID]) {
22724                 // a normal fieldID
22725                 resolved.push(allFields[fieldID]);
22726               } else {
22727                 console.log("Cannot resolve \"".concat(fieldID, "\" found in ").concat(_this.id, ".").concat(which)); // eslint-disable-line no-console
22728               }
22729             }); // no fields resolved, so use the parent's if possible
22730
22731             if (!resolved.length) {
22732               var endIndex = _this.id.lastIndexOf('/');
22733
22734               var parentID = endIndex && _this.id.substring(0, endIndex);
22735
22736               if (parentID) {
22737                 resolved = inheritFields(parentID, which);
22738               }
22739             }
22740
22741             return utilArrayUniq(resolved); // returns an array of fields to inherit from the given presetID, if found
22742
22743             function inheritFields(presetID, which) {
22744               var parent = allPresets[presetID];
22745               if (!parent) return [];
22746
22747               if (which === 'fields') {
22748                 return parent.fields().filter(shouldInherit);
22749               } else if (which === 'moreFields') {
22750                 return parent.moreFields();
22751               } else {
22752                 return [];
22753               }
22754             } // Skip `fields` for the keys which define the preset.
22755             // These are usually `typeCombo` fields like `shop=*`
22756
22757
22758             function shouldInherit(f) {
22759               if (f.key && _this.tags[f.key] !== undefined && // inherit anyway if multiple values are allowed or just a checkbox
22760               f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'manyCombo' && f.type !== 'check') return false;
22761               return true;
22762             }
22763           }
22764
22765           return _this;
22766         }
22767
22768         var _mainPresetIndex = presetIndex(); // singleton
22769         // `presetIndex` wraps a `presetCollection`
22770         // with methods for loading new data and returning defaults
22771         //
22772
22773         function presetIndex() {
22774           var dispatch$1 = dispatch('favoritePreset', 'recentsChange');
22775           var MAXRECENTS = 30; // seed the preset lists with geometry fallbacks
22776
22777           var POINT = presetPreset('point', {
22778             name: 'Point',
22779             tags: {},
22780             geometry: ['point', 'vertex'],
22781             matchScore: 0.1
22782           });
22783           var LINE = presetPreset('line', {
22784             name: 'Line',
22785             tags: {},
22786             geometry: ['line'],
22787             matchScore: 0.1
22788           });
22789           var AREA = presetPreset('area', {
22790             name: 'Area',
22791             tags: {
22792               area: 'yes'
22793             },
22794             geometry: ['area'],
22795             matchScore: 0.1
22796           });
22797           var RELATION = presetPreset('relation', {
22798             name: 'Relation',
22799             tags: {},
22800             geometry: ['relation'],
22801             matchScore: 0.1
22802           });
22803
22804           var _this = presetCollection([POINT, LINE, AREA, RELATION]);
22805
22806           var _presets = {
22807             point: POINT,
22808             line: LINE,
22809             area: AREA,
22810             relation: RELATION
22811           };
22812           var _defaults = {
22813             point: presetCollection([POINT]),
22814             vertex: presetCollection([POINT]),
22815             line: presetCollection([LINE]),
22816             area: presetCollection([AREA]),
22817             relation: presetCollection([RELATION])
22818           };
22819           var _fields = {};
22820           var _categories = {};
22821           var _universal = [];
22822           var _addablePresetIDs = null; // Set of preset IDs that the user can add
22823
22824           var _recents;
22825
22826           var _favorites; // Index of presets by (geometry, tag key).
22827
22828
22829           var _geometryIndex = {
22830             point: {},
22831             vertex: {},
22832             line: {},
22833             area: {},
22834             relation: {}
22835           };
22836
22837           var _loadPromise;
22838
22839           _this.ensureLoaded = function () {
22840             if (_loadPromise) return _loadPromise;
22841             return _loadPromise = Promise.all([_mainFileFetcher.get('preset_categories'), _mainFileFetcher.get('preset_defaults'), _mainFileFetcher.get('preset_presets'), _mainFileFetcher.get('preset_fields')]).then(function (vals) {
22842               _this.merge({
22843                 categories: vals[0],
22844                 defaults: vals[1],
22845                 presets: vals[2],
22846                 fields: vals[3]
22847               });
22848
22849               osmSetAreaKeys(_this.areaKeys());
22850               osmSetPointTags(_this.pointTags());
22851               osmSetVertexTags(_this.vertexTags());
22852             });
22853           };
22854
22855           _this.merge = function (d) {
22856             // Merge Fields
22857             if (d.fields) {
22858               Object.keys(d.fields).forEach(function (fieldID) {
22859                 var f = d.fields[fieldID];
22860
22861                 if (f) {
22862                   // add or replace
22863                   _fields[fieldID] = presetField(fieldID, f);
22864                 } else {
22865                   // remove
22866                   delete _fields[fieldID];
22867                 }
22868               });
22869             } // Merge Presets
22870
22871
22872             if (d.presets) {
22873               Object.keys(d.presets).forEach(function (presetID) {
22874                 var p = d.presets[presetID];
22875
22876                 if (p) {
22877                   // add or replace
22878                   var isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
22879
22880                   _presets[presetID] = presetPreset(presetID, p, isAddable, _fields, _presets);
22881                 } else {
22882                   // remove (but not if it's a fallback)
22883                   var existing = _presets[presetID];
22884
22885                   if (existing && !existing.isFallback()) {
22886                     delete _presets[presetID];
22887                   }
22888                 }
22889               });
22890             } // Need to rebuild _this.collection before loading categories
22891
22892
22893             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Categories
22894
22895             if (d.categories) {
22896               Object.keys(d.categories).forEach(function (categoryID) {
22897                 var c = d.categories[categoryID];
22898
22899                 if (c) {
22900                   // add or replace
22901                   _categories[categoryID] = presetCategory(categoryID, c, _this);
22902                 } else {
22903                   // remove
22904                   delete _categories[categoryID];
22905                 }
22906               });
22907             } // Rebuild _this.collection after loading categories
22908
22909
22910             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Defaults
22911
22912             if (d.defaults) {
22913               Object.keys(d.defaults).forEach(function (geometry) {
22914                 var def = d.defaults[geometry];
22915
22916                 if (Array.isArray(def)) {
22917                   // add or replace
22918                   _defaults[geometry] = presetCollection(def.map(function (id) {
22919                     return _presets[id] || _categories[id];
22920                   }).filter(Boolean));
22921                 } else {
22922                   // remove
22923                   delete _defaults[geometry];
22924                 }
22925               });
22926             } // Rebuild universal fields array
22927
22928
22929             _universal = Object.values(_fields).filter(function (field) {
22930               return field.universal;
22931             }); // Reset all the preset fields - they'll need to be resolved again
22932
22933             Object.values(_presets).forEach(function (preset) {
22934               return preset.resetFields();
22935             }); // Rebuild geometry index
22936
22937             _geometryIndex = {
22938               point: {},
22939               vertex: {},
22940               line: {},
22941               area: {},
22942               relation: {}
22943             };
22944
22945             _this.collection.forEach(function (preset) {
22946               (preset.geometry || []).forEach(function (geometry) {
22947                 var g = _geometryIndex[geometry];
22948
22949                 for (var key in preset.tags) {
22950                   (g[key] = g[key] || []).push(preset);
22951                 }
22952               });
22953             });
22954
22955             return _this;
22956           };
22957
22958           _this.match = function (entity, resolver) {
22959             return resolver["transient"](entity, 'presetMatch', function () {
22960               var geometry = entity.geometry(resolver); // Treat entities on addr:interpolation lines as points, not vertices - #3241
22961
22962               if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
22963                 geometry = 'point';
22964               }
22965
22966               return _this.matchTags(entity.tags, geometry);
22967             });
22968           };
22969
22970           _this.matchTags = function (tags, geometry) {
22971             var geometryMatches = _geometryIndex[geometry];
22972             var address;
22973             var best = -1;
22974             var match;
22975
22976             for (var k in tags) {
22977               // If any part of an address is present, allow fallback to "Address" preset - #4353
22978               if (/^addr:/.test(k) && geometryMatches['addr:*']) {
22979                 address = geometryMatches['addr:*'][0];
22980               }
22981
22982               var keyMatches = geometryMatches[k];
22983               if (!keyMatches) continue;
22984
22985               for (var i = 0; i < keyMatches.length; i++) {
22986                 var score = keyMatches[i].matchScore(tags);
22987
22988                 if (score > best) {
22989                   best = score;
22990                   match = keyMatches[i];
22991                 }
22992               }
22993             }
22994
22995             if (address && (!match || match.isFallback())) {
22996               match = address;
22997             }
22998
22999             return match || _this.fallback(geometry);
23000           };
23001
23002           _this.allowsVertex = function (entity, resolver) {
23003             if (entity.type !== 'node') return false;
23004             if (Object.keys(entity.tags).length === 0) return true;
23005             return resolver["transient"](entity, 'vertexMatch', function () {
23006               // address lines allow vertices to act as standalone points
23007               if (entity.isOnAddressLine(resolver)) return true;
23008               var geometries = osmNodeGeometriesForTags(entity.tags);
23009               if (geometries.vertex) return true;
23010               if (geometries.point) return false; // allow vertices for unspecified points
23011
23012               return true;
23013             });
23014           }; // Because of the open nature of tagging, iD will never have a complete
23015           // list of tags used in OSM, so we want it to have logic like "assume
23016           // that a closed way with an amenity tag is an area, unless the amenity
23017           // is one of these specific types". This function computes a structure
23018           // that allows testing of such conditions, based on the presets designated
23019           // as as supporting (or not supporting) the area geometry.
23020           //
23021           // The returned object L is a keeplist/discardlist of tags. A closed way
23022           // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
23023           // (see `Way#isArea()`). In other words, the keys of L form the keeplist,
23024           // and the subkeys form the discardlist.
23025
23026
23027           _this.areaKeys = function () {
23028             // The ignore list is for keys that imply lines. (We always add `area=yes` for exceptions)
23029             var ignore = ['barrier', 'highway', 'footway', 'railway', 'junction', 'type'];
23030             var areaKeys = {}; // ignore name-suggestion-index and deprecated presets
23031
23032             var presets = _this.collection.filter(function (p) {
23033               return !p.suggestion && !p.replacement;
23034             }); // keeplist
23035
23036
23037             presets.forEach(function (p) {
23038               var keys = p.tags && Object.keys(p.tags);
23039               var key = keys && keys.length && keys[0]; // pick the first tag
23040
23041               if (!key) return;
23042               if (ignore.indexOf(key) !== -1) return;
23043
23044               if (p.geometry.indexOf('area') !== -1) {
23045                 // probably an area..
23046                 areaKeys[key] = areaKeys[key] || {};
23047               }
23048             }); // discardlist
23049
23050             presets.forEach(function (p) {
23051               var key;
23052
23053               for (key in p.addTags) {
23054                 // examine all addTags to get a better sense of what can be tagged on lines - #6800
23055                 var value = p.addTags[key];
23056
23057                 if (key in areaKeys && // probably an area...
23058                 p.geometry.indexOf('line') !== -1 && // but sometimes a line
23059                 value !== '*') {
23060                   areaKeys[key][value] = true;
23061                 }
23062               }
23063             });
23064             return areaKeys;
23065           };
23066
23067           _this.pointTags = function () {
23068             return _this.collection.reduce(function (pointTags, d) {
23069               // ignore name-suggestion-index, deprecated, and generic presets
23070               if (d.suggestion || d.replacement || d.searchable === false) return pointTags; // only care about the primary tag
23071
23072               var keys = d.tags && Object.keys(d.tags);
23073               var key = keys && keys.length && keys[0]; // pick the first tag
23074
23075               if (!key) return pointTags; // if this can be a point
23076
23077               if (d.geometry.indexOf('point') !== -1) {
23078                 pointTags[key] = pointTags[key] || {};
23079                 pointTags[key][d.tags[key]] = true;
23080               }
23081
23082               return pointTags;
23083             }, {});
23084           };
23085
23086           _this.vertexTags = function () {
23087             return _this.collection.reduce(function (vertexTags, d) {
23088               // ignore name-suggestion-index, deprecated, and generic presets
23089               if (d.suggestion || d.replacement || d.searchable === false) return vertexTags; // only care about the primary tag
23090
23091               var keys = d.tags && Object.keys(d.tags);
23092               var key = keys && keys.length && keys[0]; // pick the first tag
23093
23094               if (!key) return vertexTags; // if this can be a vertex
23095
23096               if (d.geometry.indexOf('vertex') !== -1) {
23097                 vertexTags[key] = vertexTags[key] || {};
23098                 vertexTags[key][d.tags[key]] = true;
23099               }
23100
23101               return vertexTags;
23102             }, {});
23103           };
23104
23105           _this.field = function (id) {
23106             return _fields[id];
23107           };
23108
23109           _this.universal = function () {
23110             return _universal;
23111           };
23112
23113           _this.defaults = function (geometry, n, startWithRecents) {
23114             var recents = [];
23115
23116             if (startWithRecents) {
23117               recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
23118             }
23119
23120             var defaults;
23121
23122             if (_addablePresetIDs) {
23123               defaults = Array.from(_addablePresetIDs).map(function (id) {
23124                 var preset = _this.item(id);
23125
23126                 if (preset && preset.matchGeometry(geometry)) return preset;
23127                 return null;
23128               }).filter(Boolean);
23129             } else {
23130               defaults = _defaults[geometry].collection.concat(_this.fallback(geometry));
23131             }
23132
23133             return presetCollection(utilArrayUniq(recents.concat(defaults)).slice(0, n - 1));
23134           }; // pass a Set of addable preset ids
23135
23136
23137           _this.addablePresetIDs = function (val) {
23138             if (!arguments.length) return _addablePresetIDs; // accept and convert arrays
23139
23140             if (Array.isArray(val)) val = new Set(val);
23141             _addablePresetIDs = val;
23142
23143             if (_addablePresetIDs) {
23144               // reset all presets
23145               _this.collection.forEach(function (p) {
23146                 // categories aren't addable
23147                 if (p.addable) p.addable(_addablePresetIDs.has(p.id));
23148               });
23149             } else {
23150               _this.collection.forEach(function (p) {
23151                 if (p.addable) p.addable(true);
23152               });
23153             }
23154
23155             return _this;
23156           };
23157
23158           _this.recent = function () {
23159             return presetCollection(utilArrayUniq(_this.getRecents().map(function (d) {
23160               return d.preset;
23161             })));
23162           };
23163
23164           function RibbonItem(preset, source) {
23165             var item = {};
23166             item.preset = preset;
23167             item.source = source;
23168
23169             item.isFavorite = function () {
23170               return item.source === 'favorite';
23171             };
23172
23173             item.isRecent = function () {
23174               return item.source === 'recent';
23175             };
23176
23177             item.matches = function (preset) {
23178               return item.preset.id === preset.id;
23179             };
23180
23181             item.minified = function () {
23182               return {
23183                 pID: item.preset.id
23184               };
23185             };
23186
23187             return item;
23188           }
23189
23190           function ribbonItemForMinified(d, source) {
23191             if (d && d.pID) {
23192               var preset = _this.item(d.pID);
23193
23194               if (!preset) return null;
23195               return RibbonItem(preset, source);
23196             }
23197
23198             return null;
23199           }
23200
23201           _this.getGenericRibbonItems = function () {
23202             return ['point', 'line', 'area'].map(function (id) {
23203               return RibbonItem(_this.item(id), 'generic');
23204             });
23205           };
23206
23207           _this.getAddable = function () {
23208             if (!_addablePresetIDs) return [];
23209             return _addablePresetIDs.map(function (id) {
23210               var preset = _this.item(id);
23211
23212               if (preset) return RibbonItem(preset, 'addable');
23213               return null;
23214             }).filter(Boolean);
23215           };
23216
23217           function setRecents(items) {
23218             _recents = items;
23219             var minifiedItems = items.map(function (d) {
23220               return d.minified();
23221             });
23222             corePreferences('preset_recents', JSON.stringify(minifiedItems));
23223             dispatch$1.call('recentsChange');
23224           }
23225
23226           _this.getRecents = function () {
23227             if (!_recents) {
23228               // fetch from local storage
23229               _recents = (JSON.parse(corePreferences('preset_recents')) || []).reduce(function (acc, d) {
23230                 var item = ribbonItemForMinified(d, 'recent');
23231                 if (item && item.preset.addable()) acc.push(item);
23232                 return acc;
23233               }, []);
23234             }
23235
23236             return _recents;
23237           };
23238
23239           _this.addRecent = function (preset, besidePreset, after) {
23240             var recents = _this.getRecents();
23241
23242             var beforeItem = _this.recentMatching(besidePreset);
23243
23244             var toIndex = recents.indexOf(beforeItem);
23245             if (after) toIndex += 1;
23246             var newItem = RibbonItem(preset, 'recent');
23247             recents.splice(toIndex, 0, newItem);
23248             setRecents(recents);
23249           };
23250
23251           _this.removeRecent = function (preset) {
23252             var item = _this.recentMatching(preset);
23253
23254             if (item) {
23255               var items = _this.getRecents();
23256
23257               items.splice(items.indexOf(item), 1);
23258               setRecents(items);
23259             }
23260           };
23261
23262           _this.recentMatching = function (preset) {
23263             var items = _this.getRecents();
23264
23265             for (var i in items) {
23266               if (items[i].matches(preset)) {
23267                 return items[i];
23268               }
23269             }
23270
23271             return null;
23272           };
23273
23274           _this.moveItem = function (items, fromIndex, toIndex) {
23275             if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
23276             items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
23277             return items;
23278           };
23279
23280           _this.moveRecent = function (item, beforeItem) {
23281             var recents = _this.getRecents();
23282
23283             var fromIndex = recents.indexOf(item);
23284             var toIndex = recents.indexOf(beforeItem);
23285
23286             var items = _this.moveItem(recents, fromIndex, toIndex);
23287
23288             if (items) setRecents(items);
23289           };
23290
23291           _this.setMostRecent = function (preset) {
23292             if (preset.searchable === false) return;
23293
23294             var items = _this.getRecents();
23295
23296             var item = _this.recentMatching(preset);
23297
23298             if (item) {
23299               items.splice(items.indexOf(item), 1);
23300             } else {
23301               item = RibbonItem(preset, 'recent');
23302             } // remove the last recent (first in, first out)
23303
23304
23305             while (items.length >= MAXRECENTS) {
23306               items.pop();
23307             } // prepend array
23308
23309
23310             items.unshift(item);
23311             setRecents(items);
23312           };
23313
23314           function setFavorites(items) {
23315             _favorites = items;
23316             var minifiedItems = items.map(function (d) {
23317               return d.minified();
23318             });
23319             corePreferences('preset_favorites', JSON.stringify(minifiedItems)); // call update
23320
23321             dispatch$1.call('favoritePreset');
23322           }
23323
23324           _this.addFavorite = function (preset, besidePreset, after) {
23325             var favorites = _this.getFavorites();
23326
23327             var beforeItem = _this.favoriteMatching(besidePreset);
23328
23329             var toIndex = favorites.indexOf(beforeItem);
23330             if (after) toIndex += 1;
23331             var newItem = RibbonItem(preset, 'favorite');
23332             favorites.splice(toIndex, 0, newItem);
23333             setFavorites(favorites);
23334           };
23335
23336           _this.toggleFavorite = function (preset) {
23337             var favs = _this.getFavorites();
23338
23339             var favorite = _this.favoriteMatching(preset);
23340
23341             if (favorite) {
23342               favs.splice(favs.indexOf(favorite), 1);
23343             } else {
23344               // only allow 10 favorites
23345               if (favs.length === 10) {
23346                 // remove the last favorite (last in, first out)
23347                 favs.pop();
23348               } // append array
23349
23350
23351               favs.push(RibbonItem(preset, 'favorite'));
23352             }
23353
23354             setFavorites(favs);
23355           };
23356
23357           _this.removeFavorite = function (preset) {
23358             var item = _this.favoriteMatching(preset);
23359
23360             if (item) {
23361               var items = _this.getFavorites();
23362
23363               items.splice(items.indexOf(item), 1);
23364               setFavorites(items);
23365             }
23366           };
23367
23368           _this.getFavorites = function () {
23369             if (!_favorites) {
23370               // fetch from local storage
23371               var rawFavorites = JSON.parse(corePreferences('preset_favorites'));
23372
23373               if (!rawFavorites) {
23374                 rawFavorites = [];
23375                 corePreferences('preset_favorites', JSON.stringify(rawFavorites));
23376               }
23377
23378               _favorites = rawFavorites.reduce(function (output, d) {
23379                 var item = ribbonItemForMinified(d, 'favorite');
23380                 if (item && item.preset.addable()) output.push(item);
23381                 return output;
23382               }, []);
23383             }
23384
23385             return _favorites;
23386           };
23387
23388           _this.favoriteMatching = function (preset) {
23389             var favs = _this.getFavorites();
23390
23391             for (var index in favs) {
23392               if (favs[index].matches(preset)) {
23393                 return favs[index];
23394               }
23395             }
23396
23397             return null;
23398           };
23399
23400           return utilRebind(_this, dispatch$1, 'on');
23401         }
23402
23403         function utilTagText(entity) {
23404           var obj = entity && entity.tags || {};
23405           return Object.keys(obj).map(function (k) {
23406             return k + '=' + obj[k];
23407           }).join(', ');
23408         }
23409         function utilTotalExtent(array, graph) {
23410           var extent = geoExtent();
23411           var val, entity;
23412
23413           for (var i = 0; i < array.length; i++) {
23414             val = array[i];
23415             entity = typeof val === 'string' ? graph.hasEntity(val) : val;
23416
23417             if (entity) {
23418               extent._extend(entity.extent(graph));
23419             }
23420           }
23421
23422           return extent;
23423         }
23424         function utilTagDiff(oldTags, newTags) {
23425           var tagDiff = [];
23426           var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
23427           keys.forEach(function (k) {
23428             var oldVal = oldTags[k];
23429             var newVal = newTags[k];
23430
23431             if ((oldVal || oldVal === '') && (newVal === undefined || newVal !== oldVal)) {
23432               tagDiff.push({
23433                 type: '-',
23434                 key: k,
23435                 oldVal: oldVal,
23436                 newVal: newVal,
23437                 display: '- ' + k + '=' + oldVal
23438               });
23439             }
23440
23441             if ((newVal || newVal === '') && (oldVal === undefined || newVal !== oldVal)) {
23442               tagDiff.push({
23443                 type: '+',
23444                 key: k,
23445                 oldVal: oldVal,
23446                 newVal: newVal,
23447                 display: '+ ' + k + '=' + newVal
23448               });
23449             }
23450           });
23451           return tagDiff;
23452         }
23453         function utilEntitySelector(ids) {
23454           return ids.length ? '.' + ids.join(',.') : 'nothing';
23455         } // returns an selector to select entity ids for:
23456         //  - entityIDs passed in
23457         //  - shallow descendant entityIDs for any of those entities that are relations
23458
23459         function utilEntityOrMemberSelector(ids, graph) {
23460           var seen = new Set(ids);
23461           ids.forEach(collectShallowDescendants);
23462           return utilEntitySelector(Array.from(seen));
23463
23464           function collectShallowDescendants(id) {
23465             var entity = graph.hasEntity(id);
23466             if (!entity || entity.type !== 'relation') return;
23467             entity.members.map(function (member) {
23468               return member.id;
23469             }).forEach(function (id) {
23470               seen.add(id);
23471             });
23472           }
23473         } // returns an selector to select entity ids for:
23474         //  - entityIDs passed in
23475         //  - deep descendant entityIDs for any of those entities that are relations
23476
23477         function utilEntityOrDeepMemberSelector(ids, graph) {
23478           return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
23479         } // returns an selector to select entity ids for:
23480         //  - entityIDs passed in
23481         //  - deep descendant entityIDs for any of those entities that are relations
23482
23483         function utilEntityAndDeepMemberIDs(ids, graph) {
23484           var seen = new Set();
23485           ids.forEach(collectDeepDescendants);
23486           return Array.from(seen);
23487
23488           function collectDeepDescendants(id) {
23489             if (seen.has(id)) return;
23490             seen.add(id);
23491             var entity = graph.hasEntity(id);
23492             if (!entity || entity.type !== 'relation') return;
23493             entity.members.map(function (member) {
23494               return member.id;
23495             }).forEach(collectDeepDescendants); // recurse
23496           }
23497         } // returns an selector to select entity ids for:
23498         //  - deep descendant entityIDs for any of those entities that are relations
23499
23500         function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
23501           var idsSet = new Set(ids);
23502           var seen = new Set();
23503           var returners = new Set();
23504           ids.forEach(collectDeepDescendants);
23505           return utilEntitySelector(Array.from(returners));
23506
23507           function collectDeepDescendants(id) {
23508             if (seen.has(id)) return;
23509             seen.add(id);
23510
23511             if (!idsSet.has(id)) {
23512               returners.add(id);
23513             }
23514
23515             var entity = graph.hasEntity(id);
23516             if (!entity || entity.type !== 'relation') return;
23517             if (skipMultipolgonMembers && entity.isMultipolygon()) return;
23518             entity.members.map(function (member) {
23519               return member.id;
23520             }).forEach(collectDeepDescendants); // recurse
23521           }
23522         } // Adds or removes highlight styling for the specified entities
23523
23524         function utilHighlightEntities(ids, highlighted, context) {
23525           context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed('highlighted', highlighted);
23526         } // returns an Array that is the union of:
23527         //  - nodes for any nodeIDs passed in
23528         //  - child nodes of any wayIDs passed in
23529         //  - descendant member and child nodes of relationIDs passed in
23530
23531         function utilGetAllNodes(ids, graph) {
23532           var seen = new Set();
23533           var nodes = new Set();
23534           ids.forEach(collectNodes);
23535           return Array.from(nodes);
23536
23537           function collectNodes(id) {
23538             if (seen.has(id)) return;
23539             seen.add(id);
23540             var entity = graph.hasEntity(id);
23541             if (!entity) return;
23542
23543             if (entity.type === 'node') {
23544               nodes.add(entity);
23545             } else if (entity.type === 'way') {
23546               entity.nodes.forEach(collectNodes);
23547             } else {
23548               entity.members.map(function (member) {
23549                 return member.id;
23550               }).forEach(collectNodes); // recurse
23551             }
23552           }
23553         }
23554         function utilDisplayName(entity) {
23555           var localizedNameKey = 'name:' + _mainLocalizer.languageCode().toLowerCase();
23556           var name = entity.tags[localizedNameKey] || entity.tags.name || '';
23557           var network = entity.tags.cycle_network || entity.tags.network;
23558
23559           if (!name && entity.tags.ref) {
23560             name = entity.tags.ref;
23561
23562             if (network) {
23563               name = network + ' ' + name;
23564             }
23565           }
23566
23567           return name;
23568         }
23569         function utilDisplayNameForPath(entity) {
23570           var name = utilDisplayName(entity);
23571           var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
23572
23573           if (!isFirefox && name && rtlRegex.test(name)) {
23574             name = fixRTLTextForSvg(name);
23575           }
23576
23577           return name;
23578         }
23579         function utilDisplayType(id) {
23580           return {
23581             n: _t('inspector.node'),
23582             w: _t('inspector.way'),
23583             r: _t('inspector.relation')
23584           }[id.charAt(0)];
23585         }
23586         function utilDisplayLabel(entity, graphOrGeometry) {
23587           var displayName = utilDisplayName(entity);
23588
23589           if (displayName) {
23590             // use the display name if there is one
23591             return displayName;
23592           }
23593
23594           var preset = typeof graphOrGeometry === 'string' ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
23595
23596           if (preset && preset.name()) {
23597             // use the preset name if there is a match
23598             return preset.name();
23599           } // fallback to the display type (node/way/relation)
23600
23601
23602           return utilDisplayType(entity.id);
23603         }
23604         function utilEntityRoot(entityType) {
23605           return {
23606             node: 'n',
23607             way: 'w',
23608             relation: 'r'
23609           }[entityType];
23610         } // Returns a single object containing the tags of all the given entities.
23611         // Example:
23612         // {
23613         //   highway: 'service',
23614         //   service: 'parking_aisle'
23615         // }
23616         //           +
23617         // {
23618         //   highway: 'service',
23619         //   service: 'driveway',
23620         //   width: '3'
23621         // }
23622         //           =
23623         // {
23624         //   highway: 'service',
23625         //   service: [ 'driveway', 'parking_aisle' ],
23626         //   width: [ '3', undefined ]
23627         // }
23628
23629         function utilCombinedTags(entityIDs, graph) {
23630           var tags = {};
23631           var tagCounts = {};
23632           var allKeys = new Set();
23633           var entities = entityIDs.map(function (entityID) {
23634             return graph.hasEntity(entityID);
23635           }).filter(Boolean); // gather the aggregate keys
23636
23637           entities.forEach(function (entity) {
23638             var keys = Object.keys(entity.tags).filter(Boolean);
23639             keys.forEach(function (key) {
23640               allKeys.add(key);
23641             });
23642           });
23643           entities.forEach(function (entity) {
23644             allKeys.forEach(function (key) {
23645               var value = entity.tags[key]; // purposely allow `undefined`
23646
23647               if (!tags.hasOwnProperty(key)) {
23648                 // first value, set as raw
23649                 tags[key] = value;
23650               } else {
23651                 if (!Array.isArray(tags[key])) {
23652                   if (tags[key] !== value) {
23653                     // first alternate value, replace single value with array
23654                     tags[key] = [tags[key], value];
23655                   }
23656                 } else {
23657                   // type is array
23658                   if (tags[key].indexOf(value) === -1) {
23659                     // subsequent alternate value, add to array
23660                     tags[key].push(value);
23661                   }
23662                 }
23663               }
23664
23665               var tagHash = key + '=' + value;
23666               if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
23667               tagCounts[tagHash] += 1;
23668             });
23669           });
23670
23671           for (var key in tags) {
23672             if (!Array.isArray(tags[key])) continue; // sort values by frequency then alphabetically
23673
23674             tags[key] = tags[key].sort(function (val1, val2) {
23675               var key = key; // capture
23676
23677               var count2 = tagCounts[key + '=' + val2];
23678               var count1 = tagCounts[key + '=' + val1];
23679
23680               if (count2 !== count1) {
23681                 return count2 - count1;
23682               }
23683
23684               if (val2 && val1) {
23685                 return val1.localeCompare(val2);
23686               }
23687
23688               return val1 ? 1 : -1;
23689             });
23690           }
23691
23692           return tags;
23693         }
23694         function utilStringQs(str) {
23695           var i = 0; // advance past any leading '?' or '#' characters
23696
23697           while (i < str.length && (str[i] === '?' || str[i] === '#')) {
23698             i++;
23699           }
23700
23701           str = str.slice(i);
23702           return str.split('&').reduce(function (obj, pair) {
23703             var parts = pair.split('=');
23704
23705             if (parts.length === 2) {
23706               obj[parts[0]] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
23707             }
23708
23709             return obj;
23710           }, {});
23711         }
23712         function utilQsString(obj, noencode) {
23713           // encode everything except special characters used in certain hash parameters:
23714           // "/" in map states, ":", ",", {" and "}" in background
23715           function softEncode(s) {
23716             return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
23717           }
23718
23719           return Object.keys(obj).sort().map(function (key) {
23720             return encodeURIComponent(key) + '=' + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
23721           }).join('&');
23722         }
23723         function utilPrefixDOMProperty(property) {
23724           var prefixes = ['webkit', 'ms', 'moz', 'o'];
23725           var i = -1;
23726           var n = prefixes.length;
23727           var s = document.body;
23728           if (property in s) return property;
23729           property = property.substr(0, 1).toUpperCase() + property.substr(1);
23730
23731           while (++i < n) {
23732             if (prefixes[i] + property in s) {
23733               return prefixes[i] + property;
23734             }
23735           }
23736
23737           return false;
23738         }
23739         function utilPrefixCSSProperty(property) {
23740           var prefixes = ['webkit', 'ms', 'Moz', 'O'];
23741           var i = -1;
23742           var n = prefixes.length;
23743           var s = document.body.style;
23744
23745           if (property.toLowerCase() in s) {
23746             return property.toLowerCase();
23747           }
23748
23749           while (++i < n) {
23750             if (prefixes[i] + property in s) {
23751               return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
23752             }
23753           }
23754
23755           return false;
23756         }
23757         var transformProperty;
23758         function utilSetTransform(el, x, y, scale) {
23759           var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform');
23760           var translate = utilDetect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)';
23761           return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
23762         } // Calculates Levenshtein distance between two strings
23763         // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
23764         // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
23765
23766         function utilEditDistance(a, b) {
23767           a = remove$1(a.toLowerCase());
23768           b = remove$1(b.toLowerCase());
23769           if (a.length === 0) return b.length;
23770           if (b.length === 0) return a.length;
23771           var matrix = [];
23772           var i, j;
23773
23774           for (i = 0; i <= b.length; i++) {
23775             matrix[i] = [i];
23776           }
23777
23778           for (j = 0; j <= a.length; j++) {
23779             matrix[0][j] = j;
23780           }
23781
23782           for (i = 1; i <= b.length; i++) {
23783             for (j = 1; j <= a.length; j++) {
23784               if (b.charAt(i - 1) === a.charAt(j - 1)) {
23785                 matrix[i][j] = matrix[i - 1][j - 1];
23786               } else {
23787                 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
23788                 Math.min(matrix[i][j - 1] + 1, // insertion
23789                 matrix[i - 1][j] + 1)); // deletion
23790               }
23791             }
23792           }
23793
23794           return matrix[b.length][a.length];
23795         } // a d3.mouse-alike which
23796         // 1. Only works on HTML elements, not SVG
23797         // 2. Does not cause style recalculation
23798
23799         function utilFastMouse(container) {
23800           var rect = container.getBoundingClientRect();
23801           var rectLeft = rect.left;
23802           var rectTop = rect.top;
23803           var clientLeft = +container.clientLeft;
23804           var clientTop = +container.clientTop;
23805           return function (e) {
23806             return [e.clientX - rectLeft - clientLeft, e.clientY - rectTop - clientTop];
23807           };
23808         }
23809         function utilAsyncMap(inputs, func, callback) {
23810           var remaining = inputs.length;
23811           var results = [];
23812           var errors = [];
23813           inputs.forEach(function (d, i) {
23814             func(d, function done(err, data) {
23815               errors[i] = err;
23816               results[i] = data;
23817               remaining--;
23818               if (!remaining) callback(errors, results);
23819             });
23820           });
23821         } // wraps an index to an interval [0..length-1]
23822
23823         function utilWrap(index, length) {
23824           if (index < 0) {
23825             index += Math.ceil(-index / length) * length;
23826           }
23827
23828           return index % length;
23829         }
23830         /**
23831          * a replacement for functor
23832          *
23833          * @param {*} value any value
23834          * @returns {Function} a function that returns that value or the value if it's a function
23835          */
23836
23837         function utilFunctor(value) {
23838           if (typeof value === 'function') return value;
23839           return function () {
23840             return value;
23841           };
23842         }
23843         function utilNoAuto(selection) {
23844           var isText = selection.size() && selection.node().tagName.toLowerCase() === 'textarea';
23845           return selection // assign 'new-password' even for non-password fields to prevent browsers (Chrome) ignoring 'off'
23846           .attr('autocomplete', 'new-password').attr('autocorrect', 'off').attr('autocapitalize', 'off').attr('spellcheck', isText ? 'true' : 'false');
23847         } // https://stackoverflow.com/questions/194846/is-there-any-kind-of-hash-code-function-in-javascript
23848         // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
23849
23850         function utilHashcode(str) {
23851           var hash = 0;
23852
23853           if (str.length === 0) {
23854             return hash;
23855           }
23856
23857           for (var i = 0; i < str.length; i++) {
23858             var _char = str.charCodeAt(i);
23859
23860             hash = (hash << 5) - hash + _char;
23861             hash = hash & hash; // Convert to 32bit integer
23862           }
23863
23864           return hash;
23865         } // Returns version of `str` with all runs of special characters replaced by `_`;
23866         // suitable for HTML ids, classes, selectors, etc.
23867
23868         function utilSafeClassName(str) {
23869           return str.toLowerCase().replace(/[^a-z0-9]+/g, '_');
23870         } // Returns string based on `val` that is highly unlikely to collide with an id
23871         // used previously or that's present elsewhere in the document. Useful for preventing
23872         // browser-provided autofills or when embedding iD on pages with unknown elements.
23873
23874         function utilUniqueDomId(val) {
23875           return 'ideditor-' + utilSafeClassName(val.toString()) + '-' + new Date().getTime().toString();
23876         } // Returns the length of `str` in unicode characters. This can be less than
23877         // `String.length()` since a single unicode character can be composed of multiple
23878         // JavaScript UTF-16 code units.
23879
23880         function utilUnicodeCharsCount(str) {
23881           // Native ES2015 implementations of `Array.from` split strings into unicode characters
23882           return Array.from(str).length;
23883         } // Returns a new string representing `str` cut from its start to `limit` length
23884         // in unicode characters. Note that this runs the risk of splitting graphemes.
23885
23886         function utilUnicodeCharsTruncated(str, limit) {
23887           return Array.from(str).slice(0, limit).join('');
23888         }
23889
23890         function osmEntity(attrs) {
23891           // For prototypal inheritance.
23892           if (this instanceof osmEntity) return; // Create the appropriate subtype.
23893
23894           if (attrs && attrs.type) {
23895             return osmEntity[attrs.type].apply(this, arguments);
23896           } else if (attrs && attrs.id) {
23897             return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
23898           } // Initialize a generic Entity (used only in tests).
23899
23900
23901           return new osmEntity().initialize(arguments);
23902         }
23903
23904         osmEntity.id = function (type) {
23905           return osmEntity.id.fromOSM(type, osmEntity.id.next[type]--);
23906         };
23907
23908         osmEntity.id.next = {
23909           changeset: -1,
23910           node: -1,
23911           way: -1,
23912           relation: -1
23913         };
23914
23915         osmEntity.id.fromOSM = function (type, id) {
23916           return type[0] + id;
23917         };
23918
23919         osmEntity.id.toOSM = function (id) {
23920           return id.slice(1);
23921         };
23922
23923         osmEntity.id.type = function (id) {
23924           return {
23925             'c': 'changeset',
23926             'n': 'node',
23927             'w': 'way',
23928             'r': 'relation'
23929           }[id[0]];
23930         }; // A function suitable for use as the second argument to d3.selection#data().
23931
23932
23933         osmEntity.key = function (entity) {
23934           return entity.id + 'v' + (entity.v || 0);
23935         };
23936
23937         var _deprecatedTagValuesByKey;
23938
23939         osmEntity.deprecatedTagValuesByKey = function (dataDeprecated) {
23940           if (!_deprecatedTagValuesByKey) {
23941             _deprecatedTagValuesByKey = {};
23942             dataDeprecated.forEach(function (d) {
23943               var oldKeys = Object.keys(d.old);
23944
23945               if (oldKeys.length === 1) {
23946                 var oldKey = oldKeys[0];
23947                 var oldValue = d.old[oldKey];
23948
23949                 if (oldValue !== '*') {
23950                   if (!_deprecatedTagValuesByKey[oldKey]) {
23951                     _deprecatedTagValuesByKey[oldKey] = [oldValue];
23952                   } else {
23953                     _deprecatedTagValuesByKey[oldKey].push(oldValue);
23954                   }
23955                 }
23956               }
23957             });
23958           }
23959
23960           return _deprecatedTagValuesByKey;
23961         };
23962
23963         osmEntity.prototype = {
23964           tags: {},
23965           initialize: function initialize(sources) {
23966             for (var i = 0; i < sources.length; ++i) {
23967               var source = sources[i];
23968
23969               for (var prop in source) {
23970                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
23971                   if (source[prop] === undefined) {
23972                     delete this[prop];
23973                   } else {
23974                     this[prop] = source[prop];
23975                   }
23976                 }
23977               }
23978             }
23979
23980             if (!this.id && this.type) {
23981               this.id = osmEntity.id(this.type);
23982             }
23983
23984             if (!this.hasOwnProperty('visible')) {
23985               this.visible = true;
23986             }
23987
23988             return this;
23989           },
23990           copy: function copy(resolver, copies) {
23991             if (copies[this.id]) return copies[this.id];
23992             var copy = osmEntity(this, {
23993               id: undefined,
23994               user: undefined,
23995               version: undefined
23996             });
23997             copies[this.id] = copy;
23998             return copy;
23999           },
24000           osmId: function osmId() {
24001             return osmEntity.id.toOSM(this.id);
24002           },
24003           isNew: function isNew() {
24004             return this.osmId() < 0;
24005           },
24006           update: function update(attrs) {
24007             return osmEntity(this, attrs, {
24008               v: 1 + (this.v || 0)
24009             });
24010           },
24011           mergeTags: function mergeTags(tags) {
24012             var merged = Object.assign({}, this.tags); // shallow copy
24013
24014             var changed = false;
24015
24016             for (var k in tags) {
24017               var t1 = merged[k];
24018               var t2 = tags[k];
24019
24020               if (!t1) {
24021                 changed = true;
24022                 merged[k] = t2;
24023               } else if (t1 !== t2) {
24024                 changed = true;
24025                 merged[k] = utilUnicodeCharsTruncated(utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(';'), 255 // avoid exceeding character limit; see also services/osm.js -> maxCharsForTagValue()
24026                 );
24027               }
24028             }
24029
24030             return changed ? this.update({
24031               tags: merged
24032             }) : this;
24033           },
24034           intersects: function intersects(extent, resolver) {
24035             return this.extent(resolver).intersects(extent);
24036           },
24037           hasNonGeometryTags: function hasNonGeometryTags() {
24038             return Object.keys(this.tags).some(function (k) {
24039               return k !== 'area';
24040             });
24041           },
24042           hasParentRelations: function hasParentRelations(resolver) {
24043             return resolver.parentRelations(this).length > 0;
24044           },
24045           hasInterestingTags: function hasInterestingTags() {
24046             return Object.keys(this.tags).some(osmIsInterestingTag);
24047           },
24048           hasWikidata: function hasWikidata() {
24049             return !!this.tags.wikidata || !!this.tags['brand:wikidata'];
24050           },
24051           isHighwayIntersection: function isHighwayIntersection() {
24052             return false;
24053           },
24054           isDegenerate: function isDegenerate() {
24055             return true;
24056           },
24057           deprecatedTags: function deprecatedTags(dataDeprecated) {
24058             var tags = this.tags; // if there are no tags, none can be deprecated
24059
24060             if (Object.keys(tags).length === 0) return [];
24061             var deprecated = [];
24062             dataDeprecated.forEach(function (d) {
24063               var oldKeys = Object.keys(d.old);
24064
24065               if (d.replace) {
24066                 var hasExistingValues = Object.keys(d.replace).some(function (replaceKey) {
24067                   if (!tags[replaceKey] || d.old[replaceKey]) return false;
24068                   var replaceValue = d.replace[replaceKey];
24069                   if (replaceValue === '*') return false;
24070                   if (replaceValue === tags[replaceKey]) return false;
24071                   return true;
24072                 }); // don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
24073
24074                 if (hasExistingValues) return;
24075               }
24076
24077               var matchesDeprecatedTags = oldKeys.every(function (oldKey) {
24078                 if (!tags[oldKey]) return false;
24079                 if (d.old[oldKey] === '*') return true;
24080                 if (d.old[oldKey] === tags[oldKey]) return true;
24081                 var vals = tags[oldKey].split(';').filter(Boolean);
24082
24083                 if (vals.length === 0) {
24084                   return false;
24085                 } else if (vals.length > 1) {
24086                   return vals.indexOf(d.old[oldKey]) !== -1;
24087                 } else {
24088                   if (tags[oldKey] === d.old[oldKey]) {
24089                     if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
24090                       var replaceKeys = Object.keys(d.replace);
24091                       return !replaceKeys.every(function (replaceKey) {
24092                         return tags[replaceKey] === d.replace[replaceKey];
24093                       });
24094                     } else {
24095                       return true;
24096                     }
24097                   }
24098                 }
24099
24100                 return false;
24101               });
24102
24103               if (matchesDeprecatedTags) {
24104                 deprecated.push(d);
24105               }
24106             });
24107             return deprecated;
24108           }
24109         };
24110
24111         function osmLanes(entity) {
24112           if (entity.type !== 'way') return null;
24113           if (!entity.tags.highway) return null;
24114           var tags = entity.tags;
24115           var isOneWay = entity.isOneWay();
24116           var laneCount = getLaneCount(tags, isOneWay);
24117           var maxspeed = parseMaxspeed(tags);
24118           var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
24119           var forward = laneDirections.forward;
24120           var backward = laneDirections.backward;
24121           var bothways = laneDirections.bothways; // parse the piped string 'x|y|z' format
24122
24123           var turnLanes = {};
24124           turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
24125           turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
24126           turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
24127           var maxspeedLanes = {};
24128           maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
24129           maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
24130           maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
24131           var psvLanes = {};
24132           psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
24133           psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
24134           psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
24135           var busLanes = {};
24136           busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
24137           busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
24138           busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
24139           var taxiLanes = {};
24140           taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
24141           taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
24142           taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
24143           var hovLanes = {};
24144           hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
24145           hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
24146           hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
24147           var hgvLanes = {};
24148           hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
24149           hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
24150           hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
24151           var bicyclewayLanes = {};
24152           bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
24153           bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
24154           bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
24155           var lanesObj = {
24156             forward: [],
24157             backward: [],
24158             unspecified: []
24159           }; // map forward/backward/unspecified of each lane type to lanesObj
24160
24161           mapToLanesObj(lanesObj, turnLanes, 'turnLane');
24162           mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
24163           mapToLanesObj(lanesObj, psvLanes, 'psv');
24164           mapToLanesObj(lanesObj, busLanes, 'bus');
24165           mapToLanesObj(lanesObj, taxiLanes, 'taxi');
24166           mapToLanesObj(lanesObj, hovLanes, 'hov');
24167           mapToLanesObj(lanesObj, hgvLanes, 'hgv');
24168           mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
24169           return {
24170             metadata: {
24171               count: laneCount,
24172               oneway: isOneWay,
24173               forward: forward,
24174               backward: backward,
24175               bothways: bothways,
24176               turnLanes: turnLanes,
24177               maxspeed: maxspeed,
24178               maxspeedLanes: maxspeedLanes,
24179               psvLanes: psvLanes,
24180               busLanes: busLanes,
24181               taxiLanes: taxiLanes,
24182               hovLanes: hovLanes,
24183               hgvLanes: hgvLanes,
24184               bicyclewayLanes: bicyclewayLanes
24185             },
24186             lanes: lanesObj
24187           };
24188         }
24189
24190         function getLaneCount(tags, isOneWay) {
24191           var count;
24192
24193           if (tags.lanes) {
24194             count = parseInt(tags.lanes, 10);
24195
24196             if (count > 0) {
24197               return count;
24198             }
24199           }
24200
24201           switch (tags.highway) {
24202             case 'trunk':
24203             case 'motorway':
24204               count = isOneWay ? 2 : 4;
24205               break;
24206
24207             default:
24208               count = isOneWay ? 1 : 2;
24209               break;
24210           }
24211
24212           return count;
24213         }
24214
24215         function parseMaxspeed(tags) {
24216           var maxspeed = tags.maxspeed;
24217           if (!maxspeed) return;
24218           var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
24219           if (!maxspeedRegex.test(maxspeed)) return;
24220           return parseInt(maxspeed, 10);
24221         }
24222
24223         function parseLaneDirections(tags, isOneWay, laneCount) {
24224           var forward = parseInt(tags['lanes:forward'], 10);
24225           var backward = parseInt(tags['lanes:backward'], 10);
24226           var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
24227
24228           if (parseInt(tags.oneway, 10) === -1) {
24229             forward = 0;
24230             bothways = 0;
24231             backward = laneCount;
24232           } else if (isOneWay) {
24233             forward = laneCount;
24234             bothways = 0;
24235             backward = 0;
24236           } else if (isNaN(forward) && isNaN(backward)) {
24237             backward = Math.floor((laneCount - bothways) / 2);
24238             forward = laneCount - bothways - backward;
24239           } else if (isNaN(forward)) {
24240             if (backward > laneCount - bothways) {
24241               backward = laneCount - bothways;
24242             }
24243
24244             forward = laneCount - bothways - backward;
24245           } else if (isNaN(backward)) {
24246             if (forward > laneCount - bothways) {
24247               forward = laneCount - bothways;
24248             }
24249
24250             backward = laneCount - bothways - forward;
24251           }
24252
24253           return {
24254             forward: forward,
24255             backward: backward,
24256             bothways: bothways
24257           };
24258         }
24259
24260         function parseTurnLanes(tag) {
24261           if (!tag) return;
24262           var validValues = ['left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right', 'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'];
24263           return tag.split('|').map(function (s) {
24264             if (s === '') s = 'none';
24265             return s.split(';').map(function (d) {
24266               return validValues.indexOf(d) === -1 ? 'unknown' : d;
24267             });
24268           });
24269         }
24270
24271         function parseMaxspeedLanes(tag, maxspeed) {
24272           if (!tag) return;
24273           return tag.split('|').map(function (s) {
24274             if (s === 'none') return s;
24275             var m = parseInt(s, 10);
24276             if (s === '' || m === maxspeed) return null;
24277             return isNaN(m) ? 'unknown' : m;
24278           });
24279         }
24280
24281         function parseMiscLanes(tag) {
24282           if (!tag) return;
24283           var validValues = ['yes', 'no', 'designated'];
24284           return tag.split('|').map(function (s) {
24285             if (s === '') s = 'no';
24286             return validValues.indexOf(s) === -1 ? 'unknown' : s;
24287           });
24288         }
24289
24290         function parseBicycleWay(tag) {
24291           if (!tag) return;
24292           var validValues = ['yes', 'no', 'designated', 'lane'];
24293           return tag.split('|').map(function (s) {
24294             if (s === '') s = 'no';
24295             return validValues.indexOf(s) === -1 ? 'unknown' : s;
24296           });
24297         }
24298
24299         function mapToLanesObj(lanesObj, data, key) {
24300           if (data.forward) data.forward.forEach(function (l, i) {
24301             if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
24302             lanesObj.forward[i][key] = l;
24303           });
24304           if (data.backward) data.backward.forEach(function (l, i) {
24305             if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
24306             lanesObj.backward[i][key] = l;
24307           });
24308           if (data.unspecified) data.unspecified.forEach(function (l, i) {
24309             if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
24310             lanesObj.unspecified[i][key] = l;
24311           });
24312         }
24313
24314         function osmWay() {
24315           if (!(this instanceof osmWay)) {
24316             return new osmWay().initialize(arguments);
24317           } else if (arguments.length) {
24318             this.initialize(arguments);
24319           }
24320         }
24321         osmEntity.way = osmWay;
24322         osmWay.prototype = Object.create(osmEntity.prototype);
24323         Object.assign(osmWay.prototype, {
24324           type: 'way',
24325           nodes: [],
24326           copy: function copy(resolver, copies) {
24327             if (copies[this.id]) return copies[this.id];
24328             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
24329             var nodes = this.nodes.map(function (id) {
24330               return resolver.entity(id).copy(resolver, copies).id;
24331             });
24332             copy = copy.update({
24333               nodes: nodes
24334             });
24335             copies[this.id] = copy;
24336             return copy;
24337           },
24338           extent: function extent(resolver) {
24339             return resolver["transient"](this, 'extent', function () {
24340               var extent = geoExtent();
24341
24342               for (var i = 0; i < this.nodes.length; i++) {
24343                 var node = resolver.hasEntity(this.nodes[i]);
24344
24345                 if (node) {
24346                   extent._extend(node.extent());
24347                 }
24348               }
24349
24350               return extent;
24351             });
24352           },
24353           first: function first() {
24354             return this.nodes[0];
24355           },
24356           last: function last() {
24357             return this.nodes[this.nodes.length - 1];
24358           },
24359           contains: function contains(node) {
24360             return this.nodes.indexOf(node) >= 0;
24361           },
24362           affix: function affix(node) {
24363             if (this.nodes[0] === node) return 'prefix';
24364             if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
24365           },
24366           layer: function layer() {
24367             // explicit layer tag, clamp between -10, 10..
24368             if (isFinite(this.tags.layer)) {
24369               return Math.max(-10, Math.min(+this.tags.layer, 10));
24370             } // implied layer tag..
24371
24372
24373             if (this.tags.covered === 'yes') return -1;
24374             if (this.tags.location === 'overground') return 1;
24375             if (this.tags.location === 'underground') return -1;
24376             if (this.tags.location === 'underwater') return -10;
24377             if (this.tags.power === 'line') return 10;
24378             if (this.tags.power === 'minor_line') return 10;
24379             if (this.tags.aerialway) return 10;
24380             if (this.tags.bridge) return 1;
24381             if (this.tags.cutting) return -1;
24382             if (this.tags.tunnel) return -1;
24383             if (this.tags.waterway) return -1;
24384             if (this.tags.man_made === 'pipeline') return -10;
24385             if (this.tags.boundary) return -10;
24386             return 0;
24387           },
24388           // the approximate width of the line based on its tags except its `width` tag
24389           impliedLineWidthMeters: function impliedLineWidthMeters() {
24390             var averageWidths = {
24391               highway: {
24392                 // width is for single lane
24393                 motorway: 5,
24394                 motorway_link: 5,
24395                 trunk: 4.5,
24396                 trunk_link: 4.5,
24397                 primary: 4,
24398                 secondary: 4,
24399                 tertiary: 4,
24400                 primary_link: 4,
24401                 secondary_link: 4,
24402                 tertiary_link: 4,
24403                 unclassified: 4,
24404                 road: 4,
24405                 living_street: 4,
24406                 bus_guideway: 4,
24407                 pedestrian: 4,
24408                 residential: 3.5,
24409                 service: 3.5,
24410                 track: 3,
24411                 cycleway: 2.5,
24412                 bridleway: 2,
24413                 corridor: 2,
24414                 steps: 2,
24415                 path: 1.5,
24416                 footway: 1.5
24417               },
24418               railway: {
24419                 // width includes ties and rail bed, not just track gauge
24420                 rail: 2.5,
24421                 light_rail: 2.5,
24422                 tram: 2.5,
24423                 subway: 2.5,
24424                 monorail: 2.5,
24425                 funicular: 2.5,
24426                 disused: 2.5,
24427                 preserved: 2.5,
24428                 miniature: 1.5,
24429                 narrow_gauge: 1.5
24430               },
24431               waterway: {
24432                 river: 50,
24433                 canal: 25,
24434                 stream: 5,
24435                 tidal_channel: 5,
24436                 fish_pass: 2.5,
24437                 drain: 2.5,
24438                 ditch: 1.5
24439               }
24440             };
24441
24442             for (var key in averageWidths) {
24443               if (this.tags[key] && averageWidths[key][this.tags[key]]) {
24444                 var width = averageWidths[key][this.tags[key]];
24445
24446                 if (key === 'highway') {
24447                   var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
24448                   if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
24449                   return width * laneCount;
24450                 }
24451
24452                 return width;
24453               }
24454             }
24455
24456             return null;
24457           },
24458           isOneWay: function isOneWay() {
24459             // explicit oneway tag..
24460             var values = {
24461               'yes': true,
24462               '1': true,
24463               '-1': true,
24464               'reversible': true,
24465               'alternating': true,
24466               'no': false,
24467               '0': false
24468             };
24469
24470             if (values[this.tags.oneway] !== undefined) {
24471               return values[this.tags.oneway];
24472             } // implied oneway tag..
24473
24474
24475             for (var key in this.tags) {
24476               if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) return true;
24477             }
24478
24479             return false;
24480           },
24481           // Some identifier for tag that implies that this way is "sided",
24482           // i.e. the right side is the 'inside' (e.g. the right side of a
24483           // natural=cliff is lower).
24484           sidednessIdentifier: function sidednessIdentifier() {
24485             for (var key in this.tags) {
24486               var value = this.tags[key];
24487
24488               if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
24489                 if (osmRightSideIsInsideTags[key][value] === true) {
24490                   return key;
24491                 } else {
24492                   // if the map's value is something other than a
24493                   // literal true, we should use it so we can
24494                   // special case some keys (e.g. natural=coastline
24495                   // is handled differently to other naturals).
24496                   return osmRightSideIsInsideTags[key][value];
24497                 }
24498               }
24499             }
24500
24501             return null;
24502           },
24503           isSided: function isSided() {
24504             if (this.tags.two_sided === 'yes') {
24505               return false;
24506             }
24507
24508             return this.sidednessIdentifier() !== null;
24509           },
24510           lanes: function lanes() {
24511             return osmLanes(this);
24512           },
24513           isClosed: function isClosed() {
24514             return this.nodes.length > 1 && this.first() === this.last();
24515           },
24516           isConvex: function isConvex(resolver) {
24517             if (!this.isClosed() || this.isDegenerate()) return null;
24518             var nodes = utilArrayUniq(resolver.childNodes(this));
24519             var coords = nodes.map(function (n) {
24520               return n.loc;
24521             });
24522             var curr = 0;
24523             var prev = 0;
24524
24525             for (var i = 0; i < coords.length; i++) {
24526               var o = coords[(i + 1) % coords.length];
24527               var a = coords[i];
24528               var b = coords[(i + 2) % coords.length];
24529               var res = geoVecCross(a, b, o);
24530               curr = res > 0 ? 1 : res < 0 ? -1 : 0;
24531
24532               if (curr === 0) {
24533                 continue;
24534               } else if (prev && curr !== prev) {
24535                 return false;
24536               }
24537
24538               prev = curr;
24539             }
24540
24541             return true;
24542           },
24543           // returns an object with the tag that implies this is an area, if any
24544           tagSuggestingArea: function tagSuggestingArea() {
24545             return osmTagSuggestingArea(this.tags);
24546           },
24547           isArea: function isArea() {
24548             if (this.tags.area === 'yes') return true;
24549             if (!this.isClosed() || this.tags.area === 'no') return false;
24550             return this.tagSuggestingArea() !== null;
24551           },
24552           isDegenerate: function isDegenerate() {
24553             return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
24554           },
24555           areAdjacent: function areAdjacent(n1, n2) {
24556             for (var i = 0; i < this.nodes.length; i++) {
24557               if (this.nodes[i] === n1) {
24558                 if (this.nodes[i - 1] === n2) return true;
24559                 if (this.nodes[i + 1] === n2) return true;
24560               }
24561             }
24562
24563             return false;
24564           },
24565           geometry: function geometry(graph) {
24566             return graph["transient"](this, 'geometry', function () {
24567               return this.isArea() ? 'area' : 'line';
24568             });
24569           },
24570           // returns an array of objects representing the segments between the nodes in this way
24571           segments: function segments(graph) {
24572             function segmentExtent(graph) {
24573               var n1 = graph.hasEntity(this.nodes[0]);
24574               var n2 = graph.hasEntity(this.nodes[1]);
24575               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])]]);
24576             }
24577
24578             return graph["transient"](this, 'segments', function () {
24579               var segments = [];
24580
24581               for (var i = 0; i < this.nodes.length - 1; i++) {
24582                 segments.push({
24583                   id: this.id + '-' + i,
24584                   wayId: this.id,
24585                   index: i,
24586                   nodes: [this.nodes[i], this.nodes[i + 1]],
24587                   extent: segmentExtent
24588                 });
24589               }
24590
24591               return segments;
24592             });
24593           },
24594           // If this way is not closed, append the beginning node to the end of the nodelist to close it.
24595           close: function close() {
24596             if (this.isClosed() || !this.nodes.length) return this;
24597             var nodes = this.nodes.slice();
24598             nodes = nodes.filter(noRepeatNodes);
24599             nodes.push(nodes[0]);
24600             return this.update({
24601               nodes: nodes
24602             });
24603           },
24604           // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
24605           unclose: function unclose() {
24606             if (!this.isClosed()) return this;
24607             var nodes = this.nodes.slice();
24608             var connector = this.first();
24609             var i = nodes.length - 1; // remove trailing connectors..
24610
24611             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24612               nodes.splice(i, 1);
24613               i = nodes.length - 1;
24614             }
24615
24616             nodes = nodes.filter(noRepeatNodes);
24617             return this.update({
24618               nodes: nodes
24619             });
24620           },
24621           // Adds a node (id) in front of the node which is currently at position index.
24622           // If index is undefined, the node will be added to the end of the way for linear ways,
24623           //   or just before the final connecting node for circular ways.
24624           // Consecutive duplicates are eliminated including existing ones.
24625           // Circularity is always preserved when adding a node.
24626           addNode: function addNode(id, index) {
24627             var nodes = this.nodes.slice();
24628             var isClosed = this.isClosed();
24629             var max = isClosed ? nodes.length - 1 : nodes.length;
24630
24631             if (index === undefined) {
24632               index = max;
24633             }
24634
24635             if (index < 0 || index > max) {
24636               throw new RangeError('index ' + index + ' out of range 0..' + max);
24637             } // If this is a closed way, remove all connector nodes except the first one
24638             // (there may be duplicates) and adjust index if necessary..
24639
24640
24641             if (isClosed) {
24642               var connector = this.first(); // leading connectors..
24643
24644               var i = 1;
24645
24646               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
24647                 nodes.splice(i, 1);
24648                 if (index > i) index--;
24649               } // trailing connectors..
24650
24651
24652               i = nodes.length - 1;
24653
24654               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24655                 nodes.splice(i, 1);
24656                 if (index > i) index--;
24657                 i = nodes.length - 1;
24658               }
24659             }
24660
24661             nodes.splice(index, 0, id);
24662             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24663
24664             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24665               nodes.push(nodes[0]);
24666             }
24667
24668             return this.update({
24669               nodes: nodes
24670             });
24671           },
24672           // Replaces the node which is currently at position index with the given node (id).
24673           // Consecutive duplicates are eliminated including existing ones.
24674           // Circularity is preserved when updating a node.
24675           updateNode: function updateNode(id, index) {
24676             var nodes = this.nodes.slice();
24677             var isClosed = this.isClosed();
24678             var max = nodes.length - 1;
24679
24680             if (index === undefined || index < 0 || index > max) {
24681               throw new RangeError('index ' + index + ' out of range 0..' + max);
24682             } // If this is a closed way, remove all connector nodes except the first one
24683             // (there may be duplicates) and adjust index if necessary..
24684
24685
24686             if (isClosed) {
24687               var connector = this.first(); // leading connectors..
24688
24689               var i = 1;
24690
24691               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
24692                 nodes.splice(i, 1);
24693                 if (index > i) index--;
24694               } // trailing connectors..
24695
24696
24697               i = nodes.length - 1;
24698
24699               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24700                 nodes.splice(i, 1);
24701                 if (index === i) index = 0; // update leading connector instead
24702
24703                 i = nodes.length - 1;
24704               }
24705             }
24706
24707             nodes.splice(index, 1, id);
24708             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24709
24710             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24711               nodes.push(nodes[0]);
24712             }
24713
24714             return this.update({
24715               nodes: nodes
24716             });
24717           },
24718           // Replaces each occurrence of node id needle with replacement.
24719           // Consecutive duplicates are eliminated including existing ones.
24720           // Circularity is preserved.
24721           replaceNode: function replaceNode(needleID, replacementID) {
24722             var nodes = this.nodes.slice();
24723             var isClosed = this.isClosed();
24724
24725             for (var i = 0; i < nodes.length; i++) {
24726               if (nodes[i] === needleID) {
24727                 nodes[i] = replacementID;
24728               }
24729             }
24730
24731             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24732
24733             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24734               nodes.push(nodes[0]);
24735             }
24736
24737             return this.update({
24738               nodes: nodes
24739             });
24740           },
24741           // Removes each occurrence of node id.
24742           // Consecutive duplicates are eliminated including existing ones.
24743           // Circularity is preserved.
24744           removeNode: function removeNode(id) {
24745             var nodes = this.nodes.slice();
24746             var isClosed = this.isClosed();
24747             nodes = nodes.filter(function (node) {
24748               return node !== id;
24749             }).filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24750
24751             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24752               nodes.push(nodes[0]);
24753             }
24754
24755             return this.update({
24756               nodes: nodes
24757             });
24758           },
24759           asJXON: function asJXON(changeset_id) {
24760             var r = {
24761               way: {
24762                 '@id': this.osmId(),
24763                 '@version': this.version || 0,
24764                 nd: this.nodes.map(function (id) {
24765                   return {
24766                     keyAttributes: {
24767                       ref: osmEntity.id.toOSM(id)
24768                     }
24769                   };
24770                 }, this),
24771                 tag: Object.keys(this.tags).map(function (k) {
24772                   return {
24773                     keyAttributes: {
24774                       k: k,
24775                       v: this.tags[k]
24776                     }
24777                   };
24778                 }, this)
24779               }
24780             };
24781
24782             if (changeset_id) {
24783               r.way['@changeset'] = changeset_id;
24784             }
24785
24786             return r;
24787           },
24788           asGeoJSON: function asGeoJSON(resolver) {
24789             return resolver["transient"](this, 'GeoJSON', function () {
24790               var coordinates = resolver.childNodes(this).map(function (n) {
24791                 return n.loc;
24792               });
24793
24794               if (this.isArea() && this.isClosed()) {
24795                 return {
24796                   type: 'Polygon',
24797                   coordinates: [coordinates]
24798                 };
24799               } else {
24800                 return {
24801                   type: 'LineString',
24802                   coordinates: coordinates
24803                 };
24804               }
24805             });
24806           },
24807           area: function area(resolver) {
24808             return resolver["transient"](this, 'area', function () {
24809               var nodes = resolver.childNodes(this);
24810               var json = {
24811                 type: 'Polygon',
24812                 coordinates: [nodes.map(function (n) {
24813                   return n.loc;
24814                 })]
24815               };
24816
24817               if (!this.isClosed() && nodes.length) {
24818                 json.coordinates[0].push(nodes[0].loc);
24819               }
24820
24821               var area = d3_geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes
24822               // that OpenStreetMap polygons are not hemisphere-spanning.
24823
24824               if (area > 2 * Math.PI) {
24825                 json.coordinates[0] = json.coordinates[0].reverse();
24826                 area = d3_geoArea(json);
24827               }
24828
24829               return isNaN(area) ? 0 : area;
24830             });
24831           }
24832         }); // Filter function to eliminate consecutive duplicates.
24833
24834         function noRepeatNodes(node, i, arr) {
24835           return i === 0 || node !== arr[i - 1];
24836         }
24837
24838         //
24839         // 1. Relation tagged with `type=multipolygon` and no interesting tags.
24840         // 2. One and only one member with the `outer` role. Must be a way with interesting tags.
24841         // 3. No members without a role.
24842         //
24843         // Old multipolygons are no longer recommended but are still rendered as areas by iD.
24844
24845         function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
24846           if (entity.type !== 'relation' || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
24847             return false;
24848           }
24849
24850           var outerMember;
24851
24852           for (var memberIndex in entity.members) {
24853             var member = entity.members[memberIndex];
24854
24855             if (!member.role || member.role === 'outer') {
24856               if (outerMember) return false;
24857               if (member.type !== 'way') return false;
24858               if (!graph.hasEntity(member.id)) return false;
24859               outerMember = graph.entity(member.id);
24860
24861               if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
24862                 return false;
24863               }
24864             }
24865           }
24866
24867           return outerMember;
24868         } // For fixing up rendering of multipolygons with tags on the outer member.
24869         // https://github.com/openstreetmap/iD/issues/613
24870
24871         function osmIsOldMultipolygonOuterMember(entity, graph) {
24872           if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) return false;
24873           var parents = graph.parentRelations(entity);
24874           if (parents.length !== 1) return false;
24875           var parent = parents[0];
24876           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) return false;
24877           var members = parent.members,
24878               member;
24879
24880           for (var i = 0; i < members.length; i++) {
24881             member = members[i];
24882             if (member.id === entity.id && member.role && member.role !== 'outer') return false; // Not outer member
24883
24884             if (member.id !== entity.id && (!member.role || member.role === 'outer')) return false; // Not a simple multipolygon
24885           }
24886
24887           return parent;
24888         }
24889         function osmOldMultipolygonOuterMember(entity, graph) {
24890           if (entity.type !== 'way') return false;
24891           var parents = graph.parentRelations(entity);
24892           if (parents.length !== 1) return false;
24893           var parent = parents[0];
24894           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) return false;
24895           var members = parent.members,
24896               member,
24897               outerMember;
24898
24899           for (var i = 0; i < members.length; i++) {
24900             member = members[i];
24901
24902             if (!member.role || member.role === 'outer') {
24903               if (outerMember) return false; // Not a simple multipolygon
24904
24905               outerMember = member;
24906             }
24907           }
24908
24909           if (!outerMember) return false;
24910           var outerEntity = graph.hasEntity(outerMember.id);
24911           if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) return false;
24912           return outerEntity;
24913         } // Join `toJoin` array into sequences of connecting ways.
24914         // Segments which share identical start/end nodes will, as much as possible,
24915         // be connected with each other.
24916         //
24917         // The return value is a nested array. Each constituent array contains elements
24918         // of `toJoin` which have been determined to connect.
24919         //
24920         // Each consitituent array also has a `nodes` property whose value is an
24921         // ordered array of member nodes, with appropriate order reversal and
24922         // start/end coordinate de-duplication.
24923         //
24924         // Members of `toJoin` must have, at minimum, `type` and `id` properties.
24925         // Thus either an array of `osmWay`s or a relation member array may be used.
24926         //
24927         // If an member is an `osmWay`, its tags and childnodes may be reversed via
24928         // `actionReverse` in the output.
24929         //
24930         // The returned sequences array also has an `actions` array property, containing
24931         // any reversal actions that should be applied to the graph, should the calling
24932         // code attempt to actually join the given ways.
24933         //
24934         // Incomplete members (those for which `graph.hasEntity(element.id)` returns
24935         // false) and non-way members are ignored.
24936         //
24937
24938         function osmJoinWays(toJoin, graph) {
24939           function resolve(member) {
24940             return graph.childNodes(graph.entity(member.id));
24941           }
24942
24943           function reverse(item) {
24944             var action = actionReverse(item.id, {
24945               reverseOneway: true
24946             });
24947             sequences.actions.push(action);
24948             return item instanceof osmWay ? action(graph).entity(item.id) : item;
24949           } // make a copy containing only the items to join
24950
24951
24952           toJoin = toJoin.filter(function (member) {
24953             return member.type === 'way' && graph.hasEntity(member.id);
24954           }); // Are the things we are joining relation members or `osmWays`?
24955           // If `osmWays`, skip the "prefer a forward path" code below (see #4872)
24956
24957           var i;
24958           var joinAsMembers = true;
24959
24960           for (i = 0; i < toJoin.length; i++) {
24961             if (toJoin[i] instanceof osmWay) {
24962               joinAsMembers = false;
24963               break;
24964             }
24965           }
24966
24967           var sequences = [];
24968           sequences.actions = [];
24969
24970           while (toJoin.length) {
24971             // start a new sequence
24972             var item = toJoin.shift();
24973             var currWays = [item];
24974             var currNodes = resolve(item).slice(); // add to it
24975
24976             while (toJoin.length) {
24977               var start = currNodes[0];
24978               var end = currNodes[currNodes.length - 1];
24979               var fn = null;
24980               var nodes = null; // Find the next way/member to join.
24981
24982               for (i = 0; i < toJoin.length; i++) {
24983                 item = toJoin[i];
24984                 nodes = resolve(item); // (for member ordering only, not way ordering - see #4872)
24985                 // Strongly prefer to generate a forward path that preserves the order
24986                 // of the members array. For multipolygons and most relations, member
24987                 // order does not matter - but for routes, it does. (see #4589)
24988                 // If we started this sequence backwards (i.e. next member way attaches to
24989                 // the start node and not the end node), reverse the initial way before continuing.
24990
24991                 if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start || nodes[0] === start)) {
24992                   currWays[0] = reverse(currWays[0]);
24993                   currNodes.reverse();
24994                   start = currNodes[0];
24995                   end = currNodes[currNodes.length - 1];
24996                 }
24997
24998                 if (nodes[0] === end) {
24999                   fn = currNodes.push; // join to end
25000
25001                   nodes = nodes.slice(1);
25002                   break;
25003                 } else if (nodes[nodes.length - 1] === end) {
25004                   fn = currNodes.push; // join to end
25005
25006                   nodes = nodes.slice(0, -1).reverse();
25007                   item = reverse(item);
25008                   break;
25009                 } else if (nodes[nodes.length - 1] === start) {
25010                   fn = currNodes.unshift; // join to beginning
25011
25012                   nodes = nodes.slice(0, -1);
25013                   break;
25014                 } else if (nodes[0] === start) {
25015                   fn = currNodes.unshift; // join to beginning
25016
25017                   nodes = nodes.slice(1).reverse();
25018                   item = reverse(item);
25019                   break;
25020                 } else {
25021                   fn = nodes = null;
25022                 }
25023               }
25024
25025               if (!nodes) {
25026                 // couldn't find a joinable way/member
25027                 break;
25028               }
25029
25030               fn.apply(currWays, [item]);
25031               fn.apply(currNodes, nodes);
25032               toJoin.splice(i, 1);
25033             }
25034
25035             currWays.nodes = currNodes;
25036             sequences.push(currWays);
25037           }
25038
25039           return sequences;
25040         }
25041
25042         function actionAddMember(relationId, member, memberIndex, insertPair) {
25043           return function action(graph) {
25044             var relation = graph.entity(relationId); // There are some special rules for Public Transport v2 routes.
25045
25046             var isPTv2 = /stop|platform/.test(member.role);
25047
25048             if ((isNaN(memberIndex) || insertPair) && member.type === 'way' && !isPTv2) {
25049               // Try to perform sensible inserts based on how the ways join together
25050               graph = addWayMember(relation, graph);
25051             } else {
25052               // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
25053               // Stops and Platforms for PTv2 should be ordered first.
25054               // hack: We do not currently have the ability to place them in the exactly correct order.
25055               if (isPTv2 && isNaN(memberIndex)) {
25056                 memberIndex = 0;
25057               }
25058
25059               graph = graph.replace(relation.addMember(member, memberIndex));
25060             }
25061
25062             return graph;
25063           }; // Add a way member into the relation "wherever it makes sense".
25064           // In this situation we were not supplied a memberIndex.
25065
25066           function addWayMember(relation, graph) {
25067             var groups, tempWay, item, i, j, k; // remove PTv2 stops and platforms before doing anything.
25068
25069             var PTv2members = [];
25070             var members = [];
25071
25072             for (i = 0; i < relation.members.length; i++) {
25073               var m = relation.members[i];
25074
25075               if (/stop|platform/.test(m.role)) {
25076                 PTv2members.push(m);
25077               } else {
25078                 members.push(m);
25079               }
25080             }
25081
25082             relation = relation.update({
25083               members: members
25084             });
25085
25086             if (insertPair) {
25087               // We're adding a member that must stay paired with an existing member.
25088               // (This feature is used by `actionSplit`)
25089               //
25090               // This is tricky because the members may exist multiple times in the
25091               // member list, and with different A-B/B-A ordering and different roles.
25092               // (e.g. a bus route that loops out and back - #4589).
25093               //
25094               // Replace the existing member with a temporary way,
25095               // so that `osmJoinWays` can treat the pair like a single way.
25096               tempWay = osmWay({
25097                 id: 'wTemp',
25098                 nodes: insertPair.nodes
25099               });
25100               graph = graph.replace(tempWay);
25101               var tempMember = {
25102                 id: tempWay.id,
25103                 type: 'way',
25104                 role: member.role
25105               };
25106               var tempRelation = relation.replaceMember({
25107                 id: insertPair.originalID
25108               }, tempMember, true);
25109               groups = utilArrayGroupBy(tempRelation.members, 'type');
25110               groups.way = groups.way || [];
25111             } else {
25112               // Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
25113               groups = utilArrayGroupBy(relation.members, 'type');
25114               groups.way = groups.way || [];
25115               groups.way.push(member);
25116             }
25117
25118             members = withIndex(groups.way);
25119             var joined = osmJoinWays(members, graph); // `joined` might not contain all of the way members,
25120             // But will contain only the completed (downloaded) members
25121
25122             for (i = 0; i < joined.length; i++) {
25123               var segment = joined[i];
25124               var nodes = segment.nodes.slice();
25125               var startIndex = segment[0].index; // j = array index in `members` where this segment starts
25126
25127               for (j = 0; j < members.length; j++) {
25128                 if (members[j].index === startIndex) {
25129                   break;
25130                 }
25131               } // k = each member in segment
25132
25133
25134               for (k = 0; k < segment.length; k++) {
25135                 item = segment[k];
25136                 var way = graph.entity(item.id); // If this is a paired item, generate members in correct order and role
25137
25138                 if (tempWay && item.id === tempWay.id) {
25139                   if (nodes[0].id === insertPair.nodes[0]) {
25140                     item.pair = [{
25141                       id: insertPair.originalID,
25142                       type: 'way',
25143                       role: item.role
25144                     }, {
25145                       id: insertPair.insertedID,
25146                       type: 'way',
25147                       role: item.role
25148                     }];
25149                   } else {
25150                     item.pair = [{
25151                       id: insertPair.insertedID,
25152                       type: 'way',
25153                       role: item.role
25154                     }, {
25155                       id: insertPair.originalID,
25156                       type: 'way',
25157                       role: item.role
25158                     }];
25159                   }
25160                 } // reorder `members` if necessary
25161
25162
25163                 if (k > 0) {
25164                   if (j + k >= members.length || item.index !== members[j + k].index) {
25165                     moveMember(members, item.index, j + k);
25166                   }
25167                 }
25168
25169                 nodes.splice(0, way.nodes.length - 1);
25170               }
25171             }
25172
25173             if (tempWay) {
25174               graph = graph.remove(tempWay);
25175             } // Final pass: skip dead items, split pairs, remove index properties
25176
25177
25178             var wayMembers = [];
25179
25180             for (i = 0; i < members.length; i++) {
25181               item = members[i];
25182               if (item.index === -1) continue;
25183
25184               if (item.pair) {
25185                 wayMembers.push(item.pair[0]);
25186                 wayMembers.push(item.pair[1]);
25187               } else {
25188                 wayMembers.push(utilObjectOmit(item, ['index']));
25189               }
25190             } // Put stops and platforms first, then nodes, ways, relations
25191             // This is recommended for Public Transport v2 routes:
25192             // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
25193
25194
25195             var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
25196             return graph.replace(relation.update({
25197               members: newMembers
25198             })); // `moveMember()` changes the `members` array in place by splicing
25199             // the item with `.index = findIndex` to where it belongs,
25200             // and marking the old position as "dead" with `.index = -1`
25201             //
25202             // j=5, k=0                jk
25203             // segment                 5 4 7 6
25204             // members       0 1 2 3 4 5 6 7 8 9        keep 5 in j+k
25205             //
25206             // j=5, k=1                j k
25207             // segment                 5 4 7 6
25208             // members       0 1 2 3 4 5 6 7 8 9        move 4 to j+k
25209             // members       0 1 2 3 x 5 4 6 7 8 9      moved
25210             //
25211             // j=5, k=2                j   k
25212             // segment                 5 4 7 6
25213             // members       0 1 2 3 x 5 4 6 7 8 9      move 7 to j+k
25214             // members       0 1 2 3 x 5 4 7 6 x 8 9    moved
25215             //
25216             // j=5, k=3                j     k
25217             // segment                 5 4 7 6
25218             // members       0 1 2 3 x 5 4 7 6 x 8 9    keep 6 in j+k
25219             //
25220
25221             function moveMember(arr, findIndex, toIndex) {
25222               var i;
25223
25224               for (i = 0; i < arr.length; i++) {
25225                 if (arr[i].index === findIndex) {
25226                   break;
25227                 }
25228               }
25229
25230               var item = Object.assign({}, arr[i]); // shallow copy
25231
25232               arr[i].index = -1; // mark as dead
25233
25234               item.index = toIndex;
25235               arr.splice(toIndex, 0, item);
25236             } // This is the same as `Relation.indexedMembers`,
25237             // Except we don't want to index all the members, only the ways
25238
25239
25240             function withIndex(arr) {
25241               var result = new Array(arr.length);
25242
25243               for (var i = 0; i < arr.length; i++) {
25244                 result[i] = Object.assign({}, arr[i]); // shallow copy
25245
25246                 result[i].index = i;
25247               }
25248
25249               return result;
25250             }
25251           }
25252         }
25253
25254         function actionAddMidpoint(midpoint, node) {
25255           return function (graph) {
25256             graph = graph.replace(node.move(midpoint.loc));
25257             var parents = utilArrayIntersection(graph.parentWays(graph.entity(midpoint.edge[0])), graph.parentWays(graph.entity(midpoint.edge[1])));
25258             parents.forEach(function (way) {
25259               for (var i = 0; i < way.nodes.length - 1; i++) {
25260                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
25261                   graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1)); // Add only one midpoint on doubled-back segments,
25262                   // turning them into self-intersections.
25263
25264                   return;
25265                 }
25266               }
25267             });
25268             return graph;
25269           };
25270         }
25271
25272         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
25273         function actionAddVertex(wayId, nodeId, index) {
25274           return function (graph) {
25275             return graph.replace(graph.entity(wayId).addNode(nodeId, index));
25276           };
25277         }
25278
25279         function actionChangeMember(relationId, member, memberIndex) {
25280           return function (graph) {
25281             return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
25282           };
25283         }
25284
25285         function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
25286           return function action(graph) {
25287             var entity = graph.entity(entityID);
25288             var geometry = entity.geometry(graph);
25289             var tags = entity.tags;
25290             if (oldPreset) tags = oldPreset.unsetTags(tags, geometry);
25291             if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
25292             return graph.replace(entity.update({
25293               tags: tags
25294             }));
25295           };
25296         }
25297
25298         function actionChangeTags(entityId, tags) {
25299           return function (graph) {
25300             var entity = graph.entity(entityId);
25301             return graph.replace(entity.update({
25302               tags: tags
25303             }));
25304           };
25305         }
25306
25307         function osmNode() {
25308           if (!(this instanceof osmNode)) {
25309             return new osmNode().initialize(arguments);
25310           } else if (arguments.length) {
25311             this.initialize(arguments);
25312           }
25313         }
25314         osmEntity.node = osmNode;
25315         osmNode.prototype = Object.create(osmEntity.prototype);
25316         Object.assign(osmNode.prototype, {
25317           type: 'node',
25318           loc: [9999, 9999],
25319           extent: function extent() {
25320             return new geoExtent(this.loc);
25321           },
25322           geometry: function geometry(graph) {
25323             return graph["transient"](this, 'geometry', function () {
25324               return graph.isPoi(this) ? 'point' : 'vertex';
25325             });
25326           },
25327           move: function move(loc) {
25328             return this.update({
25329               loc: loc
25330             });
25331           },
25332           isDegenerate: function isDegenerate() {
25333             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);
25334           },
25335           // Inspect tags and geometry to determine which direction(s) this node/vertex points
25336           directions: function directions(resolver, projection) {
25337             var val;
25338             var i; // which tag to use?
25339
25340             if (this.isHighwayIntersection(resolver) && (this.tags.stop || '').toLowerCase() === 'all') {
25341               // all-way stop tag on a highway intersection
25342               val = 'all';
25343             } else {
25344               // generic direction tag
25345               val = (this.tags.direction || '').toLowerCase(); // better suffix-style direction tag
25346
25347               var re = /:direction$/i;
25348               var keys = Object.keys(this.tags);
25349
25350               for (i = 0; i < keys.length; i++) {
25351                 if (re.test(keys[i])) {
25352                   val = this.tags[keys[i]].toLowerCase();
25353                   break;
25354                 }
25355               }
25356             }
25357
25358             if (val === '') return [];
25359             var cardinal = {
25360               north: 0,
25361               n: 0,
25362               northnortheast: 22,
25363               nne: 22,
25364               northeast: 45,
25365               ne: 45,
25366               eastnortheast: 67,
25367               ene: 67,
25368               east: 90,
25369               e: 90,
25370               eastsoutheast: 112,
25371               ese: 112,
25372               southeast: 135,
25373               se: 135,
25374               southsoutheast: 157,
25375               sse: 157,
25376               south: 180,
25377               s: 180,
25378               southsouthwest: 202,
25379               ssw: 202,
25380               southwest: 225,
25381               sw: 225,
25382               westsouthwest: 247,
25383               wsw: 247,
25384               west: 270,
25385               w: 270,
25386               westnorthwest: 292,
25387               wnw: 292,
25388               northwest: 315,
25389               nw: 315,
25390               northnorthwest: 337,
25391               nnw: 337
25392             };
25393             var values = val.split(';');
25394             var results = [];
25395             values.forEach(function (v) {
25396               // swap cardinal for numeric directions
25397               if (cardinal[v] !== undefined) {
25398                 v = cardinal[v];
25399               } // numeric direction - just add to results
25400
25401
25402               if (v !== '' && !isNaN(+v)) {
25403                 results.push(+v);
25404                 return;
25405               } // string direction - inspect parent ways
25406
25407
25408               var lookBackward = this.tags['traffic_sign:backward'] || v === 'backward' || v === 'both' || v === 'all';
25409               var lookForward = this.tags['traffic_sign:forward'] || v === 'forward' || v === 'both' || v === 'all';
25410               if (!lookForward && !lookBackward) return;
25411               var nodeIds = {};
25412               resolver.parentWays(this).forEach(function (parent) {
25413                 var nodes = parent.nodes;
25414
25415                 for (i = 0; i < nodes.length; i++) {
25416                   if (nodes[i] === this.id) {
25417                     // match current entity
25418                     if (lookForward && i > 0) {
25419                       nodeIds[nodes[i - 1]] = true; // look back to prev node
25420                     }
25421
25422                     if (lookBackward && i < nodes.length - 1) {
25423                       nodeIds[nodes[i + 1]] = true; // look ahead to next node
25424                     }
25425                   }
25426                 }
25427               }, this);
25428               Object.keys(nodeIds).forEach(function (nodeId) {
25429                 // +90 because geoAngle returns angle from X axis, not Y (north)
25430                 results.push(geoAngle(this, resolver.entity(nodeId), projection) * (180 / Math.PI) + 90);
25431               }, this);
25432             }, this);
25433             return utilArrayUniq(results);
25434           },
25435           isEndpoint: function isEndpoint(resolver) {
25436             return resolver["transient"](this, 'isEndpoint', function () {
25437               var id = this.id;
25438               return resolver.parentWays(this).filter(function (parent) {
25439                 return !parent.isClosed() && !!parent.affix(id);
25440               }).length > 0;
25441             });
25442           },
25443           isConnected: function isConnected(resolver) {
25444             return resolver["transient"](this, 'isConnected', function () {
25445               var parents = resolver.parentWays(this);
25446
25447               if (parents.length > 1) {
25448                 // vertex is connected to multiple parent ways
25449                 for (var i in parents) {
25450                   if (parents[i].geometry(resolver) === 'line' && parents[i].hasInterestingTags()) return true;
25451                 }
25452               } else if (parents.length === 1) {
25453                 var way = parents[0];
25454                 var nodes = way.nodes.slice();
25455
25456                 if (way.isClosed()) {
25457                   nodes.pop();
25458                 } // ignore connecting node if closed
25459                 // return true if vertex appears multiple times (way is self intersecting)
25460
25461
25462                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
25463               }
25464
25465               return false;
25466             });
25467           },
25468           parentIntersectionWays: function parentIntersectionWays(resolver) {
25469             return resolver["transient"](this, 'parentIntersectionWays', function () {
25470               return resolver.parentWays(this).filter(function (parent) {
25471                 return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === 'line';
25472               });
25473             });
25474           },
25475           isIntersection: function isIntersection(resolver) {
25476             return this.parentIntersectionWays(resolver).length > 1;
25477           },
25478           isHighwayIntersection: function isHighwayIntersection(resolver) {
25479             return resolver["transient"](this, 'isHighwayIntersection', function () {
25480               return resolver.parentWays(this).filter(function (parent) {
25481                 return parent.tags.highway && parent.geometry(resolver) === 'line';
25482               }).length > 1;
25483             });
25484           },
25485           isOnAddressLine: function isOnAddressLine(resolver) {
25486             return resolver["transient"](this, 'isOnAddressLine', function () {
25487               return resolver.parentWays(this).filter(function (parent) {
25488                 return parent.tags.hasOwnProperty('addr:interpolation') && parent.geometry(resolver) === 'line';
25489               }).length > 0;
25490             });
25491           },
25492           asJXON: function asJXON(changeset_id) {
25493             var r = {
25494               node: {
25495                 '@id': this.osmId(),
25496                 '@lon': this.loc[0],
25497                 '@lat': this.loc[1],
25498                 '@version': this.version || 0,
25499                 tag: Object.keys(this.tags).map(function (k) {
25500                   return {
25501                     keyAttributes: {
25502                       k: k,
25503                       v: this.tags[k]
25504                     }
25505                   };
25506                 }, this)
25507               }
25508             };
25509             if (changeset_id) r.node['@changeset'] = changeset_id;
25510             return r;
25511           },
25512           asGeoJSON: function asGeoJSON() {
25513             return {
25514               type: 'Point',
25515               coordinates: this.loc
25516             };
25517           }
25518         });
25519
25520         function actionCircularize(wayId, projection, maxAngle) {
25521           maxAngle = (maxAngle || 20) * Math.PI / 180;
25522
25523           var action = function action(graph, t) {
25524             if (t === null || !isFinite(t)) t = 1;
25525             t = Math.min(Math.max(+t, 0), 1);
25526             var way = graph.entity(wayId);
25527             var origNodes = {};
25528             graph.childNodes(way).forEach(function (node) {
25529               if (!origNodes[node.id]) origNodes[node.id] = node;
25530             });
25531
25532             if (!way.isConvex(graph)) {
25533               graph = action.makeConvex(graph);
25534             }
25535
25536             var nodes = utilArrayUniq(graph.childNodes(way));
25537             var keyNodes = nodes.filter(function (n) {
25538               return graph.parentWays(n).length !== 1;
25539             });
25540             var points = nodes.map(function (n) {
25541               return projection(n.loc);
25542             });
25543             var keyPoints = keyNodes.map(function (n) {
25544               return projection(n.loc);
25545             });
25546             var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points);
25547             var radius = d3_median(points, function (p) {
25548               return geoVecLength(centroid, p);
25549             });
25550             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
25551             var ids, i, j, k; // we need at least two key nodes for the algorithm to work
25552
25553             if (!keyNodes.length) {
25554               keyNodes = [nodes[0]];
25555               keyPoints = [points[0]];
25556             }
25557
25558             if (keyNodes.length === 1) {
25559               var index = nodes.indexOf(keyNodes[0]);
25560               var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
25561               keyNodes.push(nodes[oppositeIndex]);
25562               keyPoints.push(points[oppositeIndex]);
25563             } // key points and nodes are those connected to the ways,
25564             // they are projected onto the circle, in between nodes are moved
25565             // to constant intervals between key nodes, extra in between nodes are
25566             // added if necessary.
25567
25568
25569             for (i = 0; i < keyPoints.length; i++) {
25570               var nextKeyNodeIndex = (i + 1) % keyNodes.length;
25571               var startNode = keyNodes[i];
25572               var endNode = keyNodes[nextKeyNodeIndex];
25573               var startNodeIndex = nodes.indexOf(startNode);
25574               var endNodeIndex = nodes.indexOf(endNode);
25575               var numberNewPoints = -1;
25576               var indexRange = endNodeIndex - startNodeIndex;
25577               var nearNodes = {};
25578               var inBetweenNodes = [];
25579               var startAngle, endAngle, totalAngle, eachAngle;
25580               var angle, loc, node, origNode;
25581
25582               if (indexRange < 0) {
25583                 indexRange += nodes.length;
25584               } // position this key node
25585
25586
25587               var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4;
25588               keyPoints[i] = [centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
25589               loc = projection.invert(keyPoints[i]);
25590               node = keyNodes[i];
25591               origNode = origNodes[node.id];
25592               node = node.move(geoVecInterp(origNode.loc, loc, t));
25593               graph = graph.replace(node); // figure out the between delta angle we want to match to
25594
25595               startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
25596               endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
25597               totalAngle = endAngle - startAngle; // detects looping around -pi/pi
25598
25599               if (totalAngle * sign > 0) {
25600                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
25601               }
25602
25603               do {
25604                 numberNewPoints++;
25605                 eachAngle = totalAngle / (indexRange + numberNewPoints);
25606               } while (Math.abs(eachAngle) > maxAngle); // move existing nodes
25607
25608
25609               for (j = 1; j < indexRange; j++) {
25610                 angle = startAngle + j * eachAngle;
25611                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]);
25612                 node = nodes[(j + startNodeIndex) % nodes.length];
25613                 origNode = origNodes[node.id];
25614                 nearNodes[node.id] = angle;
25615                 node = node.move(geoVecInterp(origNode.loc, loc, t));
25616                 graph = graph.replace(node);
25617               } // add new in between nodes if necessary
25618
25619
25620               for (j = 0; j < numberNewPoints; j++) {
25621                 angle = startAngle + (indexRange + j) * eachAngle;
25622                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]); // choose a nearnode to use as the original
25623
25624                 var min = Infinity;
25625
25626                 for (var nodeId in nearNodes) {
25627                   var nearAngle = nearNodes[nodeId];
25628                   var dist = Math.abs(nearAngle - angle);
25629
25630                   if (dist < min) {
25631                     min = dist;
25632                     origNode = origNodes[nodeId];
25633                   }
25634                 }
25635
25636                 node = osmNode({
25637                   loc: geoVecInterp(origNode.loc, loc, t)
25638                 });
25639                 graph = graph.replace(node);
25640                 nodes.splice(endNodeIndex + j, 0, node);
25641                 inBetweenNodes.push(node.id);
25642               } // Check for other ways that share these keyNodes..
25643               // If keyNodes are adjacent in both ways,
25644               // we can add inBetweenNodes to that shared way too..
25645
25646
25647               if (indexRange === 1 && inBetweenNodes.length) {
25648                 var startIndex1 = way.nodes.lastIndexOf(startNode.id);
25649                 var endIndex1 = way.nodes.lastIndexOf(endNode.id);
25650                 var wayDirection1 = endIndex1 - startIndex1;
25651
25652                 if (wayDirection1 < -1) {
25653                   wayDirection1 = 1;
25654                 }
25655
25656                 var parentWays = graph.parentWays(keyNodes[i]);
25657
25658                 for (j = 0; j < parentWays.length; j++) {
25659                   var sharedWay = parentWays[j];
25660                   if (sharedWay === way) continue;
25661
25662                   if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
25663                     var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
25664                     var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
25665                     var wayDirection2 = endIndex2 - startIndex2;
25666                     var insertAt = endIndex2;
25667
25668                     if (wayDirection2 < -1) {
25669                       wayDirection2 = 1;
25670                     }
25671
25672                     if (wayDirection1 !== wayDirection2) {
25673                       inBetweenNodes.reverse();
25674                       insertAt = startIndex2;
25675                     }
25676
25677                     for (k = 0; k < inBetweenNodes.length; k++) {
25678                       sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
25679                     }
25680
25681                     graph = graph.replace(sharedWay);
25682                   }
25683                 }
25684               }
25685             } // update the way to have all the new nodes
25686
25687
25688             ids = nodes.map(function (n) {
25689               return n.id;
25690             });
25691             ids.push(ids[0]);
25692             way = way.update({
25693               nodes: ids
25694             });
25695             graph = graph.replace(way);
25696             return graph;
25697           };
25698
25699           action.makeConvex = function (graph) {
25700             var way = graph.entity(wayId);
25701             var nodes = utilArrayUniq(graph.childNodes(way));
25702             var points = nodes.map(function (n) {
25703               return projection(n.loc);
25704             });
25705             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
25706             var hull = d3_polygonHull(points);
25707             var i, j; // D3 convex hulls go counterclockwise..
25708
25709             if (sign === -1) {
25710               nodes.reverse();
25711               points.reverse();
25712             }
25713
25714             for (i = 0; i < hull.length - 1; i++) {
25715               var startIndex = points.indexOf(hull[i]);
25716               var endIndex = points.indexOf(hull[i + 1]);
25717               var indexRange = endIndex - startIndex;
25718
25719               if (indexRange < 0) {
25720                 indexRange += nodes.length;
25721               } // move interior nodes to the surface of the convex hull..
25722
25723
25724               for (j = 1; j < indexRange; j++) {
25725                 var point = geoVecInterp(hull[i], hull[i + 1], j / indexRange);
25726                 var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
25727                 graph = graph.replace(node);
25728               }
25729             }
25730
25731             return graph;
25732           };
25733
25734           action.disabled = function (graph) {
25735             if (!graph.entity(wayId).isClosed()) {
25736               return 'not_closed';
25737             } //disable when already circular
25738
25739
25740             var way = graph.entity(wayId);
25741             var nodes = utilArrayUniq(graph.childNodes(way));
25742             var points = nodes.map(function (n) {
25743               return projection(n.loc);
25744             });
25745             var hull = d3_polygonHull(points);
25746             var epsilonAngle = Math.PI / 180;
25747
25748             if (hull.length !== points.length || hull.length < 3) {
25749               return false;
25750             }
25751
25752             var centroid = d3_polygonCentroid(points);
25753             var radius = geoVecLengthSquare(centroid, points[0]);
25754             var i, actualPoint; // compare distances between centroid and points
25755
25756             for (i = 0; i < hull.length; i++) {
25757               actualPoint = hull[i];
25758               var actualDist = geoVecLengthSquare(actualPoint, centroid);
25759               var diff = Math.abs(actualDist - radius); //compare distances with epsilon-error (5%)
25760
25761               if (diff > 0.05 * radius) {
25762                 return false;
25763               }
25764             } //check if central angles are smaller than maxAngle
25765
25766
25767             for (i = 0; i < hull.length; i++) {
25768               actualPoint = hull[i];
25769               var nextPoint = hull[(i + 1) % hull.length];
25770               var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
25771               var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
25772               var angle = endAngle - startAngle;
25773
25774               if (angle < 0) {
25775                 angle = -angle;
25776               }
25777
25778               if (angle > Math.PI) {
25779                 angle = 2 * Math.PI - angle;
25780               }
25781
25782               if (angle > maxAngle + epsilonAngle) {
25783                 return false;
25784               }
25785             }
25786
25787             return 'already_circular';
25788           };
25789
25790           action.transitionable = true;
25791           return action;
25792         }
25793
25794         function actionDeleteWay(wayID) {
25795           function canDeleteNode(node, graph) {
25796             // don't delete nodes still attached to ways or relations
25797             if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
25798             var geometries = osmNodeGeometriesForTags(node.tags); // don't delete if this node can be a standalone point
25799
25800             if (geometries.point) return false; // delete if this node only be a vertex
25801
25802             if (geometries.vertex) return true; // iD doesn't know if this should be a point or vertex,
25803             // so only delete if there are no interesting tags
25804
25805             return !node.hasInterestingTags();
25806           }
25807
25808           var action = function action(graph) {
25809             var way = graph.entity(wayID);
25810             graph.parentRelations(way).forEach(function (parent) {
25811               parent = parent.removeMembersWithID(wayID);
25812               graph = graph.replace(parent);
25813
25814               if (parent.isDegenerate()) {
25815                 graph = actionDeleteRelation(parent.id)(graph);
25816               }
25817             });
25818             new Set(way.nodes).forEach(function (nodeID) {
25819               graph = graph.replace(way.removeNode(nodeID));
25820               var node = graph.entity(nodeID);
25821
25822               if (canDeleteNode(node, graph)) {
25823                 graph = graph.remove(node);
25824               }
25825             });
25826             return graph.remove(way);
25827           };
25828
25829           return action;
25830         }
25831
25832         function actionDeleteMultiple(ids) {
25833           var actions = {
25834             way: actionDeleteWay,
25835             node: actionDeleteNode,
25836             relation: actionDeleteRelation
25837           };
25838
25839           var action = function action(graph) {
25840             ids.forEach(function (id) {
25841               if (graph.hasEntity(id)) {
25842                 // It may have been deleted already.
25843                 graph = actions[graph.entity(id).type](id)(graph);
25844               }
25845             });
25846             return graph;
25847           };
25848
25849           return action;
25850         }
25851
25852         function actionDeleteRelation(relationID, allowUntaggedMembers) {
25853           function canDeleteEntity(entity, graph) {
25854             return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && !entity.hasInterestingTags() && !allowUntaggedMembers;
25855           }
25856
25857           var action = function action(graph) {
25858             var relation = graph.entity(relationID);
25859             graph.parentRelations(relation).forEach(function (parent) {
25860               parent = parent.removeMembersWithID(relationID);
25861               graph = graph.replace(parent);
25862
25863               if (parent.isDegenerate()) {
25864                 graph = actionDeleteRelation(parent.id)(graph);
25865               }
25866             });
25867             var memberIDs = utilArrayUniq(relation.members.map(function (m) {
25868               return m.id;
25869             }));
25870             memberIDs.forEach(function (memberID) {
25871               graph = graph.replace(relation.removeMembersWithID(memberID));
25872               var entity = graph.entity(memberID);
25873
25874               if (canDeleteEntity(entity, graph)) {
25875                 graph = actionDeleteMultiple([memberID])(graph);
25876               }
25877             });
25878             return graph.remove(relation);
25879           };
25880
25881           return action;
25882         }
25883
25884         function actionDeleteNode(nodeId) {
25885           var action = function action(graph) {
25886             var node = graph.entity(nodeId);
25887             graph.parentWays(node).forEach(function (parent) {
25888               parent = parent.removeNode(nodeId);
25889               graph = graph.replace(parent);
25890
25891               if (parent.isDegenerate()) {
25892                 graph = actionDeleteWay(parent.id)(graph);
25893               }
25894             });
25895             graph.parentRelations(node).forEach(function (parent) {
25896               parent = parent.removeMembersWithID(nodeId);
25897               graph = graph.replace(parent);
25898
25899               if (parent.isDegenerate()) {
25900                 graph = actionDeleteRelation(parent.id)(graph);
25901               }
25902             });
25903             return graph.remove(node);
25904           };
25905
25906           return action;
25907         }
25908
25909         //
25910         // First choose a node to be the survivor, with preference given
25911         // to an existing (not new) node.
25912         //
25913         // Tags and relation memberships of of non-surviving nodes are merged
25914         // to the survivor.
25915         //
25916         // This is the inverse of `iD.actionDisconnect`.
25917         //
25918         // Reference:
25919         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
25920         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
25921         //
25922
25923         function actionConnect(nodeIDs) {
25924           var action = function action(graph) {
25925             var survivor;
25926             var node;
25927             var parents;
25928             var i, j; // Choose a survivor node, prefer an existing (not new) node - #4974
25929
25930             for (i = 0; i < nodeIDs.length; i++) {
25931               survivor = graph.entity(nodeIDs[i]);
25932               if (survivor.version) break; // found one
25933             } // Replace all non-surviving nodes with the survivor and merge tags.
25934
25935
25936             for (i = 0; i < nodeIDs.length; i++) {
25937               node = graph.entity(nodeIDs[i]);
25938               if (node.id === survivor.id) continue;
25939               parents = graph.parentWays(node);
25940
25941               for (j = 0; j < parents.length; j++) {
25942                 graph = graph.replace(parents[j].replaceNode(node.id, survivor.id));
25943               }
25944
25945               parents = graph.parentRelations(node);
25946
25947               for (j = 0; j < parents.length; j++) {
25948                 graph = graph.replace(parents[j].replaceMember(node, survivor));
25949               }
25950
25951               survivor = survivor.mergeTags(node.tags);
25952               graph = actionDeleteNode(node.id)(graph);
25953             }
25954
25955             graph = graph.replace(survivor); // find and delete any degenerate ways created by connecting adjacent vertices
25956
25957             parents = graph.parentWays(survivor);
25958
25959             for (i = 0; i < parents.length; i++) {
25960               if (parents[i].isDegenerate()) {
25961                 graph = actionDeleteWay(parents[i].id)(graph);
25962               }
25963             }
25964
25965             return graph;
25966           };
25967
25968           action.disabled = function (graph) {
25969             var seen = {};
25970             var restrictionIDs = [];
25971             var survivor;
25972             var node, way;
25973             var relations, relation, role;
25974             var i, j, k; // Choose a survivor node, prefer an existing (not new) node - #4974
25975
25976             for (i = 0; i < nodeIDs.length; i++) {
25977               survivor = graph.entity(nodeIDs[i]);
25978               if (survivor.version) break; // found one
25979             } // 1. disable if the nodes being connected have conflicting relation roles
25980
25981
25982             for (i = 0; i < nodeIDs.length; i++) {
25983               node = graph.entity(nodeIDs[i]);
25984               relations = graph.parentRelations(node);
25985
25986               for (j = 0; j < relations.length; j++) {
25987                 relation = relations[j];
25988                 role = relation.memberById(node.id).role || ''; // if this node is a via node in a restriction, remember for later
25989
25990                 if (relation.hasFromViaTo()) {
25991                   restrictionIDs.push(relation.id);
25992                 }
25993
25994                 if (seen[relation.id] !== undefined && seen[relation.id] !== role) {
25995                   return 'relation';
25996                 } else {
25997                   seen[relation.id] = role;
25998                 }
25999               }
26000             } // gather restrictions for parent ways
26001
26002
26003             for (i = 0; i < nodeIDs.length; i++) {
26004               node = graph.entity(nodeIDs[i]);
26005               var parents = graph.parentWays(node);
26006
26007               for (j = 0; j < parents.length; j++) {
26008                 var parent = parents[j];
26009                 relations = graph.parentRelations(parent);
26010
26011                 for (k = 0; k < relations.length; k++) {
26012                   relation = relations[k];
26013
26014                   if (relation.hasFromViaTo()) {
26015                     restrictionIDs.push(relation.id);
26016                   }
26017                 }
26018               }
26019             } // test restrictions
26020
26021
26022             restrictionIDs = utilArrayUniq(restrictionIDs);
26023
26024             for (i = 0; i < restrictionIDs.length; i++) {
26025               relation = graph.entity(restrictionIDs[i]);
26026               if (!relation.isComplete(graph)) continue;
26027               var memberWays = relation.members.filter(function (m) {
26028                 return m.type === 'way';
26029               }).map(function (m) {
26030                 return graph.entity(m.id);
26031               });
26032               memberWays = utilArrayUniq(memberWays);
26033               var f = relation.memberByRole('from');
26034               var t = relation.memberByRole('to');
26035               var isUturn = f.id === t.id; // 2a. disable if connection would damage a restriction
26036               // (a key node is a node at the junction of ways)
26037
26038               var nodes = {
26039                 from: [],
26040                 via: [],
26041                 to: [],
26042                 keyfrom: [],
26043                 keyto: []
26044               };
26045
26046               for (j = 0; j < relation.members.length; j++) {
26047                 collectNodes(relation.members[j], nodes);
26048               }
26049
26050               nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
26051               nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
26052               var filter = keyNodeFilter(nodes.keyfrom, nodes.keyto);
26053               nodes.from = nodes.from.filter(filter);
26054               nodes.via = nodes.via.filter(filter);
26055               nodes.to = nodes.to.filter(filter);
26056               var connectFrom = false;
26057               var connectVia = false;
26058               var connectTo = false;
26059               var connectKeyFrom = false;
26060               var connectKeyTo = false;
26061
26062               for (j = 0; j < nodeIDs.length; j++) {
26063                 var n = nodeIDs[j];
26064
26065                 if (nodes.from.indexOf(n) !== -1) {
26066                   connectFrom = true;
26067                 }
26068
26069                 if (nodes.via.indexOf(n) !== -1) {
26070                   connectVia = true;
26071                 }
26072
26073                 if (nodes.to.indexOf(n) !== -1) {
26074                   connectTo = true;
26075                 }
26076
26077                 if (nodes.keyfrom.indexOf(n) !== -1) {
26078                   connectKeyFrom = true;
26079                 }
26080
26081                 if (nodes.keyto.indexOf(n) !== -1) {
26082                   connectKeyTo = true;
26083                 }
26084               }
26085
26086               if (connectFrom && connectTo && !isUturn) {
26087                 return 'restriction';
26088               }
26089
26090               if (connectFrom && connectVia) {
26091                 return 'restriction';
26092               }
26093
26094               if (connectTo && connectVia) {
26095                 return 'restriction';
26096               } // connecting to a key node -
26097               // if both nodes are on a member way (i.e. part of the turn restriction),
26098               // the connecting node must be adjacent to the key node.
26099
26100
26101               if (connectKeyFrom || connectKeyTo) {
26102                 if (nodeIDs.length !== 2) {
26103                   return 'restriction';
26104                 }
26105
26106                 var n0 = null;
26107                 var n1 = null;
26108
26109                 for (j = 0; j < memberWays.length; j++) {
26110                   way = memberWays[j];
26111
26112                   if (way.contains(nodeIDs[0])) {
26113                     n0 = nodeIDs[0];
26114                   }
26115
26116                   if (way.contains(nodeIDs[1])) {
26117                     n1 = nodeIDs[1];
26118                   }
26119                 }
26120
26121                 if (n0 && n1) {
26122                   // both nodes are part of the restriction
26123                   var ok = false;
26124
26125                   for (j = 0; j < memberWays.length; j++) {
26126                     way = memberWays[j];
26127
26128                     if (way.areAdjacent(n0, n1)) {
26129                       ok = true;
26130                       break;
26131                     }
26132                   }
26133
26134                   if (!ok) {
26135                     return 'restriction';
26136                   }
26137                 }
26138               } // 2b. disable if nodes being connected will destroy a member way in a restriction
26139               // (to test, make a copy and try actually connecting the nodes)
26140
26141
26142               for (j = 0; j < memberWays.length; j++) {
26143                 way = memberWays[j].update({}); // make copy
26144
26145                 for (k = 0; k < nodeIDs.length; k++) {
26146                   if (nodeIDs[k] === survivor.id) continue;
26147
26148                   if (way.areAdjacent(nodeIDs[k], survivor.id)) {
26149                     way = way.removeNode(nodeIDs[k]);
26150                   } else {
26151                     way = way.replaceNode(nodeIDs[k], survivor.id);
26152                   }
26153                 }
26154
26155                 if (way.isDegenerate()) {
26156                   return 'restriction';
26157                 }
26158               }
26159             }
26160
26161             return false; // if a key node appears multiple times (indexOf !== lastIndexOf) it's a FROM-VIA or TO-VIA junction
26162
26163             function hasDuplicates(n, i, arr) {
26164               return arr.indexOf(n) !== arr.lastIndexOf(n);
26165             }
26166
26167             function keyNodeFilter(froms, tos) {
26168               return function (n) {
26169                 return froms.indexOf(n) === -1 && tos.indexOf(n) === -1;
26170               };
26171             }
26172
26173             function collectNodes(member, collection) {
26174               var entity = graph.hasEntity(member.id);
26175               if (!entity) return;
26176               var role = member.role || '';
26177
26178               if (!collection[role]) {
26179                 collection[role] = [];
26180               }
26181
26182               if (member.type === 'node') {
26183                 collection[role].push(member.id);
26184
26185                 if (role === 'via') {
26186                   collection.keyfrom.push(member.id);
26187                   collection.keyto.push(member.id);
26188                 }
26189               } else if (member.type === 'way') {
26190                 collection[role].push.apply(collection[role], entity.nodes);
26191
26192                 if (role === 'from' || role === 'via') {
26193                   collection.keyfrom.push(entity.first());
26194                   collection.keyfrom.push(entity.last());
26195                 }
26196
26197                 if (role === 'to' || role === 'via') {
26198                   collection.keyto.push(entity.first());
26199                   collection.keyto.push(entity.last());
26200                 }
26201               }
26202             }
26203           };
26204
26205           return action;
26206         }
26207
26208         function actionCopyEntities(ids, fromGraph) {
26209           var _copies = {};
26210
26211           var action = function action(graph) {
26212             ids.forEach(function (id) {
26213               fromGraph.entity(id).copy(fromGraph, _copies);
26214             });
26215
26216             for (var id in _copies) {
26217               graph = graph.replace(_copies[id]);
26218             }
26219
26220             return graph;
26221           };
26222
26223           action.copies = function () {
26224             return _copies;
26225           };
26226
26227           return action;
26228         }
26229
26230         function actionDeleteMember(relationId, memberIndex) {
26231           return function (graph) {
26232             var relation = graph.entity(relationId).removeMember(memberIndex);
26233             graph = graph.replace(relation);
26234             if (relation.isDegenerate()) graph = actionDeleteRelation(relation.id)(graph);
26235             return graph;
26236           };
26237         }
26238
26239         function actionDiscardTags(difference, discardTags) {
26240           discardTags = discardTags || {};
26241           return function (graph) {
26242             difference.modified().forEach(checkTags);
26243             difference.created().forEach(checkTags);
26244             return graph;
26245
26246             function checkTags(entity) {
26247               var keys = Object.keys(entity.tags);
26248               var didDiscard = false;
26249               var tags = {};
26250
26251               for (var i = 0; i < keys.length; i++) {
26252                 var k = keys[i];
26253
26254                 if (discardTags[k] || !entity.tags[k]) {
26255                   didDiscard = true;
26256                 } else {
26257                   tags[k] = entity.tags[k];
26258                 }
26259               }
26260
26261               if (didDiscard) {
26262                 graph = graph.replace(entity.update({
26263                   tags: tags
26264                 }));
26265               }
26266             }
26267           };
26268         }
26269
26270         //
26271         // Optionally, disconnect only the given ways.
26272         //
26273         // For testing convenience, accepts an ID to assign to the (first) new node.
26274         // Normally, this will be undefined and the way will automatically
26275         // be assigned a new ID.
26276         //
26277         // This is the inverse of `iD.actionConnect`.
26278         //
26279         // Reference:
26280         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
26281         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
26282         //
26283
26284         function actionDisconnect(nodeId, newNodeId) {
26285           var wayIds;
26286
26287           var action = function action(graph) {
26288             var node = graph.entity(nodeId);
26289             var connections = action.connections(graph);
26290             connections.forEach(function (connection) {
26291               var way = graph.entity(connection.wayID);
26292               var newNode = osmNode({
26293                 id: newNodeId,
26294                 loc: node.loc,
26295                 tags: node.tags
26296               });
26297               graph = graph.replace(newNode);
26298
26299               if (connection.index === 0 && way.isArea()) {
26300                 // replace shared node with shared node..
26301                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
26302               } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
26303                 // replace closing node with new new node..
26304                 graph = graph.replace(way.unclose().addNode(newNode.id));
26305               } else {
26306                 // replace shared node with multiple new nodes..
26307                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
26308               }
26309             });
26310             return graph;
26311           };
26312
26313           action.connections = function (graph) {
26314             var candidates = [];
26315             var keeping = false;
26316             var parentWays = graph.parentWays(graph.entity(nodeId));
26317             var way, waynode;
26318
26319             for (var i = 0; i < parentWays.length; i++) {
26320               way = parentWays[i];
26321
26322               if (wayIds && wayIds.indexOf(way.id) === -1) {
26323                 keeping = true;
26324                 continue;
26325               }
26326
26327               if (way.isArea() && way.nodes[0] === nodeId) {
26328                 candidates.push({
26329                   wayID: way.id,
26330                   index: 0
26331                 });
26332               } else {
26333                 for (var j = 0; j < way.nodes.length; j++) {
26334                   waynode = way.nodes[j];
26335
26336                   if (waynode === nodeId) {
26337                     if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j === way.nodes.length - 1) {
26338                       continue;
26339                     }
26340
26341                     candidates.push({
26342                       wayID: way.id,
26343                       index: j
26344                     });
26345                   }
26346                 }
26347               }
26348             }
26349
26350             return keeping ? candidates : candidates.slice(1);
26351           };
26352
26353           action.disabled = function (graph) {
26354             var connections = action.connections(graph);
26355             if (connections.length === 0) return 'not_connected';
26356             var parentWays = graph.parentWays(graph.entity(nodeId));
26357             var seenRelationIds = {};
26358             var sharedRelation;
26359             parentWays.forEach(function (way) {
26360               var relations = graph.parentRelations(way);
26361               relations.forEach(function (relation) {
26362                 if (relation.id in seenRelationIds) {
26363                   if (wayIds) {
26364                     if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
26365                       sharedRelation = relation;
26366                     }
26367                   } else {
26368                     sharedRelation = relation;
26369                   }
26370                 } else {
26371                   seenRelationIds[relation.id] = way.id;
26372                 }
26373               });
26374             });
26375             if (sharedRelation) return 'relation';
26376           };
26377
26378           action.limitWays = function (val) {
26379             if (!arguments.length) return wayIds;
26380             wayIds = val;
26381             return action;
26382           };
26383
26384           return action;
26385         }
26386
26387         var geojsonRewind = rewind;
26388
26389         function rewind(gj, outer) {
26390           var type = gj && gj.type,
26391               i;
26392
26393           if (type === 'FeatureCollection') {
26394             for (i = 0; i < gj.features.length; i++) {
26395               rewind(gj.features[i], outer);
26396             }
26397           } else if (type === 'GeometryCollection') {
26398             for (i = 0; i < gj.geometries.length; i++) {
26399               rewind(gj.geometries[i], outer);
26400             }
26401           } else if (type === 'Feature') {
26402             rewind(gj.geometry, outer);
26403           } else if (type === 'Polygon') {
26404             rewindRings(gj.coordinates, outer);
26405           } else if (type === 'MultiPolygon') {
26406             for (i = 0; i < gj.coordinates.length; i++) {
26407               rewindRings(gj.coordinates[i], outer);
26408             }
26409           }
26410
26411           return gj;
26412         }
26413
26414         function rewindRings(rings, outer) {
26415           if (rings.length === 0) return;
26416           rewindRing(rings[0], outer);
26417
26418           for (var i = 1; i < rings.length; i++) {
26419             rewindRing(rings[i], !outer);
26420           }
26421         }
26422
26423         function rewindRing(ring, dir) {
26424           var area = 0;
26425
26426           for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
26427             area += (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
26428           }
26429
26430           if (area >= 0 !== !!dir) ring.reverse();
26431         }
26432
26433         function actionExtract(entityID) {
26434           var extractedNodeID;
26435
26436           var action = function action(graph) {
26437             var entity = graph.entity(entityID);
26438
26439             if (entity.type === 'node') {
26440               return extractFromNode(entity, graph);
26441             }
26442
26443             return extractFromWayOrRelation(entity, graph);
26444           };
26445
26446           function extractFromNode(node, graph) {
26447             extractedNodeID = node.id; // Create a new node to replace the one we will detach
26448
26449             var replacement = osmNode({
26450               loc: node.loc
26451             });
26452             graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
26453
26454             graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
26455               return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
26456             }, graph); // Process any relations too
26457
26458             return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
26459               return accGraph.replace(parentRel.replaceMember(node, replacement));
26460             }, graph);
26461           }
26462
26463           function extractFromWayOrRelation(entity, graph) {
26464             var fromGeometry = entity.geometry(graph);
26465             var keysToCopyAndRetain = ['source', 'wheelchair'];
26466             var keysToRetain = ['area'];
26467             var buildingKeysToRetain = ['architect', 'building', 'height', 'layer']; // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
26468
26469             var extractedLoc = d3_geoCentroid(geojsonRewind(Object.assign({}, entity.asGeoJSON(graph)), true));
26470
26471             if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
26472               extractedLoc = entity.extent(graph).center();
26473             }
26474
26475             var indoorAreaValues = {
26476               area: true,
26477               corridor: true,
26478               elevator: true,
26479               level: true,
26480               room: true
26481             };
26482             var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
26483             var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
26484             var entityTags = Object.assign({}, entity.tags); // shallow copy
26485
26486             var pointTags = {};
26487
26488             for (var key in entityTags) {
26489               if (entity.type === 'relation' && key === 'type') {
26490                 continue;
26491               }
26492
26493               if (keysToRetain.indexOf(key) !== -1) {
26494                 continue;
26495               }
26496
26497               if (isBuilding) {
26498                 // don't transfer building-related tags
26499                 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
26500               } // leave `indoor` tag on the area
26501
26502
26503               if (isIndoorArea && key === 'indoor') {
26504                 continue;
26505               } // copy the tag from the entity to the point
26506
26507
26508               pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
26509
26510               if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
26511                 continue;
26512               } else if (isIndoorArea && key === 'level') {
26513                 // leave `level` on both features
26514                 continue;
26515               } // remove the tag from the entity
26516
26517
26518               delete entityTags[key];
26519             }
26520
26521             if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
26522               // ensure that areas keep area geometry
26523               entityTags.area = 'yes';
26524             }
26525
26526             var replacement = osmNode({
26527               loc: extractedLoc,
26528               tags: pointTags
26529             });
26530             graph = graph.replace(replacement);
26531             extractedNodeID = replacement.id;
26532             return graph.replace(entity.update({
26533               tags: entityTags
26534             }));
26535           }
26536
26537           action.getExtractedNodeID = function () {
26538             return extractedNodeID;
26539           };
26540
26541           return action;
26542         }
26543
26544         //
26545         // This is the inverse of `iD.actionSplit`.
26546         //
26547         // Reference:
26548         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
26549         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
26550         //
26551
26552         function actionJoin(ids) {
26553           function groupEntitiesByGeometry(graph) {
26554             var entities = ids.map(function (id) {
26555               return graph.entity(id);
26556             });
26557             return Object.assign({
26558               line: []
26559             }, utilArrayGroupBy(entities, function (entity) {
26560               return entity.geometry(graph);
26561             }));
26562           }
26563
26564           var action = function action(graph) {
26565             var ways = ids.map(graph.entity, graph);
26566             var survivorID = ways[0].id; // if any of the ways are sided (e.g. coastline, cliff, kerb)
26567             // sort them first so they establish the overall order - #6033
26568
26569             ways.sort(function (a, b) {
26570               var aSided = a.isSided();
26571               var bSided = b.isSided();
26572               return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
26573             }); // Prefer to keep an existing way.
26574
26575             for (var i = 0; i < ways.length; i++) {
26576               if (!ways[i].isNew()) {
26577                 survivorID = ways[i].id;
26578                 break;
26579               }
26580             }
26581
26582             var sequences = osmJoinWays(ways, graph);
26583             var joined = sequences[0]; // We might need to reverse some of these ways before joining them.  #4688
26584             // `joined.actions` property will contain any actions we need to apply.
26585
26586             graph = sequences.actions.reduce(function (g, action) {
26587               return action(g);
26588             }, graph);
26589             var survivor = graph.entity(survivorID);
26590             survivor = survivor.update({
26591               nodes: joined.nodes.map(function (n) {
26592                 return n.id;
26593               })
26594             });
26595             graph = graph.replace(survivor);
26596             joined.forEach(function (way) {
26597               if (way.id === survivorID) return;
26598               graph.parentRelations(way).forEach(function (parent) {
26599                 graph = graph.replace(parent.replaceMember(way, survivor));
26600               });
26601               survivor = survivor.mergeTags(way.tags);
26602               graph = graph.replace(survivor);
26603               graph = actionDeleteWay(way.id)(graph);
26604             }); // Finds if the join created a single-member multipolygon,
26605             // and if so turns it into a basic area instead
26606
26607             function checkForSimpleMultipolygon() {
26608               if (!survivor.isClosed()) return;
26609               var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
26610                 // find multipolygons where the survivor is the only member
26611                 return multipolygon.members.length === 1;
26612               }); // skip if this is the single member of multiple multipolygons
26613
26614               if (multipolygons.length !== 1) return;
26615               var multipolygon = multipolygons[0];
26616
26617               for (var key in survivor.tags) {
26618                 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
26619                 multipolygon.tags[key] !== survivor.tags[key]) return;
26620               }
26621
26622               survivor = survivor.mergeTags(multipolygon.tags);
26623               graph = graph.replace(survivor);
26624               graph = actionDeleteRelation(multipolygon.id, true
26625               /* allow untagged members */
26626               )(graph);
26627               var tags = Object.assign({}, survivor.tags);
26628
26629               if (survivor.geometry(graph) !== 'area') {
26630                 // ensure the feature persists as an area
26631                 tags.area = 'yes';
26632               }
26633
26634               delete tags.type; // remove type=multipolygon
26635
26636               survivor = survivor.update({
26637                 tags: tags
26638               });
26639               graph = graph.replace(survivor);
26640             }
26641
26642             checkForSimpleMultipolygon();
26643             return graph;
26644           }; // Returns the number of nodes the resultant way is expected to have
26645
26646
26647           action.resultingWayNodesLength = function (graph) {
26648             return ids.reduce(function (count, id) {
26649               return count + graph.entity(id).nodes.length;
26650             }, 0) - ids.length - 1;
26651           };
26652
26653           action.disabled = function (graph) {
26654             var geometries = groupEntitiesByGeometry(graph);
26655
26656             if (ids.length < 2 || ids.length !== geometries.line.length) {
26657               return 'not_eligible';
26658             }
26659
26660             var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
26661
26662             if (joined.length > 1) {
26663               return 'not_adjacent';
26664             } // Loop through all combinations of path-pairs
26665             // to check potential intersections between all pairs
26666
26667
26668             for (var i = 0; i < ids.length - 1; i++) {
26669               for (var j = i + 1; j < ids.length; j++) {
26670                 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
26671                   return e.loc;
26672                 });
26673                 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
26674                   return e.loc;
26675                 });
26676                 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
26677                 // each other/the line, as opposed to crossing it
26678
26679                 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
26680                   return n.loc.toString();
26681                 }), intersections.map(function (n) {
26682                   return n.toString();
26683                 }));
26684
26685                 if (common.length !== intersections.length) {
26686                   return 'paths_intersect';
26687                 }
26688               }
26689             }
26690
26691             var nodeIds = joined[0].nodes.map(function (n) {
26692               return n.id;
26693             }).slice(1, -1);
26694             var relation;
26695             var tags = {};
26696             var conflicting = false;
26697             joined[0].forEach(function (way) {
26698               var parents = graph.parentRelations(way);
26699               parents.forEach(function (parent) {
26700                 if (parent.isRestriction() && parent.members.some(function (m) {
26701                   return nodeIds.indexOf(m.id) >= 0;
26702                 })) {
26703                   relation = parent;
26704                 }
26705               });
26706
26707               for (var k in way.tags) {
26708                 if (!(k in tags)) {
26709                   tags[k] = way.tags[k];
26710                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
26711                   conflicting = true;
26712                 }
26713               }
26714             });
26715
26716             if (relation) {
26717               return 'restriction';
26718             }
26719
26720             if (conflicting) {
26721               return 'conflicting_tags';
26722             }
26723           };
26724
26725           return action;
26726         }
26727
26728         function actionMerge(ids) {
26729           function groupEntitiesByGeometry(graph) {
26730             var entities = ids.map(function (id) {
26731               return graph.entity(id);
26732             });
26733             return Object.assign({
26734               point: [],
26735               area: [],
26736               line: [],
26737               relation: []
26738             }, utilArrayGroupBy(entities, function (entity) {
26739               return entity.geometry(graph);
26740             }));
26741           }
26742
26743           var action = function action(graph) {
26744             var geometries = groupEntitiesByGeometry(graph);
26745             var target = geometries.area[0] || geometries.line[0];
26746             var points = geometries.point;
26747             points.forEach(function (point) {
26748               target = target.mergeTags(point.tags);
26749               graph = graph.replace(target);
26750               graph.parentRelations(point).forEach(function (parent) {
26751                 graph = graph.replace(parent.replaceMember(point, target));
26752               });
26753               var nodes = utilArrayUniq(graph.childNodes(target));
26754               var removeNode = point;
26755
26756               for (var i = 0; i < nodes.length; i++) {
26757                 var node = nodes[i];
26758
26759                 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
26760                   continue;
26761                 } // Found an uninteresting child node on the target way.
26762                 // Move orig point into its place to preserve point's history. #3683
26763
26764
26765                 graph = graph.replace(point.update({
26766                   tags: {},
26767                   loc: node.loc
26768                 }));
26769                 target = target.replaceNode(node.id, point.id);
26770                 graph = graph.replace(target);
26771                 removeNode = node;
26772                 break;
26773               }
26774
26775               graph = graph.remove(removeNode);
26776             });
26777
26778             if (target.tags.area === 'yes') {
26779               var tags = Object.assign({}, target.tags); // shallow copy
26780
26781               delete tags.area;
26782
26783               if (osmTagSuggestingArea(tags)) {
26784                 // remove the `area` tag if area geometry is now implied - #3851
26785                 target = target.update({
26786                   tags: tags
26787                 });
26788                 graph = graph.replace(target);
26789               }
26790             }
26791
26792             return graph;
26793           };
26794
26795           action.disabled = function (graph) {
26796             var geometries = groupEntitiesByGeometry(graph);
26797
26798             if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
26799               return 'not_eligible';
26800             }
26801           };
26802
26803           return action;
26804         }
26805
26806         //
26807         // 1. move all the nodes to a common location
26808         // 2. `actionConnect` them
26809
26810         function actionMergeNodes(nodeIDs, loc) {
26811           // If there is a single "interesting" node, use that as the location.
26812           // Otherwise return the average location of all the nodes.
26813           function chooseLoc(graph) {
26814             if (!nodeIDs.length) return null;
26815             var sum = [0, 0];
26816             var interestingCount = 0;
26817             var interestingLoc;
26818
26819             for (var i = 0; i < nodeIDs.length; i++) {
26820               var node = graph.entity(nodeIDs[i]);
26821
26822               if (node.hasInterestingTags()) {
26823                 interestingLoc = ++interestingCount === 1 ? node.loc : null;
26824               }
26825
26826               sum = geoVecAdd(sum, node.loc);
26827             }
26828
26829             return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
26830           }
26831
26832           var action = function action(graph) {
26833             if (nodeIDs.length < 2) return graph;
26834             var toLoc = loc;
26835
26836             if (!toLoc) {
26837               toLoc = chooseLoc(graph);
26838             }
26839
26840             for (var i = 0; i < nodeIDs.length; i++) {
26841               var node = graph.entity(nodeIDs[i]);
26842
26843               if (node.loc !== toLoc) {
26844                 graph = graph.replace(node.move(toLoc));
26845               }
26846             }
26847
26848             return actionConnect(nodeIDs)(graph);
26849           };
26850
26851           action.disabled = function (graph) {
26852             if (nodeIDs.length < 2) return 'not_eligible';
26853
26854             for (var i = 0; i < nodeIDs.length; i++) {
26855               var entity = graph.entity(nodeIDs[i]);
26856               if (entity.type !== 'node') return 'not_eligible';
26857             }
26858
26859             return actionConnect(nodeIDs).disabled(graph);
26860           };
26861
26862           return action;
26863         }
26864
26865         function osmChangeset() {
26866           if (!(this instanceof osmChangeset)) {
26867             return new osmChangeset().initialize(arguments);
26868           } else if (arguments.length) {
26869             this.initialize(arguments);
26870           }
26871         }
26872         osmEntity.changeset = osmChangeset;
26873         osmChangeset.prototype = Object.create(osmEntity.prototype);
26874         Object.assign(osmChangeset.prototype, {
26875           type: 'changeset',
26876           extent: function extent() {
26877             return new geoExtent();
26878           },
26879           geometry: function geometry() {
26880             return 'changeset';
26881           },
26882           asJXON: function asJXON() {
26883             return {
26884               osm: {
26885                 changeset: {
26886                   tag: Object.keys(this.tags).map(function (k) {
26887                     return {
26888                       '@k': k,
26889                       '@v': this.tags[k]
26890                     };
26891                   }, this),
26892                   '@version': 0.6,
26893                   '@generator': 'iD'
26894                 }
26895               }
26896             };
26897           },
26898           // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26899           // XML. Returns a string.
26900           osmChangeJXON: function osmChangeJXON(changes) {
26901             var changeset_id = this.id;
26902
26903             function nest(x, order) {
26904               var groups = {};
26905
26906               for (var i = 0; i < x.length; i++) {
26907                 var tagName = Object.keys(x[i])[0];
26908                 if (!groups[tagName]) groups[tagName] = [];
26909                 groups[tagName].push(x[i][tagName]);
26910               }
26911
26912               var ordered = {};
26913               order.forEach(function (o) {
26914                 if (groups[o]) ordered[o] = groups[o];
26915               });
26916               return ordered;
26917             } // sort relations in a changeset by dependencies
26918
26919
26920             function sort(changes) {
26921               // find a referenced relation in the current changeset
26922               function resolve(item) {
26923                 return relations.find(function (relation) {
26924                   return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
26925                 });
26926               } // a new item is an item that has not been already processed
26927
26928
26929               function isNew(item) {
26930                 return !sorted[item['@id']] && !processing.find(function (proc) {
26931                   return proc['@id'] === item['@id'];
26932                 });
26933               }
26934
26935               var processing = [];
26936               var sorted = {};
26937               var relations = changes.relation;
26938               if (!relations) return changes;
26939
26940               for (var i = 0; i < relations.length; i++) {
26941                 var relation = relations[i]; // skip relation if already sorted
26942
26943                 if (!sorted[relation['@id']]) {
26944                   processing.push(relation);
26945                 }
26946
26947                 while (processing.length > 0) {
26948                   var next = processing[0],
26949                       deps = next.member.map(resolve).filter(Boolean).filter(isNew);
26950
26951                   if (deps.length === 0) {
26952                     sorted[next['@id']] = next;
26953                     processing.shift();
26954                   } else {
26955                     processing = deps.concat(processing);
26956                   }
26957                 }
26958               }
26959
26960               changes.relation = Object.values(sorted);
26961               return changes;
26962             }
26963
26964             function rep(entity) {
26965               return entity.asJXON(changeset_id);
26966             }
26967
26968             return {
26969               osmChange: {
26970                 '@version': 0.6,
26971                 '@generator': 'iD',
26972                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
26973                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26974                 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
26975                   '@if-unused': true
26976                 })
26977               }
26978             };
26979           },
26980           asGeoJSON: function asGeoJSON() {
26981             return {};
26982           }
26983         });
26984
26985         function osmNote() {
26986           if (!(this instanceof osmNote)) {
26987             return new osmNote().initialize(arguments);
26988           } else if (arguments.length) {
26989             this.initialize(arguments);
26990           }
26991         }
26992
26993         osmNote.id = function () {
26994           return osmNote.id.next--;
26995         };
26996
26997         osmNote.id.next = -1;
26998         Object.assign(osmNote.prototype, {
26999           type: 'note',
27000           initialize: function initialize(sources) {
27001             for (var i = 0; i < sources.length; ++i) {
27002               var source = sources[i];
27003
27004               for (var prop in source) {
27005                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
27006                   if (source[prop] === undefined) {
27007                     delete this[prop];
27008                   } else {
27009                     this[prop] = source[prop];
27010                   }
27011                 }
27012               }
27013             }
27014
27015             if (!this.id) {
27016               this.id = osmNote.id().toString();
27017             }
27018
27019             return this;
27020           },
27021           extent: function extent() {
27022             return new geoExtent(this.loc);
27023           },
27024           update: function update(attrs) {
27025             return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
27026           },
27027           isNew: function isNew() {
27028             return this.id < 0;
27029           },
27030           move: function move(loc) {
27031             return this.update({
27032               loc: loc
27033             });
27034           }
27035         });
27036
27037         function osmRelation() {
27038           if (!(this instanceof osmRelation)) {
27039             return new osmRelation().initialize(arguments);
27040           } else if (arguments.length) {
27041             this.initialize(arguments);
27042           }
27043         }
27044         osmEntity.relation = osmRelation;
27045         osmRelation.prototype = Object.create(osmEntity.prototype);
27046
27047         osmRelation.creationOrder = function (a, b) {
27048           var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
27049           var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
27050           if (aId < 0 || bId < 0) return aId - bId;
27051           return bId - aId;
27052         };
27053
27054         Object.assign(osmRelation.prototype, {
27055           type: 'relation',
27056           members: [],
27057           copy: function copy(resolver, copies) {
27058             if (copies[this.id]) return copies[this.id];
27059             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
27060             var members = this.members.map(function (member) {
27061               return Object.assign({}, member, {
27062                 id: resolver.entity(member.id).copy(resolver, copies).id
27063               });
27064             });
27065             copy = copy.update({
27066               members: members
27067             });
27068             copies[this.id] = copy;
27069             return copy;
27070           },
27071           extent: function extent(resolver, memo) {
27072             return resolver["transient"](this, 'extent', function () {
27073               if (memo && memo[this.id]) return geoExtent();
27074               memo = memo || {};
27075               memo[this.id] = true;
27076               var extent = geoExtent();
27077
27078               for (var i = 0; i < this.members.length; i++) {
27079                 var member = resolver.hasEntity(this.members[i].id);
27080
27081                 if (member) {
27082                   extent._extend(member.extent(resolver, memo));
27083                 }
27084               }
27085
27086               return extent;
27087             });
27088           },
27089           geometry: function geometry(graph) {
27090             return graph["transient"](this, 'geometry', function () {
27091               return this.isMultipolygon() ? 'area' : 'relation';
27092             });
27093           },
27094           isDegenerate: function isDegenerate() {
27095             return this.members.length === 0;
27096           },
27097           // Return an array of members, each extended with an 'index' property whose value
27098           // is the member index.
27099           indexedMembers: function indexedMembers() {
27100             var result = new Array(this.members.length);
27101
27102             for (var i = 0; i < this.members.length; i++) {
27103               result[i] = Object.assign({}, this.members[i], {
27104                 index: i
27105               });
27106             }
27107
27108             return result;
27109           },
27110           // Return the first member with the given role. A copy of the member object
27111           // is returned, extended with an 'index' property whose value is the member index.
27112           memberByRole: function memberByRole(role) {
27113             for (var i = 0; i < this.members.length; i++) {
27114               if (this.members[i].role === role) {
27115                 return Object.assign({}, this.members[i], {
27116                   index: i
27117                 });
27118               }
27119             }
27120           },
27121           // Same as memberByRole, but returns all members with the given role
27122           membersByRole: function membersByRole(role) {
27123             var result = [];
27124
27125             for (var i = 0; i < this.members.length; i++) {
27126               if (this.members[i].role === role) {
27127                 result.push(Object.assign({}, this.members[i], {
27128                   index: i
27129                 }));
27130               }
27131             }
27132
27133             return result;
27134           },
27135           // Return the first member with the given id. A copy of the member object
27136           // is returned, extended with an 'index' property whose value is the member index.
27137           memberById: function memberById(id) {
27138             for (var i = 0; i < this.members.length; i++) {
27139               if (this.members[i].id === id) {
27140                 return Object.assign({}, this.members[i], {
27141                   index: i
27142                 });
27143               }
27144             }
27145           },
27146           // Return the first member with the given id and role. A copy of the member object
27147           // is returned, extended with an 'index' property whose value is the member index.
27148           memberByIdAndRole: function memberByIdAndRole(id, role) {
27149             for (var i = 0; i < this.members.length; i++) {
27150               if (this.members[i].id === id && this.members[i].role === role) {
27151                 return Object.assign({}, this.members[i], {
27152                   index: i
27153                 });
27154               }
27155             }
27156           },
27157           addMember: function addMember(member, index) {
27158             var members = this.members.slice();
27159             members.splice(index === undefined ? members.length : index, 0, member);
27160             return this.update({
27161               members: members
27162             });
27163           },
27164           updateMember: function updateMember(member, index) {
27165             var members = this.members.slice();
27166             members.splice(index, 1, Object.assign({}, members[index], member));
27167             return this.update({
27168               members: members
27169             });
27170           },
27171           removeMember: function removeMember(index) {
27172             var members = this.members.slice();
27173             members.splice(index, 1);
27174             return this.update({
27175               members: members
27176             });
27177           },
27178           removeMembersWithID: function removeMembersWithID(id) {
27179             var members = this.members.filter(function (m) {
27180               return m.id !== id;
27181             });
27182             return this.update({
27183               members: members
27184             });
27185           },
27186           moveMember: function moveMember(fromIndex, toIndex) {
27187             var members = this.members.slice();
27188             members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
27189             return this.update({
27190               members: members
27191             });
27192           },
27193           // Wherever a member appears with id `needle.id`, replace it with a member
27194           // with id `replacement.id`, type `replacement.type`, and the original role,
27195           // By default, adding a duplicate member (by id and role) is prevented.
27196           // Return an updated relation.
27197           replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
27198             if (!this.memberById(needle.id)) return this;
27199             var members = [];
27200
27201             for (var i = 0; i < this.members.length; i++) {
27202               var member = this.members[i];
27203
27204               if (member.id !== needle.id) {
27205                 members.push(member);
27206               } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
27207                 members.push({
27208                   id: replacement.id,
27209                   type: replacement.type,
27210                   role: member.role
27211                 });
27212               }
27213             }
27214
27215             return this.update({
27216               members: members
27217             });
27218           },
27219           asJXON: function asJXON(changeset_id) {
27220             var r = {
27221               relation: {
27222                 '@id': this.osmId(),
27223                 '@version': this.version || 0,
27224                 member: this.members.map(function (member) {
27225                   return {
27226                     keyAttributes: {
27227                       type: member.type,
27228                       role: member.role,
27229                       ref: osmEntity.id.toOSM(member.id)
27230                     }
27231                   };
27232                 }, this),
27233                 tag: Object.keys(this.tags).map(function (k) {
27234                   return {
27235                     keyAttributes: {
27236                       k: k,
27237                       v: this.tags[k]
27238                     }
27239                   };
27240                 }, this)
27241               }
27242             };
27243
27244             if (changeset_id) {
27245               r.relation['@changeset'] = changeset_id;
27246             }
27247
27248             return r;
27249           },
27250           asGeoJSON: function asGeoJSON(resolver) {
27251             return resolver["transient"](this, 'GeoJSON', function () {
27252               if (this.isMultipolygon()) {
27253                 return {
27254                   type: 'MultiPolygon',
27255                   coordinates: this.multipolygon(resolver)
27256                 };
27257               } else {
27258                 return {
27259                   type: 'FeatureCollection',
27260                   properties: this.tags,
27261                   features: this.members.map(function (member) {
27262                     return Object.assign({
27263                       role: member.role
27264                     }, resolver.entity(member.id).asGeoJSON(resolver));
27265                   })
27266                 };
27267               }
27268             });
27269           },
27270           area: function area(resolver) {
27271             return resolver["transient"](this, 'area', function () {
27272               return d3_geoArea(this.asGeoJSON(resolver));
27273             });
27274           },
27275           isMultipolygon: function isMultipolygon() {
27276             return this.tags.type === 'multipolygon';
27277           },
27278           isComplete: function isComplete(resolver) {
27279             for (var i = 0; i < this.members.length; i++) {
27280               if (!resolver.hasEntity(this.members[i].id)) {
27281                 return false;
27282               }
27283             }
27284
27285             return true;
27286           },
27287           hasFromViaTo: function hasFromViaTo() {
27288             return this.members.some(function (m) {
27289               return m.role === 'from';
27290             }) && this.members.some(function (m) {
27291               return m.role === 'via';
27292             }) && this.members.some(function (m) {
27293               return m.role === 'to';
27294             });
27295           },
27296           isRestriction: function isRestriction() {
27297             return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27298           },
27299           isValidRestriction: function isValidRestriction() {
27300             if (!this.isRestriction()) return false;
27301             var froms = this.members.filter(function (m) {
27302               return m.role === 'from';
27303             });
27304             var vias = this.members.filter(function (m) {
27305               return m.role === 'via';
27306             });
27307             var tos = this.members.filter(function (m) {
27308               return m.role === 'to';
27309             });
27310             if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
27311             if (froms.some(function (m) {
27312               return m.type !== 'way';
27313             })) return false;
27314             if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
27315             if (tos.some(function (m) {
27316               return m.type !== 'way';
27317             })) return false;
27318             if (vias.length === 0) return false;
27319             if (vias.length > 1 && vias.some(function (m) {
27320               return m.type !== 'way';
27321             })) return false;
27322             return true;
27323           },
27324           // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27325           // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27326           //
27327           // This corresponds to the structure needed for rendering a multipolygon path using a
27328           // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27329           //
27330           // In the case of invalid geometries, this function will still return a result which
27331           // includes the nodes of all way members, but some Nds may be unclosed and some inner
27332           // rings not matched with the intended outer ring.
27333           //
27334           multipolygon: function multipolygon(resolver) {
27335             var outers = this.members.filter(function (m) {
27336               return 'outer' === (m.role || 'outer');
27337             });
27338             var inners = this.members.filter(function (m) {
27339               return 'inner' === m.role;
27340             });
27341             outers = osmJoinWays(outers, resolver);
27342             inners = osmJoinWays(inners, resolver);
27343
27344             var sequenceToLineString = function sequenceToLineString(sequence) {
27345               if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
27346                 // close unclosed parts to ensure correct area rendering - #2945
27347                 sequence.nodes.push(sequence.nodes[0]);
27348               }
27349
27350               return sequence.nodes.map(function (node) {
27351                 return node.loc;
27352               });
27353             };
27354
27355             outers = outers.map(sequenceToLineString);
27356             inners = inners.map(sequenceToLineString);
27357             var result = outers.map(function (o) {
27358               // Heuristic for detecting counterclockwise winding order. Assumes
27359               // that OpenStreetMap polygons are not hemisphere-spanning.
27360               return [d3_geoArea({
27361                 type: 'Polygon',
27362                 coordinates: [o]
27363               }) > 2 * Math.PI ? o.reverse() : o];
27364             });
27365
27366             function findOuter(inner) {
27367               var o, outer;
27368
27369               for (o = 0; o < outers.length; o++) {
27370                 outer = outers[o];
27371                 if (geoPolygonContainsPolygon(outer, inner)) return o;
27372               }
27373
27374               for (o = 0; o < outers.length; o++) {
27375                 outer = outers[o];
27376                 if (geoPolygonIntersectsPolygon(outer, inner, false)) return o;
27377               }
27378             }
27379
27380             for (var i = 0; i < inners.length; i++) {
27381               var inner = inners[i];
27382
27383               if (d3_geoArea({
27384                 type: 'Polygon',
27385                 coordinates: [inner]
27386               }) < 2 * Math.PI) {
27387                 inner = inner.reverse();
27388               }
27389
27390               var o = findOuter(inners[i]);
27391
27392               if (o !== undefined) {
27393                 result[o].push(inners[i]);
27394               } else {
27395                 result.push([inners[i]]); // Invalid geometry
27396               }
27397             }
27398
27399             return result;
27400           }
27401         });
27402
27403         var QAItem = /*#__PURE__*/function () {
27404           function QAItem(loc, service, itemType, id, props) {
27405             _classCallCheck(this, QAItem);
27406
27407             // Store required properties
27408             this.loc = loc;
27409             this.service = service.title;
27410             this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
27411
27412             this.id = id ? id : "".concat(QAItem.id());
27413             this.update(props); // Some QA services have marker icons to differentiate issues
27414
27415             if (service && typeof service.getIcon === 'function') {
27416               this.icon = service.getIcon(itemType);
27417             }
27418           }
27419
27420           _createClass(QAItem, [{
27421             key: "update",
27422             value: function update(props) {
27423               var _this = this;
27424
27425               // You can't override this initial information
27426               var loc = this.loc,
27427                   service = this.service,
27428                   itemType = this.itemType,
27429                   id = this.id;
27430               Object.keys(props).forEach(function (prop) {
27431                 return _this[prop] = props[prop];
27432               });
27433               this.loc = loc;
27434               this.service = service;
27435               this.itemType = itemType;
27436               this.id = id;
27437               return this;
27438             } // Generic handling for newly created QAItems
27439
27440           }], [{
27441             key: "id",
27442             value: function id() {
27443               return this.nextId--;
27444             }
27445           }]);
27446
27447           return QAItem;
27448         }();
27449         QAItem.nextId = -1;
27450
27451         //
27452         // Optionally, split only the given ways, if multiple ways share
27453         // the given node.
27454         //
27455         // This is the inverse of `iD.actionJoin`.
27456         //
27457         // For testing convenience, accepts an ID to assign to the new way.
27458         // Normally, this will be undefined and the way will automatically
27459         // be assigned a new ID.
27460         //
27461         // Reference:
27462         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
27463         //
27464
27465         function actionSplit(nodeIds, newWayIds) {
27466           // accept single ID for backwards-compatiblity
27467           if (typeof nodeIds === 'string') nodeIds = [nodeIds];
27468
27469           var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
27470
27471
27472           var _keepHistoryOn = 'longest'; // 'longest', 'first'
27473           // The IDs of the ways actually created by running this action
27474
27475           var _createdWayIDs = [];
27476
27477           function dist(graph, nA, nB) {
27478             var locA = graph.entity(nA).loc;
27479             var locB = graph.entity(nB).loc;
27480             var epsilon = 1e-6;
27481             return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
27482           } // If the way is closed, we need to search for a partner node
27483           // to split the way at.
27484           //
27485           // The following looks for a node that is both far away from
27486           // the initial node in terms of way segment length and nearby
27487           // in terms of beeline-distance. This assures that areas get
27488           // split on the most "natural" points (independent of the number
27489           // of nodes).
27490           // For example: bone-shaped areas get split across their waist
27491           // line, circles across the diameter.
27492
27493
27494           function splitArea(nodes, idxA, graph) {
27495             var lengths = new Array(nodes.length);
27496             var length;
27497             var i;
27498             var best = 0;
27499             var idxB;
27500
27501             function wrap(index) {
27502               return utilWrap(index, nodes.length);
27503             } // calculate lengths
27504
27505
27506             length = 0;
27507
27508             for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
27509               length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
27510               lengths[i] = length;
27511             }
27512
27513             length = 0;
27514
27515             for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
27516               length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
27517
27518               if (length < lengths[i]) {
27519                 lengths[i] = length;
27520               }
27521             } // determine best opposite node to split
27522
27523
27524             for (i = 0; i < nodes.length; i++) {
27525               var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
27526
27527               if (cost > best) {
27528                 idxB = i;
27529                 best = cost;
27530               }
27531             }
27532
27533             return idxB;
27534           }
27535
27536           function totalLengthBetweenNodes(graph, nodes) {
27537             var totalLength = 0;
27538
27539             for (var i = 0; i < nodes.length - 1; i++) {
27540               totalLength += dist(graph, nodes[i], nodes[i + 1]);
27541             }
27542
27543             return totalLength;
27544           }
27545
27546           function split(graph, nodeId, wayA, newWayId) {
27547             var wayB = osmWay({
27548               id: newWayId,
27549               tags: wayA.tags
27550             }); // `wayB` is the NEW way
27551
27552             var origNodes = wayA.nodes.slice();
27553             var nodesA;
27554             var nodesB;
27555             var isArea = wayA.isArea();
27556             var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
27557
27558             if (wayA.isClosed()) {
27559               var nodes = wayA.nodes.slice(0, -1);
27560               var idxA = nodes.indexOf(nodeId);
27561               var idxB = splitArea(nodes, idxA, graph);
27562
27563               if (idxB < idxA) {
27564                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
27565                 nodesB = nodes.slice(idxB, idxA + 1);
27566               } else {
27567                 nodesA = nodes.slice(idxA, idxB + 1);
27568                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
27569               }
27570             } else {
27571               var idx = wayA.nodes.indexOf(nodeId, 1);
27572               nodesA = wayA.nodes.slice(0, idx + 1);
27573               nodesB = wayA.nodes.slice(idx);
27574             }
27575
27576             var lengthA = totalLengthBetweenNodes(graph, nodesA);
27577             var lengthB = totalLengthBetweenNodes(graph, nodesB);
27578
27579             if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
27580               // keep the history on the longer way, regardless of the node count
27581               wayA = wayA.update({
27582                 nodes: nodesB
27583               });
27584               wayB = wayB.update({
27585                 nodes: nodesA
27586               });
27587               var temp = lengthA;
27588               lengthA = lengthB;
27589               lengthB = temp;
27590             } else {
27591               wayA = wayA.update({
27592                 nodes: nodesA
27593               });
27594               wayB = wayB.update({
27595                 nodes: nodesB
27596               });
27597             }
27598
27599             if (wayA.tags.step_count) {
27600               // divide up the the step count proportionally between the two ways
27601               var stepCount = parseFloat(wayA.tags.step_count);
27602
27603               if (stepCount && // ensure a number
27604               isFinite(stepCount) && // ensure positive
27605               stepCount > 0 && // ensure integer
27606               Math.round(stepCount) === stepCount) {
27607                 var tagsA = Object.assign({}, wayA.tags);
27608                 var tagsB = Object.assign({}, wayB.tags);
27609                 var ratioA = lengthA / (lengthA + lengthB);
27610                 var countA = Math.round(stepCount * ratioA);
27611                 tagsA.step_count = countA.toString();
27612                 tagsB.step_count = (stepCount - countA).toString();
27613                 wayA = wayA.update({
27614                   tags: tagsA
27615                 });
27616                 wayB = wayB.update({
27617                   tags: tagsB
27618                 });
27619               }
27620             }
27621
27622             graph = graph.replace(wayA);
27623             graph = graph.replace(wayB);
27624             graph.parentRelations(wayA).forEach(function (relation) {
27625               var member; // Turn restrictions - make sure:
27626               // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
27627               //    (whichever one is connected to the VIA node/ways)
27628               // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
27629
27630               if (relation.hasFromViaTo()) {
27631                 var f = relation.memberByRole('from');
27632                 var v = relation.membersByRole('via');
27633                 var t = relation.memberByRole('to');
27634                 var i; // 1. split a FROM/TO
27635
27636                 if (f.id === wayA.id || t.id === wayA.id) {
27637                   var keepB = false;
27638
27639                   if (v.length === 1 && v[0].type === 'node') {
27640                     // check via node
27641                     keepB = wayB.contains(v[0].id);
27642                   } else {
27643                     // check via way(s)
27644                     for (i = 0; i < v.length; i++) {
27645                       if (v[i].type === 'way') {
27646                         var wayVia = graph.hasEntity(v[i].id);
27647
27648                         if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
27649                           keepB = true;
27650                           break;
27651                         }
27652                       }
27653                     }
27654                   }
27655
27656                   if (keepB) {
27657                     relation = relation.replaceMember(wayA, wayB);
27658                     graph = graph.replace(relation);
27659                   } // 2. split a VIA
27660
27661                 } else {
27662                   for (i = 0; i < v.length; i++) {
27663                     if (v[i].type === 'way' && v[i].id === wayA.id) {
27664                       member = {
27665                         id: wayB.id,
27666                         type: 'way',
27667                         role: 'via'
27668                       };
27669                       graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
27670                       break;
27671                     }
27672                   }
27673                 } // All other relations (Routes, Multipolygons, etc):
27674                 // 1. Both `wayA` and `wayB` remain in the relation
27675                 // 2. But must be inserted as a pair (see `actionAddMember` for details)
27676
27677               } else {
27678                 if (relation === isOuter) {
27679                   graph = graph.replace(relation.mergeTags(wayA.tags));
27680                   graph = graph.replace(wayA.update({
27681                     tags: {}
27682                   }));
27683                   graph = graph.replace(wayB.update({
27684                     tags: {}
27685                   }));
27686                 }
27687
27688                 member = {
27689                   id: wayB.id,
27690                   type: 'way',
27691                   role: relation.memberById(wayA.id).role
27692                 };
27693                 var insertPair = {
27694                   originalID: wayA.id,
27695                   insertedID: wayB.id,
27696                   nodes: origNodes
27697                 };
27698                 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
27699               }
27700             });
27701
27702             if (!isOuter && isArea) {
27703               var multipolygon = osmRelation({
27704                 tags: Object.assign({}, wayA.tags, {
27705                   type: 'multipolygon'
27706                 }),
27707                 members: [{
27708                   id: wayA.id,
27709                   role: 'outer',
27710                   type: 'way'
27711                 }, {
27712                   id: wayB.id,
27713                   role: 'outer',
27714                   type: 'way'
27715                 }]
27716               });
27717               graph = graph.replace(multipolygon);
27718               graph = graph.replace(wayA.update({
27719                 tags: {}
27720               }));
27721               graph = graph.replace(wayB.update({
27722                 tags: {}
27723               }));
27724             }
27725
27726             _createdWayIDs.push(wayB.id);
27727
27728             return graph;
27729           }
27730
27731           var action = function action(graph) {
27732             _createdWayIDs = [];
27733             var newWayIndex = 0;
27734
27735             for (var i = 0; i < nodeIds.length; i++) {
27736               var nodeId = nodeIds[i];
27737               var candidates = action.waysForNode(nodeId, graph);
27738
27739               for (var j = 0; j < candidates.length; j++) {
27740                 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
27741                 newWayIndex += 1;
27742               }
27743             }
27744
27745             return graph;
27746           };
27747
27748           action.getCreatedWayIDs = function () {
27749             return _createdWayIDs;
27750           };
27751
27752           action.waysForNode = function (nodeId, graph) {
27753             var node = graph.entity(nodeId);
27754             var splittableParents = graph.parentWays(node).filter(isSplittable);
27755
27756             if (!_wayIDs) {
27757               // If the ways to split aren't specified, only split the lines.
27758               // If there are no lines to split, split the areas.
27759               var hasLine = splittableParents.some(function (parent) {
27760                 return parent.geometry(graph) === 'line';
27761               });
27762
27763               if (hasLine) {
27764                 return splittableParents.filter(function (parent) {
27765                   return parent.geometry(graph) === 'line';
27766                 });
27767               }
27768             }
27769
27770             return splittableParents;
27771
27772             function isSplittable(parent) {
27773               // If the ways to split are specified, ignore everything else.
27774               if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
27775
27776               if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
27777
27778               for (var i = 1; i < parent.nodes.length - 1; i++) {
27779                 if (parent.nodes[i] === nodeId) return true;
27780               }
27781
27782               return false;
27783             }
27784           };
27785
27786           action.ways = function (graph) {
27787             return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
27788               return action.waysForNode(nodeId, graph);
27789             })));
27790           };
27791
27792           action.disabled = function (graph) {
27793             for (var i = 0; i < nodeIds.length; i++) {
27794               var nodeId = nodeIds[i];
27795               var candidates = action.waysForNode(nodeId, graph);
27796
27797               if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
27798                 return 'not_eligible';
27799               }
27800             }
27801           };
27802
27803           action.limitWays = function (val) {
27804             if (!arguments.length) return _wayIDs;
27805             _wayIDs = val;
27806             return action;
27807           };
27808
27809           action.keepHistoryOn = function (val) {
27810             if (!arguments.length) return _keepHistoryOn;
27811             _keepHistoryOn = val;
27812             return action;
27813           };
27814
27815           return action;
27816         }
27817
27818         function coreGraph(other, mutable) {
27819           if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
27820
27821           if (other instanceof coreGraph) {
27822             var base = other.base();
27823             this.entities = Object.assign(Object.create(base.entities), other.entities);
27824             this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
27825             this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
27826           } else {
27827             this.entities = Object.create({});
27828             this._parentWays = Object.create({});
27829             this._parentRels = Object.create({});
27830             this.rebase(other || [], [this]);
27831           }
27832
27833           this.transients = {};
27834           this._childNodes = {};
27835           this.frozen = !mutable;
27836         }
27837         coreGraph.prototype = {
27838           hasEntity: function hasEntity(id) {
27839             return this.entities[id];
27840           },
27841           entity: function entity(id) {
27842             var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
27843
27844             if (!entity) {
27845               entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
27846             }
27847
27848             if (!entity) {
27849               throw new Error('entity ' + id + ' not found');
27850             }
27851
27852             return entity;
27853           },
27854           geometry: function geometry(id) {
27855             return this.entity(id).geometry(this);
27856           },
27857           "transient": function transient(entity, key, fn) {
27858             var id = entity.id;
27859             var transients = this.transients[id] || (this.transients[id] = {});
27860
27861             if (transients[key] !== undefined) {
27862               return transients[key];
27863             }
27864
27865             transients[key] = fn.call(entity);
27866             return transients[key];
27867           },
27868           parentWays: function parentWays(entity) {
27869             var parents = this._parentWays[entity.id];
27870             var result = [];
27871
27872             if (parents) {
27873               parents.forEach(function (id) {
27874                 result.push(this.entity(id));
27875               }, this);
27876             }
27877
27878             return result;
27879           },
27880           isPoi: function isPoi(entity) {
27881             var parents = this._parentWays[entity.id];
27882             return !parents || parents.size === 0;
27883           },
27884           isShared: function isShared(entity) {
27885             var parents = this._parentWays[entity.id];
27886             return parents && parents.size > 1;
27887           },
27888           parentRelations: function parentRelations(entity) {
27889             var parents = this._parentRels[entity.id];
27890             var result = [];
27891
27892             if (parents) {
27893               parents.forEach(function (id) {
27894                 result.push(this.entity(id));
27895               }, this);
27896             }
27897
27898             return result;
27899           },
27900           parentMultipolygons: function parentMultipolygons(entity) {
27901             return this.parentRelations(entity).filter(function (relation) {
27902               return relation.isMultipolygon();
27903             });
27904           },
27905           childNodes: function childNodes(entity) {
27906             if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27907             if (!entity.nodes) return [];
27908             var nodes = [];
27909
27910             for (var i = 0; i < entity.nodes.length; i++) {
27911               nodes[i] = this.entity(entity.nodes[i]);
27912             }
27913             this._childNodes[entity.id] = nodes;
27914             return this._childNodes[entity.id];
27915           },
27916           base: function base() {
27917             return {
27918               'entities': Object.getPrototypeOf(this.entities),
27919               'parentWays': Object.getPrototypeOf(this._parentWays),
27920               'parentRels': Object.getPrototypeOf(this._parentRels)
27921             };
27922           },
27923           // Unlike other graph methods, rebase mutates in place. This is because it
27924           // is used only during the history operation that merges newly downloaded
27925           // data into each state. To external consumers, it should appear as if the
27926           // graph always contained the newly downloaded data.
27927           rebase: function rebase(entities, stack, force) {
27928             var base = this.base();
27929             var i, j, k, id;
27930
27931             for (i = 0; i < entities.length; i++) {
27932               var entity = entities[i];
27933               if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
27934
27935               base.entities[entity.id] = entity;
27936
27937               this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
27938
27939
27940               if (entity.type === 'way') {
27941                 for (j = 0; j < entity.nodes.length; j++) {
27942                   id = entity.nodes[j];
27943
27944                   for (k = 1; k < stack.length; k++) {
27945                     var ents = stack[k].entities;
27946
27947                     if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27948                       delete ents[id];
27949                     }
27950                   }
27951                 }
27952               }
27953             }
27954
27955             for (i = 0; i < stack.length; i++) {
27956               stack[i]._updateRebased();
27957             }
27958           },
27959           _updateRebased: function _updateRebased() {
27960             var base = this.base();
27961             Object.keys(this._parentWays).forEach(function (child) {
27962               if (base.parentWays[child]) {
27963                 base.parentWays[child].forEach(function (id) {
27964                   if (!this.entities.hasOwnProperty(id)) {
27965                     this._parentWays[child].add(id);
27966                   }
27967                 }, this);
27968               }
27969             }, this);
27970             Object.keys(this._parentRels).forEach(function (child) {
27971               if (base.parentRels[child]) {
27972                 base.parentRels[child].forEach(function (id) {
27973                   if (!this.entities.hasOwnProperty(id)) {
27974                     this._parentRels[child].add(id);
27975                   }
27976                 }, this);
27977               }
27978             }, this);
27979             this.transients = {}; // this._childNodes is not updated, under the assumption that
27980             // ways are always downloaded with their child nodes.
27981           },
27982           // Updates calculated properties (parentWays, parentRels) for the specified change
27983           _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
27984             parentWays = parentWays || this._parentWays;
27985             parentRels = parentRels || this._parentRels;
27986             var type = entity && entity.type || oldentity && oldentity.type;
27987             var removed, added, i;
27988
27989             if (type === 'way') {
27990               // Update parentWays
27991               if (oldentity && entity) {
27992                 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
27993                 added = utilArrayDifference(entity.nodes, oldentity.nodes);
27994               } else if (oldentity) {
27995                 removed = oldentity.nodes;
27996                 added = [];
27997               } else if (entity) {
27998                 removed = [];
27999                 added = entity.nodes;
28000               }
28001
28002               for (i = 0; i < removed.length; i++) {
28003                 // make a copy of prototype property, store as own property, and update..
28004                 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
28005                 parentWays[removed[i]]["delete"](oldentity.id);
28006               }
28007
28008               for (i = 0; i < added.length; i++) {
28009                 // make a copy of prototype property, store as own property, and update..
28010                 parentWays[added[i]] = new Set(parentWays[added[i]]);
28011                 parentWays[added[i]].add(entity.id);
28012               }
28013             } else if (type === 'relation') {
28014               // Update parentRels
28015               // diff only on the IDs since the same entity can be a member multiple times with different roles
28016               var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
28017                 return m.id;
28018               }) : [];
28019               var entityMemberIDs = entity ? entity.members.map(function (m) {
28020                 return m.id;
28021               }) : [];
28022
28023               if (oldentity && entity) {
28024                 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
28025                 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
28026               } else if (oldentity) {
28027                 removed = oldentityMemberIDs;
28028                 added = [];
28029               } else if (entity) {
28030                 removed = [];
28031                 added = entityMemberIDs;
28032               }
28033
28034               for (i = 0; i < removed.length; i++) {
28035                 // make a copy of prototype property, store as own property, and update..
28036                 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
28037                 parentRels[removed[i]]["delete"](oldentity.id);
28038               }
28039
28040               for (i = 0; i < added.length; i++) {
28041                 // make a copy of prototype property, store as own property, and update..
28042                 parentRels[added[i]] = new Set(parentRels[added[i]]);
28043                 parentRels[added[i]].add(entity.id);
28044               }
28045             }
28046           },
28047           replace: function replace(entity) {
28048             if (this.entities[entity.id] === entity) return this;
28049             return this.update(function () {
28050               this._updateCalculated(this.entities[entity.id], entity);
28051
28052               this.entities[entity.id] = entity;
28053             });
28054           },
28055           remove: function remove(entity) {
28056             return this.update(function () {
28057               this._updateCalculated(entity, undefined);
28058
28059               this.entities[entity.id] = undefined;
28060             });
28061           },
28062           revert: function revert(id) {
28063             var baseEntity = this.base().entities[id];
28064             var headEntity = this.entities[id];
28065             if (headEntity === baseEntity) return this;
28066             return this.update(function () {
28067               this._updateCalculated(headEntity, baseEntity);
28068
28069               delete this.entities[id];
28070             });
28071           },
28072           update: function update() {
28073             var graph = this.frozen ? coreGraph(this, true) : this;
28074
28075             for (var i = 0; i < arguments.length; i++) {
28076               arguments[i].call(graph, graph);
28077             }
28078
28079             if (this.frozen) graph.frozen = true;
28080             return graph;
28081           },
28082           // Obliterates any existing entities
28083           load: function load(entities) {
28084             var base = this.base();
28085             this.entities = Object.create(base.entities);
28086
28087             for (var i in entities) {
28088               this.entities[i] = entities[i];
28089
28090               this._updateCalculated(base.entities[i], this.entities[i]);
28091             }
28092
28093             return this;
28094           }
28095         };
28096
28097         function osmTurn(turn) {
28098           if (!(this instanceof osmTurn)) {
28099             return new osmTurn(turn);
28100           }
28101
28102           Object.assign(this, turn);
28103         }
28104         function osmIntersection(graph, startVertexId, maxDistance) {
28105           maxDistance = maxDistance || 30; // in meters
28106
28107           var vgraph = coreGraph(); // virtual graph
28108
28109           var i, j, k;
28110
28111           function memberOfRestriction(entity) {
28112             return graph.parentRelations(entity).some(function (r) {
28113               return r.isRestriction();
28114             });
28115           }
28116
28117           function isRoad(way) {
28118             if (way.isArea() || way.isDegenerate()) return false;
28119             var roads = {
28120               'motorway': true,
28121               'motorway_link': true,
28122               'trunk': true,
28123               'trunk_link': true,
28124               'primary': true,
28125               'primary_link': true,
28126               'secondary': true,
28127               'secondary_link': true,
28128               'tertiary': true,
28129               'tertiary_link': true,
28130               'residential': true,
28131               'unclassified': true,
28132               'living_street': true,
28133               'service': true,
28134               'road': true,
28135               'track': true
28136             };
28137             return roads[way.tags.highway];
28138           }
28139
28140           var startNode = graph.entity(startVertexId);
28141           var checkVertices = [startNode];
28142           var checkWays;
28143           var vertices = [];
28144           var vertexIds = [];
28145           var vertex;
28146           var ways = [];
28147           var wayIds = [];
28148           var way;
28149           var nodes = [];
28150           var node;
28151           var parents = [];
28152           var parent; // `actions` will store whatever actions must be performed to satisfy
28153           // preconditions for adding a turn restriction to this intersection.
28154           //  - Remove any existing degenerate turn restrictions (missing from/to, etc)
28155           //  - Reverse oneways so that they are drawn in the forward direction
28156           //  - Split ways on key vertices
28157
28158           var actions = []; // STEP 1:  walk the graph outwards from starting vertex to search
28159           //  for more key vertices and ways to include in the intersection..
28160
28161           while (checkVertices.length) {
28162             vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
28163
28164             checkWays = graph.parentWays(vertex);
28165             var hasWays = false;
28166
28167             for (i = 0; i < checkWays.length; i++) {
28168               way = checkWays[i];
28169               if (!isRoad(way) && !memberOfRestriction(way)) continue;
28170               ways.push(way); // it's a road, or it's already in a turn restriction
28171
28172               hasWays = true; // check the way's children for more key vertices
28173
28174               nodes = utilArrayUniq(graph.childNodes(way));
28175
28176               for (j = 0; j < nodes.length; j++) {
28177                 node = nodes[j];
28178                 if (node === vertex) continue; // same thing
28179
28180                 if (vertices.indexOf(node) !== -1) continue; // seen it already
28181
28182                 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
28183                 // a key vertex will have parents that are also roads
28184
28185                 var hasParents = false;
28186                 parents = graph.parentWays(node);
28187
28188                 for (k = 0; k < parents.length; k++) {
28189                   parent = parents[k];
28190                   if (parent === way) continue; // same thing
28191
28192                   if (ways.indexOf(parent) !== -1) continue; // seen it already
28193
28194                   if (!isRoad(parent)) continue; // not a road
28195
28196                   hasParents = true;
28197                   break;
28198                 }
28199
28200                 if (hasParents) {
28201                   checkVertices.push(node);
28202                 }
28203               }
28204             }
28205
28206             if (hasWays) {
28207               vertices.push(vertex);
28208             }
28209           }
28210
28211           vertices = utilArrayUniq(vertices);
28212           ways = utilArrayUniq(ways); // STEP 2:  Build a virtual graph containing only the entities in the intersection..
28213           // Everything done after this step should act on the virtual graph
28214           // Any actions that must be performed later to the main graph go in `actions` array
28215
28216           ways.forEach(function (way) {
28217             graph.childNodes(way).forEach(function (node) {
28218               vgraph = vgraph.replace(node);
28219             });
28220             vgraph = vgraph.replace(way);
28221             graph.parentRelations(way).forEach(function (relation) {
28222               if (relation.isRestriction()) {
28223                 if (relation.isValidRestriction(graph)) {
28224                   vgraph = vgraph.replace(relation);
28225                 } else if (relation.isComplete(graph)) {
28226                   actions.push(actionDeleteRelation(relation.id));
28227                 }
28228               }
28229             });
28230           }); // STEP 3:  Force all oneways to be drawn in the forward direction
28231
28232           ways.forEach(function (w) {
28233             var way = vgraph.entity(w.id);
28234
28235             if (way.tags.oneway === '-1') {
28236               var action = actionReverse(way.id, {
28237                 reverseOneway: true
28238               });
28239               actions.push(action);
28240               vgraph = action(vgraph);
28241             }
28242           }); // STEP 4:  Split ways on key vertices
28243
28244           var origCount = osmEntity.id.next.way;
28245           vertices.forEach(function (v) {
28246             // This is an odd way to do it, but we need to find all the ways that
28247             // will be split here, then split them one at a time to ensure that these
28248             // actions can be replayed on the main graph exactly in the same order.
28249             // (It is unintuitive, but the order of ways returned from graph.parentWays()
28250             // is arbitrary, depending on how the main graph and vgraph were built)
28251             var splitAll = actionSplit([v.id]).keepHistoryOn('first');
28252
28253             if (!splitAll.disabled(vgraph)) {
28254               splitAll.ways(vgraph).forEach(function (way) {
28255                 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
28256                 actions.push(splitOne);
28257                 vgraph = splitOne(vgraph);
28258               });
28259             }
28260           }); // In here is where we should also split the intersection at nearby junction.
28261           //   for https://github.com/mapbox/iD-internal/issues/31
28262           // nearbyVertices.forEach(function(v) {
28263           // });
28264           // Reasons why we reset the way id count here:
28265           //  1. Continuity with way ids created by the splits so that we can replay
28266           //     these actions later if the user decides to create a turn restriction
28267           //  2. Avoids churning way ids just by hovering over a vertex
28268           //     and displaying the turn restriction editor
28269
28270           osmEntity.id.next.way = origCount; // STEP 5:  Update arrays to point to vgraph entities
28271
28272           vertexIds = vertices.map(function (v) {
28273             return v.id;
28274           });
28275           vertices = [];
28276           ways = [];
28277           vertexIds.forEach(function (id) {
28278             var vertex = vgraph.entity(id);
28279             var parents = vgraph.parentWays(vertex);
28280             vertices.push(vertex);
28281             ways = ways.concat(parents);
28282           });
28283           vertices = utilArrayUniq(vertices);
28284           ways = utilArrayUniq(ways);
28285           vertexIds = vertices.map(function (v) {
28286             return v.id;
28287           });
28288           wayIds = ways.map(function (w) {
28289             return w.id;
28290           }); // STEP 6:  Update the ways with some metadata that will be useful for
28291           // walking the intersection graph later and rendering turn arrows.
28292
28293           function withMetadata(way, vertexIds) {
28294             var __oneWay = way.isOneWay(); // which affixes are key vertices?
28295
28296
28297             var __first = vertexIds.indexOf(way.first()) !== -1;
28298
28299             var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
28300
28301
28302             var __via = __first && __last;
28303
28304             var __from = __first && !__oneWay || __last;
28305
28306             var __to = __first || __last && !__oneWay;
28307
28308             return way.update({
28309               __first: __first,
28310               __last: __last,
28311               __from: __from,
28312               __via: __via,
28313               __to: __to,
28314               __oneWay: __oneWay
28315             });
28316           }
28317
28318           ways = [];
28319           wayIds.forEach(function (id) {
28320             var way = withMetadata(vgraph.entity(id), vertexIds);
28321             vgraph = vgraph.replace(way);
28322             ways.push(way);
28323           }); // STEP 7:  Simplify - This is an iterative process where we:
28324           //  1. Find trivial vertices with only 2 parents
28325           //  2. trim off the leaf way from those vertices and remove from vgraph
28326
28327           var keepGoing;
28328           var removeWayIds = [];
28329           var removeVertexIds = [];
28330
28331           do {
28332             keepGoing = false;
28333             checkVertices = vertexIds.slice();
28334
28335             for (i = 0; i < checkVertices.length; i++) {
28336               var vertexId = checkVertices[i];
28337               vertex = vgraph.hasEntity(vertexId);
28338
28339               if (!vertex) {
28340                 if (vertexIds.indexOf(vertexId) !== -1) {
28341                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28342                 }
28343
28344                 removeVertexIds.push(vertexId);
28345                 continue;
28346               }
28347
28348               parents = vgraph.parentWays(vertex);
28349
28350               if (parents.length < 3) {
28351                 if (vertexIds.indexOf(vertexId) !== -1) {
28352                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28353                 }
28354               }
28355
28356               if (parents.length === 2) {
28357                 // vertex with 2 parents is trivial
28358                 var a = parents[0];
28359                 var b = parents[1];
28360                 var aIsLeaf = a && !a.__via;
28361                 var bIsLeaf = b && !b.__via;
28362                 var leaf, survivor;
28363
28364                 if (aIsLeaf && !bIsLeaf) {
28365                   leaf = a;
28366                   survivor = b;
28367                 } else if (!aIsLeaf && bIsLeaf) {
28368                   leaf = b;
28369                   survivor = a;
28370                 }
28371
28372                 if (leaf && survivor) {
28373                   survivor = withMetadata(survivor, vertexIds); // update survivor way
28374
28375                   vgraph = vgraph.replace(survivor).remove(leaf); // update graph
28376
28377                   removeWayIds.push(leaf.id);
28378                   keepGoing = true;
28379                 }
28380               }
28381
28382               parents = vgraph.parentWays(vertex);
28383
28384               if (parents.length < 2) {
28385                 // vertex is no longer a key vertex
28386                 if (vertexIds.indexOf(vertexId) !== -1) {
28387                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28388                 }
28389
28390                 removeVertexIds.push(vertexId);
28391                 keepGoing = true;
28392               }
28393
28394               if (parents.length < 1) {
28395                 // vertex is no longer attached to anything
28396                 vgraph = vgraph.remove(vertex);
28397               }
28398             }
28399           } while (keepGoing);
28400
28401           vertices = vertices.filter(function (vertex) {
28402             return removeVertexIds.indexOf(vertex.id) === -1;
28403           }).map(function (vertex) {
28404             return vgraph.entity(vertex.id);
28405           });
28406           ways = ways.filter(function (way) {
28407             return removeWayIds.indexOf(way.id) === -1;
28408           }).map(function (way) {
28409             return vgraph.entity(way.id);
28410           }); // OK!  Here is our intersection..
28411
28412           var intersection = {
28413             graph: vgraph,
28414             actions: actions,
28415             vertices: vertices,
28416             ways: ways
28417           }; // Get all the valid turns through this intersection given a starting way id.
28418           // This operates on the virtual graph for everything.
28419           //
28420           // Basically, walk through all possible paths from starting way,
28421           //   honoring the existing turn restrictions as we go (watch out for loops!)
28422           //
28423           // For each path found, generate and return a `osmTurn` datastructure.
28424           //
28425
28426           intersection.turns = function (fromWayId, maxViaWay) {
28427             if (!fromWayId) return [];
28428             if (!maxViaWay) maxViaWay = 0;
28429             var vgraph = intersection.graph;
28430             var keyVertexIds = intersection.vertices.map(function (v) {
28431               return v.id;
28432             });
28433             var start = vgraph.entity(fromWayId);
28434             if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0   from-*-to              (0 vias)
28435             // maxViaWay=1   from-*-via-*-to        (1 via max)
28436             // maxViaWay=2   from-*-via-*-via-*-to  (2 vias max)
28437
28438             var maxPathLength = maxViaWay * 2 + 3;
28439             var turns = [];
28440             step(start);
28441             return turns; // traverse the intersection graph and find all the valid paths
28442
28443             function step(entity, currPath, currRestrictions, matchedRestriction) {
28444               currPath = (currPath || []).slice(); // shallow copy
28445
28446               if (currPath.length >= maxPathLength) return;
28447               currPath.push(entity.id);
28448               currRestrictions = (currRestrictions || []).slice(); // shallow copy
28449
28450               var i, j;
28451
28452               if (entity.type === 'node') {
28453                 var parents = vgraph.parentWays(entity);
28454                 var nextWays = []; // which ways can we step into?
28455
28456                 for (i = 0; i < parents.length; i++) {
28457                   var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
28458
28459                   if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
28460
28461                   if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
28462
28463                   var restrict = null;
28464
28465                   for (j = 0; j < currRestrictions.length; j++) {
28466                     var restriction = currRestrictions[j];
28467                     var f = restriction.memberByRole('from');
28468                     var v = restriction.membersByRole('via');
28469                     var t = restriction.memberByRole('to');
28470                     var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
28471
28472                     var matchesFrom = f.id === fromWayId;
28473                     var matchesViaTo = false;
28474                     var isAlongOnlyPath = false;
28475
28476                     if (t.id === way.id) {
28477                       // match TO
28478                       if (v.length === 1 && v[0].type === 'node') {
28479                         // match VIA node
28480                         matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
28481                       } else {
28482                         // match all VIA ways
28483                         var pathVias = [];
28484
28485                         for (k = 2; k < currPath.length; k += 2) {
28486                           // k = 2 skips FROM
28487                           pathVias.push(currPath[k]); // (path goes way-node-way...)
28488                         }
28489
28490                         var restrictionVias = [];
28491
28492                         for (k = 0; k < v.length; k++) {
28493                           if (v[k].type === 'way') {
28494                             restrictionVias.push(v[k].id);
28495                           }
28496                         }
28497
28498                         var diff = utilArrayDifference(pathVias, restrictionVias);
28499                         matchesViaTo = !diff.length;
28500                       }
28501                     } else if (isOnly) {
28502                       for (k = 0; k < v.length; k++) {
28503                         // way doesn't match TO, but is one of the via ways along the path of an "only"
28504                         if (v[k].type === 'way' && v[k].id === way.id) {
28505                           isAlongOnlyPath = true;
28506                           break;
28507                         }
28508                       }
28509                     }
28510
28511                     if (matchesViaTo) {
28512                       if (isOnly) {
28513                         restrict = {
28514                           id: restriction.id,
28515                           direct: matchesFrom,
28516                           from: f.id,
28517                           only: true,
28518                           end: true
28519                         };
28520                       } else {
28521                         restrict = {
28522                           id: restriction.id,
28523                           direct: matchesFrom,
28524                           from: f.id,
28525                           no: true,
28526                           end: true
28527                         };
28528                       }
28529                     } else {
28530                       // indirect - caused by a different nearby restriction
28531                       if (isAlongOnlyPath) {
28532                         restrict = {
28533                           id: restriction.id,
28534                           direct: false,
28535                           from: f.id,
28536                           only: true,
28537                           end: false
28538                         };
28539                       } else if (isOnly) {
28540                         restrict = {
28541                           id: restriction.id,
28542                           direct: false,
28543                           from: f.id,
28544                           no: true,
28545                           end: true
28546                         };
28547                       }
28548                     } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
28549
28550
28551                     if (restrict && restrict.direct) break;
28552                   }
28553
28554                   nextWays.push({
28555                     way: way,
28556                     restrict: restrict
28557                   });
28558                 }
28559
28560                 nextWays.forEach(function (nextWay) {
28561                   step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
28562                 });
28563               } else {
28564                 // entity.type === 'way'
28565                 if (currPath.length >= 3) {
28566                   // this is a "complete" path..
28567                   var turnPath = currPath.slice(); // shallow copy
28568                   // an indirect restriction - only include the partial path (starting at FROM)
28569
28570                   if (matchedRestriction && matchedRestriction.direct === false) {
28571                     for (i = 0; i < turnPath.length; i++) {
28572                       if (turnPath[i] === matchedRestriction.from) {
28573                         turnPath = turnPath.slice(i);
28574                         break;
28575                       }
28576                     }
28577                   }
28578
28579                   var turn = pathToTurn(turnPath);
28580
28581                   if (turn) {
28582                     if (matchedRestriction) {
28583                       turn.restrictionID = matchedRestriction.id;
28584                       turn.no = matchedRestriction.no;
28585                       turn.only = matchedRestriction.only;
28586                       turn.direct = matchedRestriction.direct;
28587                     }
28588
28589                     turns.push(osmTurn(turn));
28590                   }
28591
28592                   if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
28593                 }
28594
28595                 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
28596                 // which nodes can we step into?
28597
28598                 var n1 = vgraph.entity(entity.first());
28599                 var n2 = vgraph.entity(entity.last());
28600                 var dist = geoSphericalDistance(n1.loc, n2.loc);
28601                 var nextNodes = [];
28602
28603                 if (currPath.length > 1) {
28604                   if (dist > maxDistance) return; // the next node is too far
28605
28606                   if (!entity.__via) return; // this way is a leaf / can't be a via
28607                 }
28608
28609                 if (!entity.__oneWay && // bidirectional..
28610                 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
28611                 currPath.indexOf(n1.id) === -1) {
28612                   // haven't seen it yet..
28613                   nextNodes.push(n1); // can advance to first node
28614                 }
28615
28616                 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
28617                 currPath.indexOf(n2.id) === -1) {
28618                   // haven't seen it yet..
28619                   nextNodes.push(n2); // can advance to last node
28620                 }
28621
28622                 nextNodes.forEach(function (nextNode) {
28623                   // gather restrictions FROM this way
28624                   var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
28625                     if (!r.isRestriction()) return false;
28626                     var f = r.memberByRole('from');
28627                     if (!f || f.id !== entity.id) return false;
28628                     var isOnly = /^only_/.test(r.tags.restriction);
28629                     if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
28630
28631                     var isOnlyVia = false;
28632                     var v = r.membersByRole('via');
28633
28634                     if (v.length === 1 && v[0].type === 'node') {
28635                       // via node
28636                       isOnlyVia = v[0].id === nextNode.id;
28637                     } else {
28638                       // via way(s)
28639                       for (var i = 0; i < v.length; i++) {
28640                         if (v[i].type !== 'way') continue;
28641                         var viaWay = vgraph.entity(v[i].id);
28642
28643                         if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
28644                           isOnlyVia = true;
28645                           break;
28646                         }
28647                       }
28648                     }
28649
28650                     return isOnlyVia;
28651                   });
28652                   step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
28653                 });
28654               }
28655             } // assumes path is alternating way-node-way of odd length
28656
28657
28658             function pathToTurn(path) {
28659               if (path.length < 3) return;
28660               var fromWayId, fromNodeId, fromVertexId;
28661               var toWayId, toNodeId, toVertexId;
28662               var viaWayIds, viaNodeId, isUturn;
28663               fromWayId = path[0];
28664               toWayId = path[path.length - 1];
28665
28666               if (path.length === 3 && fromWayId === toWayId) {
28667                 // u turn
28668                 var way = vgraph.entity(fromWayId);
28669                 if (way.__oneWay) return null;
28670                 isUturn = true;
28671                 viaNodeId = fromVertexId = toVertexId = path[1];
28672                 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
28673               } else {
28674                 isUturn = false;
28675                 fromVertexId = path[1];
28676                 fromNodeId = adjacentNode(fromWayId, fromVertexId);
28677                 toVertexId = path[path.length - 2];
28678                 toNodeId = adjacentNode(toWayId, toVertexId);
28679
28680                 if (path.length === 3) {
28681                   viaNodeId = path[1];
28682                 } else {
28683                   viaWayIds = path.filter(function (entityId) {
28684                     return entityId[0] === 'w';
28685                   });
28686                   viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
28687                 }
28688               }
28689
28690               return {
28691                 key: path.join('_'),
28692                 path: path,
28693                 from: {
28694                   node: fromNodeId,
28695                   way: fromWayId,
28696                   vertex: fromVertexId
28697                 },
28698                 via: {
28699                   node: viaNodeId,
28700                   ways: viaWayIds
28701                 },
28702                 to: {
28703                   node: toNodeId,
28704                   way: toWayId,
28705                   vertex: toVertexId
28706                 },
28707                 u: isUturn
28708               };
28709
28710               function adjacentNode(wayId, affixId) {
28711                 var nodes = vgraph.entity(wayId).nodes;
28712                 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
28713               }
28714             }
28715           };
28716
28717           return intersection;
28718         }
28719         function osmInferRestriction(graph, turn, projection) {
28720           var fromWay = graph.entity(turn.from.way);
28721           var fromNode = graph.entity(turn.from.node);
28722           var fromVertex = graph.entity(turn.from.vertex);
28723           var toWay = graph.entity(turn.to.way);
28724           var toNode = graph.entity(turn.to.node);
28725           var toVertex = graph.entity(turn.to.vertex);
28726           var fromOneWay = fromWay.tags.oneway === 'yes';
28727           var toOneWay = toWay.tags.oneway === 'yes';
28728           var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
28729
28730           while (angle < 0) {
28731             angle += 360;
28732           }
28733
28734           if (fromNode === toNode) return 'no_u_turn';
28735           if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
28736
28737           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)
28738
28739           if (angle < 158) return 'no_right_turn';
28740           if (angle > 202) return 'no_left_turn';
28741           return 'no_straight_on';
28742         }
28743
28744         function actionMergePolygon(ids, newRelationId) {
28745           function groupEntities(graph) {
28746             var entities = ids.map(function (id) {
28747               return graph.entity(id);
28748             });
28749             var geometryGroups = utilArrayGroupBy(entities, function (entity) {
28750               if (entity.type === 'way' && entity.isClosed()) {
28751                 return 'closedWay';
28752               } else if (entity.type === 'relation' && entity.isMultipolygon()) {
28753                 return 'multipolygon';
28754               } else {
28755                 return 'other';
28756               }
28757             });
28758             return Object.assign({
28759               closedWay: [],
28760               multipolygon: [],
28761               other: []
28762             }, geometryGroups);
28763           }
28764
28765           var action = function action(graph) {
28766             var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
28767             //
28768             // Each element is itself an array of objects with an id property, and has a
28769             // locs property which is an array of the locations forming the polygon.
28770
28771             var polygons = entities.multipolygon.reduce(function (polygons, m) {
28772               return polygons.concat(osmJoinWays(m.members, graph));
28773             }, []).concat(entities.closedWay.map(function (d) {
28774               var member = [{
28775                 id: d.id
28776               }];
28777               member.nodes = graph.childNodes(d);
28778               return member;
28779             })); // contained is an array of arrays of boolean values,
28780             // where contained[j][k] is true iff the jth way is
28781             // contained by the kth way.
28782
28783             var contained = polygons.map(function (w, i) {
28784               return polygons.map(function (d, n) {
28785                 if (i === n) return null;
28786                 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
28787                   return n.loc;
28788                 }), w.nodes.map(function (n) {
28789                   return n.loc;
28790                 }));
28791               });
28792             }); // Sort all polygons as either outer or inner ways
28793
28794             var members = [];
28795             var outer = true;
28796
28797             while (polygons.length) {
28798               extractUncontained(polygons);
28799               polygons = polygons.filter(isContained);
28800               contained = contained.filter(isContained).map(filterContained);
28801             }
28802
28803             function isContained(d, i) {
28804               return contained[i].some(function (val) {
28805                 return val;
28806               });
28807             }
28808
28809             function filterContained(d) {
28810               return d.filter(isContained);
28811             }
28812
28813             function extractUncontained(polygons) {
28814               polygons.forEach(function (d, i) {
28815                 if (!isContained(d, i)) {
28816                   d.forEach(function (member) {
28817                     members.push({
28818                       type: 'way',
28819                       id: member.id,
28820                       role: outer ? 'outer' : 'inner'
28821                     });
28822                   });
28823                 }
28824               });
28825               outer = !outer;
28826             } // Move all tags to one relation
28827
28828
28829             var relation = entities.multipolygon[0] || osmRelation({
28830               id: newRelationId,
28831               tags: {
28832                 type: 'multipolygon'
28833               }
28834             });
28835             entities.multipolygon.slice(1).forEach(function (m) {
28836               relation = relation.mergeTags(m.tags);
28837               graph = graph.remove(m);
28838             });
28839             entities.closedWay.forEach(function (way) {
28840               function isThisOuter(m) {
28841                 return m.id === way.id && m.role !== 'inner';
28842               }
28843
28844               if (members.some(isThisOuter)) {
28845                 relation = relation.mergeTags(way.tags);
28846                 graph = graph.replace(way.update({
28847                   tags: {}
28848                 }));
28849               }
28850             });
28851             return graph.replace(relation.update({
28852               members: members,
28853               tags: utilObjectOmit(relation.tags, ['area'])
28854             }));
28855           };
28856
28857           action.disabled = function (graph) {
28858             var entities = groupEntities(graph);
28859
28860             if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
28861               return 'not_eligible';
28862             }
28863
28864             if (!entities.multipolygon.every(function (r) {
28865               return r.isComplete(graph);
28866             })) {
28867               return 'incomplete_relation';
28868             }
28869
28870             if (!entities.multipolygon.length) {
28871               var sharedMultipolygons = [];
28872               entities.closedWay.forEach(function (way, i) {
28873                 if (i === 0) {
28874                   sharedMultipolygons = graph.parentMultipolygons(way);
28875                 } else {
28876                   sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
28877                 }
28878               });
28879               sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
28880                 return relation.members.length === entities.closedWay.length;
28881               });
28882
28883               if (sharedMultipolygons.length) {
28884                 // don't create a new multipolygon if it'd be redundant
28885                 return 'not_eligible';
28886               }
28887             } else if (entities.closedWay.some(function (way) {
28888               return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
28889             })) {
28890               // don't add a way to a multipolygon again if it's already a member
28891               return 'not_eligible';
28892             }
28893           };
28894
28895           return action;
28896         }
28897
28898         var UNSUPPORTED_Y$3 = regexpStickyHelpers.UNSUPPORTED_Y;
28899
28900         // `RegExp.prototype.flags` getter
28901         // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
28902         if (descriptors && (/./g.flags != 'g' || UNSUPPORTED_Y$3)) {
28903           objectDefineProperty.f(RegExp.prototype, 'flags', {
28904             configurable: true,
28905             get: regexpFlags
28906           });
28907         }
28908
28909         var fastDeepEqual = function equal(a, b) {
28910           if (a === b) return true;
28911
28912           if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
28913             if (a.constructor !== b.constructor) return false;
28914             var length, i, keys;
28915
28916             if (Array.isArray(a)) {
28917               length = a.length;
28918               if (length != b.length) return false;
28919
28920               for (i = length; i-- !== 0;) {
28921                 if (!equal(a[i], b[i])) return false;
28922               }
28923
28924               return true;
28925             }
28926
28927             if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
28928             if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
28929             if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
28930             keys = Object.keys(a);
28931             length = keys.length;
28932             if (length !== Object.keys(b).length) return false;
28933
28934             for (i = length; i-- !== 0;) {
28935               if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
28936             }
28937
28938             for (i = length; i-- !== 0;) {
28939               var key = keys[i];
28940               if (!equal(a[key], b[key])) return false;
28941             }
28942
28943             return true;
28944           } // true if both NaN, false otherwise
28945
28946
28947           return a !== a && b !== b;
28948         };
28949
28950         // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
28951         // comparison, Bell Telephone Laboratories CSTR #41 (1976)
28952         // http://www.cs.dartmouth.edu/~doug/
28953         // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
28954         //
28955         // Expects two arrays, finds longest common sequence
28956
28957         function LCS(buffer1, buffer2) {
28958           var equivalenceClasses = {};
28959
28960           for (var j = 0; j < buffer2.length; j++) {
28961             var item = buffer2[j];
28962
28963             if (equivalenceClasses[item]) {
28964               equivalenceClasses[item].push(j);
28965             } else {
28966               equivalenceClasses[item] = [j];
28967             }
28968           }
28969
28970           var NULLRESULT = {
28971             buffer1index: -1,
28972             buffer2index: -1,
28973             chain: null
28974           };
28975           var candidates = [NULLRESULT];
28976
28977           for (var i = 0; i < buffer1.length; i++) {
28978             var _item = buffer1[i];
28979             var buffer2indices = equivalenceClasses[_item] || [];
28980             var r = 0;
28981             var c = candidates[0];
28982
28983             for (var jx = 0; jx < buffer2indices.length; jx++) {
28984               var _j = buffer2indices[jx];
28985               var s = void 0;
28986
28987               for (s = r; s < candidates.length; s++) {
28988                 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
28989                   break;
28990                 }
28991               }
28992
28993               if (s < candidates.length) {
28994                 var newCandidate = {
28995                   buffer1index: i,
28996                   buffer2index: _j,
28997                   chain: candidates[s]
28998                 };
28999
29000                 if (r === candidates.length) {
29001                   candidates.push(c);
29002                 } else {
29003                   candidates[r] = c;
29004                 }
29005
29006                 r = s + 1;
29007                 c = newCandidate;
29008
29009                 if (r === candidates.length) {
29010                   break; // no point in examining further (j)s
29011                 }
29012               }
29013             }
29014
29015             candidates[r] = c;
29016           } // At this point, we know the LCS: it's in the reverse of the
29017           // linked-list through .chain of candidates[candidates.length - 1].
29018
29019
29020           return candidates[candidates.length - 1];
29021         } // We apply the LCS to build a 'comm'-style picture of the
29022         // offsets and lengths of mismatched chunks in the input
29023         // buffers. This is used by diff3MergeRegions.
29024
29025
29026         function diffIndices(buffer1, buffer2) {
29027           var lcs = LCS(buffer1, buffer2);
29028           var result = [];
29029           var tail1 = buffer1.length;
29030           var tail2 = buffer2.length;
29031
29032           for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
29033             var mismatchLength1 = tail1 - candidate.buffer1index - 1;
29034             var mismatchLength2 = tail2 - candidate.buffer2index - 1;
29035             tail1 = candidate.buffer1index;
29036             tail2 = candidate.buffer2index;
29037
29038             if (mismatchLength1 || mismatchLength2) {
29039               result.push({
29040                 buffer1: [tail1 + 1, mismatchLength1],
29041                 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
29042                 buffer2: [tail2 + 1, mismatchLength2],
29043                 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
29044               });
29045             }
29046           }
29047
29048           result.reverse();
29049           return result;
29050         } // We apply the LCS to build a JSON representation of a
29051         // independently derived from O, returns a fairly complicated
29052         // internal representation of merge decisions it's taken. The
29053         // interested reader may wish to consult
29054         //
29055         // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
29056         // 'A Formal Investigation of ' In Arvind and Prasad,
29057         // editors, Foundations of Software Technology and Theoretical
29058         // Computer Science (FSTTCS), December 2007.
29059         //
29060         // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
29061         //
29062
29063
29064         function diff3MergeRegions(a, o, b) {
29065           // "hunks" are array subsets where `a` or `b` are different from `o`
29066           // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
29067           var hunks = [];
29068
29069           function addHunk(h, ab) {
29070             hunks.push({
29071               ab: ab,
29072               oStart: h.buffer1[0],
29073               oLength: h.buffer1[1],
29074               // length of o to remove
29075               abStart: h.buffer2[0],
29076               abLength: h.buffer2[1] // length of a/b to insert
29077               // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
29078
29079             });
29080           }
29081
29082           diffIndices(o, a).forEach(function (item) {
29083             return addHunk(item, 'a');
29084           });
29085           diffIndices(o, b).forEach(function (item) {
29086             return addHunk(item, 'b');
29087           });
29088           hunks.sort(function (x, y) {
29089             return x.oStart - y.oStart;
29090           });
29091           var results = [];
29092           var currOffset = 0;
29093
29094           function advanceTo(endOffset) {
29095             if (endOffset > currOffset) {
29096               results.push({
29097                 stable: true,
29098                 buffer: 'o',
29099                 bufferStart: currOffset,
29100                 bufferLength: endOffset - currOffset,
29101                 bufferContent: o.slice(currOffset, endOffset)
29102               });
29103               currOffset = endOffset;
29104             }
29105           }
29106
29107           while (hunks.length) {
29108             var hunk = hunks.shift();
29109             var regionStart = hunk.oStart;
29110             var regionEnd = hunk.oStart + hunk.oLength;
29111             var regionHunks = [hunk];
29112             advanceTo(regionStart); // Try to pull next overlapping hunk into this region
29113
29114             while (hunks.length) {
29115               var nextHunk = hunks[0];
29116               var nextHunkStart = nextHunk.oStart;
29117               if (nextHunkStart > regionEnd) break; // no overlap
29118
29119               regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
29120               regionHunks.push(hunks.shift());
29121             }
29122
29123             if (regionHunks.length === 1) {
29124               // Only one hunk touches this region, meaning that there is no conflict here.
29125               // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
29126               if (hunk.abLength > 0) {
29127                 var buffer = hunk.ab === 'a' ? a : b;
29128                 results.push({
29129                   stable: true,
29130                   buffer: hunk.ab,
29131                   bufferStart: hunk.abStart,
29132                   bufferLength: hunk.abLength,
29133                   bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
29134                 });
29135               }
29136             } else {
29137               // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
29138               // Effectively merge all the `a` hunks into one giant hunk, then do the
29139               // same for the `b` hunks; then, correct for skew in the regions of `o`
29140               // that each side changed, and report appropriate spans for the three sides.
29141               var bounds = {
29142                 a: [a.length, -1, o.length, -1],
29143                 b: [b.length, -1, o.length, -1]
29144               };
29145
29146               while (regionHunks.length) {
29147                 hunk = regionHunks.shift();
29148                 var oStart = hunk.oStart;
29149                 var oEnd = oStart + hunk.oLength;
29150                 var abStart = hunk.abStart;
29151                 var abEnd = abStart + hunk.abLength;
29152                 var _b = bounds[hunk.ab];
29153                 _b[0] = Math.min(abStart, _b[0]);
29154                 _b[1] = Math.max(abEnd, _b[1]);
29155                 _b[2] = Math.min(oStart, _b[2]);
29156                 _b[3] = Math.max(oEnd, _b[3]);
29157               }
29158
29159               var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
29160               var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
29161               var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
29162               var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
29163               var result = {
29164                 stable: false,
29165                 aStart: aStart,
29166                 aLength: aEnd - aStart,
29167                 aContent: a.slice(aStart, aEnd),
29168                 oStart: regionStart,
29169                 oLength: regionEnd - regionStart,
29170                 oContent: o.slice(regionStart, regionEnd),
29171                 bStart: bStart,
29172                 bLength: bEnd - bStart,
29173                 bContent: b.slice(bStart, bEnd)
29174               };
29175               results.push(result);
29176             }
29177
29178             currOffset = regionEnd;
29179           }
29180
29181           advanceTo(o.length);
29182           return results;
29183         } // Applies the output of diff3MergeRegions to actually
29184         // construct the merged buffer; the returned result alternates
29185         // between 'ok' and 'conflict' blocks.
29186         // A "false conflict" is where `a` and `b` both change the same from `o`
29187
29188
29189         function diff3Merge(a, o, b, options) {
29190           var defaults = {
29191             excludeFalseConflicts: true,
29192             stringSeparator: /\s+/
29193           };
29194           options = Object.assign(defaults, options);
29195           var aString = typeof a === 'string';
29196           var oString = typeof o === 'string';
29197           var bString = typeof b === 'string';
29198           if (aString) a = a.split(options.stringSeparator);
29199           if (oString) o = o.split(options.stringSeparator);
29200           if (bString) b = b.split(options.stringSeparator);
29201           var results = [];
29202           var regions = diff3MergeRegions(a, o, b);
29203           var okBuffer = [];
29204
29205           function flushOk() {
29206             if (okBuffer.length) {
29207               results.push({
29208                 ok: okBuffer
29209               });
29210             }
29211
29212             okBuffer = [];
29213           }
29214
29215           function isFalseConflict(a, b) {
29216             if (a.length !== b.length) return false;
29217
29218             for (var i = 0; i < a.length; i++) {
29219               if (a[i] !== b[i]) return false;
29220             }
29221
29222             return true;
29223           }
29224
29225           regions.forEach(function (region) {
29226             if (region.stable) {
29227               var _okBuffer;
29228
29229               (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
29230             } else {
29231               if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
29232                 var _okBuffer2;
29233
29234                 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
29235               } else {
29236                 flushOk();
29237                 results.push({
29238                   conflict: {
29239                     a: region.aContent,
29240                     aIndex: region.aStart,
29241                     o: region.oContent,
29242                     oIndex: region.oStart,
29243                     b: region.bContent,
29244                     bIndex: region.bStart
29245                   }
29246                 });
29247               }
29248             }
29249           });
29250           flushOk();
29251           return results;
29252         }
29253
29254         function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
29255           discardTags = discardTags || {};
29256           var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
29257
29258           var _conflicts = [];
29259
29260           function user(d) {
29261             return typeof formatUser === 'function' ? formatUser(d) : d;
29262           }
29263
29264           function mergeLocation(remote, target) {
29265             function pointEqual(a, b) {
29266               var epsilon = 1e-6;
29267               return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
29268             }
29269
29270             if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
29271               return target;
29272             }
29273
29274             if (_option === 'force_remote') {
29275               return target.update({
29276                 loc: remote.loc
29277               });
29278             }
29279
29280             _conflicts.push(_t('merge_remote_changes.conflict.location', {
29281               user: user(remote.user)
29282             }));
29283
29284             return target;
29285           }
29286
29287           function mergeNodes(base, remote, target) {
29288             if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
29289               return target;
29290             }
29291
29292             if (_option === 'force_remote') {
29293               return target.update({
29294                 nodes: remote.nodes
29295               });
29296             }
29297
29298             var ccount = _conflicts.length;
29299             var o = base.nodes || [];
29300             var a = target.nodes || [];
29301             var b = remote.nodes || [];
29302             var nodes = [];
29303             var hunks = diff3Merge(a, o, b, {
29304               excludeFalseConflicts: true
29305             });
29306
29307             for (var i = 0; i < hunks.length; i++) {
29308               var hunk = hunks[i];
29309
29310               if (hunk.ok) {
29311                 nodes.push.apply(nodes, hunk.ok);
29312               } else {
29313                 // for all conflicts, we can assume c.a !== c.b
29314                 // because `diff3Merge` called with `true` option to exclude false conflicts..
29315                 var c = hunk.conflict;
29316
29317                 if (fastDeepEqual(c.o, c.a)) {
29318                   // only changed remotely
29319                   nodes.push.apply(nodes, c.b);
29320                 } else if (fastDeepEqual(c.o, c.b)) {
29321                   // only changed locally
29322                   nodes.push.apply(nodes, c.a);
29323                 } else {
29324                   // changed both locally and remotely
29325                   _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
29326                     user: user(remote.user)
29327                   }));
29328
29329                   break;
29330                 }
29331               }
29332             }
29333
29334             return _conflicts.length === ccount ? target.update({
29335               nodes: nodes
29336             }) : target;
29337           }
29338
29339           function mergeChildren(targetWay, children, updates, graph) {
29340             function isUsed(node, targetWay) {
29341               var hasInterestingParent = graph.parentWays(node).some(function (way) {
29342                 return way.id !== targetWay.id;
29343               });
29344               return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
29345             }
29346
29347             var ccount = _conflicts.length;
29348
29349             for (var i = 0; i < children.length; i++) {
29350               var id = children[i];
29351               var node = graph.hasEntity(id); // remove unused childNodes..
29352
29353               if (targetWay.nodes.indexOf(id) === -1) {
29354                 if (node && !isUsed(node, targetWay)) {
29355                   updates.removeIds.push(id);
29356                 }
29357
29358                 continue;
29359               } // restore used childNodes..
29360
29361
29362               var local = localGraph.hasEntity(id);
29363               var remote = remoteGraph.hasEntity(id);
29364               var target;
29365
29366               if (_option === 'force_remote' && remote && remote.visible) {
29367                 updates.replacements.push(remote);
29368               } else if (_option === 'force_local' && local) {
29369                 target = osmEntity(local);
29370
29371                 if (remote) {
29372                   target = target.update({
29373                     version: remote.version
29374                   });
29375                 }
29376
29377                 updates.replacements.push(target);
29378               } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
29379                 target = osmEntity(local, {
29380                   version: remote.version
29381                 });
29382
29383                 if (remote.visible) {
29384                   target = mergeLocation(remote, target);
29385                 } else {
29386                   _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29387                     user: user(remote.user)
29388                   }));
29389                 }
29390
29391                 if (_conflicts.length !== ccount) break;
29392                 updates.replacements.push(target);
29393               }
29394             }
29395
29396             return targetWay;
29397           }
29398
29399           function updateChildren(updates, graph) {
29400             for (var i = 0; i < updates.replacements.length; i++) {
29401               graph = graph.replace(updates.replacements[i]);
29402             }
29403
29404             if (updates.removeIds.length) {
29405               graph = actionDeleteMultiple(updates.removeIds)(graph);
29406             }
29407
29408             return graph;
29409           }
29410
29411           function mergeMembers(remote, target) {
29412             if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
29413               return target;
29414             }
29415
29416             if (_option === 'force_remote') {
29417               return target.update({
29418                 members: remote.members
29419               });
29420             }
29421
29422             _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
29423               user: user(remote.user)
29424             }));
29425
29426             return target;
29427           }
29428
29429           function mergeTags(base, remote, target) {
29430             if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
29431               return target;
29432             }
29433
29434             if (_option === 'force_remote') {
29435               return target.update({
29436                 tags: remote.tags
29437               });
29438             }
29439
29440             var ccount = _conflicts.length;
29441             var o = base.tags || {};
29442             var a = target.tags || {};
29443             var b = remote.tags || {};
29444             var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
29445               return !discardTags[k];
29446             });
29447             var tags = Object.assign({}, a); // shallow copy
29448
29449             var changed = false;
29450
29451             for (var i = 0; i < keys.length; i++) {
29452               var k = keys[i];
29453
29454               if (o[k] !== b[k] && a[k] !== b[k]) {
29455                 // changed remotely..
29456                 if (o[k] !== a[k]) {
29457                   // changed locally..
29458                   _conflicts.push(_t('merge_remote_changes.conflict.tags', {
29459                     tag: k,
29460                     local: a[k],
29461                     remote: b[k],
29462                     user: user(remote.user)
29463                   }));
29464                 } else {
29465                   // unchanged locally, accept remote change..
29466                   if (b.hasOwnProperty(k)) {
29467                     tags[k] = b[k];
29468                   } else {
29469                     delete tags[k];
29470                   }
29471
29472                   changed = true;
29473                 }
29474               }
29475             }
29476
29477             return changed && _conflicts.length === ccount ? target.update({
29478               tags: tags
29479             }) : target;
29480           } //  `graph.base()` is the common ancestor of the two graphs.
29481           //  `localGraph` contains user's edits up to saving
29482           //  `remoteGraph` contains remote edits to modified nodes
29483           //  `graph` must be a descendent of `localGraph` and may include
29484           //      some conflict resolution actions performed on it.
29485           //
29486           //                  --- ... --- `localGraph` -- ... -- `graph`
29487           //                 /
29488           //  `graph.base()` --- ... --- `remoteGraph`
29489           //
29490
29491
29492           var action = function action(graph) {
29493             var updates = {
29494               replacements: [],
29495               removeIds: []
29496             };
29497             var base = graph.base().entities[id];
29498             var local = localGraph.entity(id);
29499             var remote = remoteGraph.entity(id);
29500             var target = osmEntity(local, {
29501               version: remote.version
29502             }); // delete/undelete
29503
29504             if (!remote.visible) {
29505               if (_option === 'force_remote') {
29506                 return actionDeleteMultiple([id])(graph);
29507               } else if (_option === 'force_local') {
29508                 if (target.type === 'way') {
29509                   target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
29510                   graph = updateChildren(updates, graph);
29511                 }
29512
29513                 return graph.replace(target);
29514               } else {
29515                 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29516                   user: user(remote.user)
29517                 }));
29518
29519                 return graph; // do nothing
29520               }
29521             } // merge
29522
29523
29524             if (target.type === 'node') {
29525               target = mergeLocation(remote, target);
29526             } else if (target.type === 'way') {
29527               // pull in any child nodes that may not be present locally..
29528               graph.rebase(remoteGraph.childNodes(remote), [graph], false);
29529               target = mergeNodes(base, remote, target);
29530               target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
29531             } else if (target.type === 'relation') {
29532               target = mergeMembers(remote, target);
29533             }
29534
29535             target = mergeTags(base, remote, target);
29536
29537             if (!_conflicts.length) {
29538               graph = updateChildren(updates, graph).replace(target);
29539             }
29540
29541             return graph;
29542           };
29543
29544           action.withOption = function (opt) {
29545             _option = opt;
29546             return action;
29547           };
29548
29549           action.conflicts = function () {
29550             return _conflicts;
29551           };
29552
29553           return action;
29554         }
29555
29556         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
29557
29558         function actionMove(moveIDs, tryDelta, projection, cache) {
29559           var _delta = tryDelta;
29560
29561           function setupCache(graph) {
29562             function canMove(nodeID) {
29563               // Allow movement of any node that is in the selectedIDs list..
29564               if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
29565
29566               var parents = graph.parentWays(graph.entity(nodeID));
29567               if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
29568
29569               var parentsMoving = parents.every(function (way) {
29570                 return cache.moving[way.id];
29571               });
29572               if (!parentsMoving) delete cache.moving[nodeID];
29573               return parentsMoving;
29574             }
29575
29576             function cacheEntities(ids) {
29577               for (var i = 0; i < ids.length; i++) {
29578                 var id = ids[i];
29579                 if (cache.moving[id]) continue;
29580                 cache.moving[id] = true;
29581                 var entity = graph.hasEntity(id);
29582                 if (!entity) continue;
29583
29584                 if (entity.type === 'node') {
29585                   cache.nodes.push(id);
29586                   cache.startLoc[id] = entity.loc;
29587                 } else if (entity.type === 'way') {
29588                   cache.ways.push(id);
29589                   cacheEntities(entity.nodes);
29590                 } else {
29591                   cacheEntities(entity.members.map(function (member) {
29592                     return member.id;
29593                   }));
29594                 }
29595               }
29596             }
29597
29598             function cacheIntersections(ids) {
29599               function isEndpoint(way, id) {
29600                 return !way.isClosed() && !!way.affix(id);
29601               }
29602
29603               for (var i = 0; i < ids.length; i++) {
29604                 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
29605
29606                 var childNodes = graph.childNodes(graph.entity(id));
29607
29608                 for (var j = 0; j < childNodes.length; j++) {
29609                   var node = childNodes[j];
29610                   var parents = graph.parentWays(node);
29611                   if (parents.length !== 2) continue;
29612                   var moved = graph.entity(id);
29613                   var unmoved = null;
29614
29615                   for (var k = 0; k < parents.length; k++) {
29616                     var way = parents[k];
29617
29618                     if (!cache.moving[way.id]) {
29619                       unmoved = way;
29620                       break;
29621                     }
29622                   }
29623
29624                   if (!unmoved) continue; // exclude ways that are overly connected..
29625
29626                   if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
29627                   if (moved.isArea() || unmoved.isArea()) continue;
29628                   cache.intersections.push({
29629                     nodeId: node.id,
29630                     movedId: moved.id,
29631                     unmovedId: unmoved.id,
29632                     movedIsEP: isEndpoint(moved, node.id),
29633                     unmovedIsEP: isEndpoint(unmoved, node.id)
29634                   });
29635                 }
29636               }
29637             }
29638
29639             if (!cache) {
29640               cache = {};
29641             }
29642
29643             if (!cache.ok) {
29644               cache.moving = {};
29645               cache.intersections = [];
29646               cache.replacedVertex = {};
29647               cache.startLoc = {};
29648               cache.nodes = [];
29649               cache.ways = [];
29650               cacheEntities(moveIDs);
29651               cacheIntersections(cache.ways);
29652               cache.nodes = cache.nodes.filter(canMove);
29653               cache.ok = true;
29654             }
29655           } // Place a vertex where the moved vertex used to be, to preserve way shape..
29656           //
29657           //  Start:
29658           //      b ---- e
29659           //     / \
29660           //    /   \
29661           //   /     \
29662           //  a       c
29663           //
29664           //      *               node '*' added to preserve shape
29665           //     / \
29666           //    /   b ---- e      way `b,e` moved here:
29667           //   /     \
29668           //  a       c
29669           //
29670           //
29671
29672
29673           function replaceMovedVertex(nodeId, wayId, graph, delta) {
29674             var way = graph.entity(wayId);
29675             var moved = graph.entity(nodeId);
29676             var movedIndex = way.nodes.indexOf(nodeId);
29677             var len, prevIndex, nextIndex;
29678
29679             if (way.isClosed()) {
29680               len = way.nodes.length - 1;
29681               prevIndex = (movedIndex + len - 1) % len;
29682               nextIndex = (movedIndex + len + 1) % len;
29683             } else {
29684               len = way.nodes.length;
29685               prevIndex = movedIndex - 1;
29686               nextIndex = movedIndex + 1;
29687             }
29688
29689             var prev = graph.hasEntity(way.nodes[prevIndex]);
29690             var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
29691
29692             if (!prev || !next) return graph;
29693             var key = wayId + '_' + nodeId;
29694             var orig = cache.replacedVertex[key];
29695
29696             if (!orig) {
29697               orig = osmNode();
29698               cache.replacedVertex[key] = orig;
29699               cache.startLoc[orig.id] = cache.startLoc[nodeId];
29700             }
29701
29702             var start, end;
29703
29704             if (delta) {
29705               start = projection(cache.startLoc[nodeId]);
29706               end = projection.invert(geoVecAdd(start, delta));
29707             } else {
29708               end = cache.startLoc[nodeId];
29709             }
29710
29711             orig = orig.move(end);
29712             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..
29713
29714             if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
29715
29716             var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
29717             var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
29718             var d1 = geoPathLength(p1);
29719             var d2 = geoPathLength(p2);
29720             var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
29721
29722             if (way.isClosed() && insertAt === 0) insertAt = len;
29723             way = way.addNode(orig.id, insertAt);
29724             return graph.replace(orig).replace(way);
29725           } // Remove duplicate vertex that might have been added by
29726           // replaceMovedVertex.  This is done after the unzorro checks.
29727
29728
29729           function removeDuplicateVertices(wayId, graph) {
29730             var way = graph.entity(wayId);
29731             var epsilon = 1e-6;
29732             var prev, curr;
29733
29734             function isInteresting(node, graph) {
29735               return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
29736             }
29737
29738             for (var i = 0; i < way.nodes.length; i++) {
29739               curr = graph.entity(way.nodes[i]);
29740
29741               if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
29742                 if (!isInteresting(prev, graph)) {
29743                   way = way.removeNode(prev.id);
29744                   graph = graph.replace(way).remove(prev);
29745                 } else if (!isInteresting(curr, graph)) {
29746                   way = way.removeNode(curr.id);
29747                   graph = graph.replace(way).remove(curr);
29748                 }
29749               }
29750
29751               prev = curr;
29752             }
29753
29754             return graph;
29755           } // Reorder nodes around intersections that have moved..
29756           //
29757           //  Start:                way1.nodes: b,e         (moving)
29758           //  a - b - c ----- d     way2.nodes: a,b,c,d     (static)
29759           //      |                 vertex: b
29760           //      e                 isEP1: true,  isEP2, false
29761           //
29762           //  way1 `b,e` moved here:
29763           //  a ----- c = b - d
29764           //              |
29765           //              e
29766           //
29767           //  reorder nodes         way1.nodes: b,e
29768           //  a ----- c - b - d     way2.nodes: a,c,b,d
29769           //              |
29770           //              e
29771           //
29772
29773
29774           function unZorroIntersection(intersection, graph) {
29775             var vertex = graph.entity(intersection.nodeId);
29776             var way1 = graph.entity(intersection.movedId);
29777             var way2 = graph.entity(intersection.unmovedId);
29778             var isEP1 = intersection.movedIsEP;
29779             var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
29780
29781             if (isEP1 && isEP2) return graph;
29782             var nodes1 = graph.childNodes(way1).filter(function (n) {
29783               return n !== vertex;
29784             });
29785             var nodes2 = graph.childNodes(way2).filter(function (n) {
29786               return n !== vertex;
29787             });
29788             if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
29789             if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
29790             var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
29791             var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
29792             var loc; // snap vertex to nearest edge (or some point between them)..
29793
29794             if (!isEP1 && !isEP2) {
29795               var epsilon = 1e-6,
29796                   maxIter = 10;
29797
29798               for (var i = 0; i < maxIter; i++) {
29799                 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
29800                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
29801                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
29802                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
29803               }
29804             } else if (!isEP1) {
29805               loc = edge1.loc;
29806             } else {
29807               loc = edge2.loc;
29808             }
29809
29810             graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
29811
29812             if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
29813               way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
29814               graph = graph.replace(way1);
29815             }
29816
29817             if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
29818               way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
29819               graph = graph.replace(way2);
29820             }
29821
29822             return graph;
29823           }
29824
29825           function cleanupIntersections(graph) {
29826             for (var i = 0; i < cache.intersections.length; i++) {
29827               var obj = cache.intersections[i];
29828               graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
29829               graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
29830               graph = unZorroIntersection(obj, graph);
29831               graph = removeDuplicateVertices(obj.movedId, graph);
29832               graph = removeDuplicateVertices(obj.unmovedId, graph);
29833             }
29834
29835             return graph;
29836           } // check if moving way endpoint can cross an unmoved way, if so limit delta..
29837
29838
29839           function limitDelta(graph) {
29840             function moveNode(loc) {
29841               return geoVecAdd(projection(loc), _delta);
29842             }
29843
29844             for (var i = 0; i < cache.intersections.length; i++) {
29845               var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
29846
29847               if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
29848
29849               if (!obj.movedIsEP) continue;
29850               var node = graph.entity(obj.nodeId);
29851               var start = projection(node.loc);
29852               var end = geoVecAdd(start, _delta);
29853               var movedNodes = graph.childNodes(graph.entity(obj.movedId));
29854               var movedPath = movedNodes.map(function (n) {
29855                 return moveNode(n.loc);
29856               });
29857               var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
29858               var unmovedPath = unmovedNodes.map(function (n) {
29859                 return projection(n.loc);
29860               });
29861               var hits = geoPathIntersections(movedPath, unmovedPath);
29862
29863               for (var j = 0; i < hits.length; i++) {
29864                 if (geoVecEqual(hits[j], end)) continue;
29865                 var edge = geoChooseEdge(unmovedNodes, end, projection);
29866                 _delta = geoVecSubtract(projection(edge.loc), start);
29867               }
29868             }
29869           }
29870
29871           var action = function action(graph) {
29872             if (_delta[0] === 0 && _delta[1] === 0) return graph;
29873             setupCache(graph);
29874
29875             if (cache.intersections.length) {
29876               limitDelta(graph);
29877             }
29878
29879             for (var i = 0; i < cache.nodes.length; i++) {
29880               var node = graph.entity(cache.nodes[i]);
29881               var start = projection(node.loc);
29882               var end = geoVecAdd(start, _delta);
29883               graph = graph.replace(node.move(projection.invert(end)));
29884             }
29885
29886             if (cache.intersections.length) {
29887               graph = cleanupIntersections(graph);
29888             }
29889
29890             return graph;
29891           };
29892
29893           action.delta = function () {
29894             return _delta;
29895           };
29896
29897           return action;
29898         }
29899
29900         function actionMoveMember(relationId, fromIndex, toIndex) {
29901           return function (graph) {
29902             return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
29903           };
29904         }
29905
29906         function actionMoveNode(nodeID, toLoc) {
29907           var action = function action(graph, t) {
29908             if (t === null || !isFinite(t)) t = 1;
29909             t = Math.min(Math.max(+t, 0), 1);
29910             var node = graph.entity(nodeID);
29911             return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
29912           };
29913
29914           action.transitionable = true;
29915           return action;
29916         }
29917
29918         function actionNoop() {
29919           return function (graph) {
29920             return graph;
29921           };
29922         }
29923
29924         function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
29925           var epsilon = ep || 1e-4;
29926           var threshold = degThresh || 13; // degrees within right or straight to alter
29927           // We test normalized dot products so we can compare as cos(angle)
29928
29929           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
29930           var upperThreshold = Math.cos(threshold * Math.PI / 180);
29931
29932           var action = function action(graph, t) {
29933             if (t === null || !isFinite(t)) t = 1;
29934             t = Math.min(Math.max(+t, 0), 1);
29935             var way = graph.entity(wayID);
29936             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
29937
29938             if (way.tags.nonsquare) {
29939               var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
29940
29941               delete tags.nonsquare;
29942               way = way.update({
29943                 tags: tags
29944               });
29945             }
29946
29947             graph = graph.replace(way);
29948             var isClosed = way.isClosed();
29949             var nodes = graph.childNodes(way).slice(); // shallow copy
29950
29951             if (isClosed) nodes.pop();
29952
29953             if (vertexID !== undefined) {
29954               nodes = nodeSubset(nodes, vertexID, isClosed);
29955               if (nodes.length !== 3) return graph;
29956             } // note: all geometry functions here use the unclosed node/point/coord list
29957
29958
29959             var nodeCount = {};
29960             var points = [];
29961             var corner = {
29962               i: 0,
29963               dotp: 1
29964             };
29965             var node, point, loc, score, motions, i, j;
29966
29967             for (i = 0; i < nodes.length; i++) {
29968               node = nodes[i];
29969               nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
29970               points.push({
29971                 id: node.id,
29972                 coord: projection(node.loc)
29973               });
29974             }
29975
29976             if (points.length === 3) {
29977               // move only one vertex for right triangle
29978               for (i = 0; i < 1000; i++) {
29979                 motions = points.map(calcMotion);
29980                 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
29981                 score = corner.dotp;
29982
29983                 if (score < epsilon) {
29984                   break;
29985                 }
29986               }
29987
29988               node = graph.entity(nodes[corner.i].id);
29989               loc = projection.invert(points[corner.i].coord);
29990               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
29991             } else {
29992               var straights = [];
29993               var simplified = []; // Remove points from nearly straight sections..
29994               // This produces a simplified shape to orthogonalize
29995
29996               for (i = 0; i < points.length; i++) {
29997                 point = points[i];
29998                 var dotp = 0;
29999
30000                 if (isClosed || i > 0 && i < points.length - 1) {
30001                   var a = points[(i - 1 + points.length) % points.length];
30002                   var b = points[(i + 1) % points.length];
30003                   dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
30004                 }
30005
30006                 if (dotp > upperThreshold) {
30007                   straights.push(point);
30008                 } else {
30009                   simplified.push(point);
30010                 }
30011               } // Orthogonalize the simplified shape
30012
30013
30014               var bestPoints = clonePoints(simplified);
30015               var originalPoints = clonePoints(simplified);
30016               score = Infinity;
30017
30018               for (i = 0; i < 1000; i++) {
30019                 motions = simplified.map(calcMotion);
30020
30021                 for (j = 0; j < motions.length; j++) {
30022                   simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
30023                 }
30024
30025                 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
30026
30027                 if (newScore < score) {
30028                   bestPoints = clonePoints(simplified);
30029                   score = newScore;
30030                 }
30031
30032                 if (score < epsilon) {
30033                   break;
30034                 }
30035               }
30036
30037               var bestCoords = bestPoints.map(function (p) {
30038                 return p.coord;
30039               });
30040               if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
30041
30042               for (i = 0; i < bestPoints.length; i++) {
30043                 point = bestPoints[i];
30044
30045                 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
30046                   node = graph.entity(point.id);
30047                   loc = projection.invert(point.coord);
30048                   graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
30049                 }
30050               } // move the nodes along straight segments
30051
30052
30053               for (i = 0; i < straights.length; i++) {
30054                 point = straights[i];
30055                 if (nodeCount[point.id] > 1) continue; // skip self-intersections
30056
30057                 node = graph.entity(point.id);
30058
30059                 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
30060                   // remove uninteresting points..
30061                   graph = actionDeleteNode(node.id)(graph);
30062                 } else {
30063                   // move interesting points to the nearest edge..
30064                   var choice = geoVecProject(point.coord, bestCoords);
30065
30066                   if (choice) {
30067                     loc = projection.invert(choice.target);
30068                     graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
30069                   }
30070                 }
30071               }
30072             }
30073
30074             return graph;
30075
30076             function clonePoints(array) {
30077               return array.map(function (p) {
30078                 return {
30079                   id: p.id,
30080                   coord: [p.coord[0], p.coord[1]]
30081                 };
30082               });
30083             }
30084
30085             function calcMotion(point, i, array) {
30086               // don't try to move the endpoints of a non-closed way.
30087               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)
30088
30089               if (nodeCount[array[i].id] > 1) return [0, 0];
30090               var a = array[(i - 1 + array.length) % array.length].coord;
30091               var origin = point.coord;
30092               var b = array[(i + 1) % array.length].coord;
30093               var p = geoVecSubtract(a, origin);
30094               var q = geoVecSubtract(b, origin);
30095               var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
30096               p = geoVecNormalize(p);
30097               q = geoVecNormalize(q);
30098               var dotp = p[0] * q[0] + p[1] * q[1];
30099               var val = Math.abs(dotp);
30100
30101               if (val < lowerThreshold) {
30102                 // nearly orthogonal
30103                 corner.i = i;
30104                 corner.dotp = val;
30105                 var vec = geoVecNormalize(geoVecAdd(p, q));
30106                 return geoVecScale(vec, 0.1 * dotp * scale);
30107               }
30108
30109               return [0, 0]; // do nothing
30110             }
30111           }; // if we are only orthogonalizing one vertex,
30112           // get that vertex and the previous and next
30113
30114
30115           function nodeSubset(nodes, vertexID, isClosed) {
30116             var first = isClosed ? 0 : 1;
30117             var last = isClosed ? nodes.length : nodes.length - 1;
30118
30119             for (var i = first; i < last; i++) {
30120               if (nodes[i].id === vertexID) {
30121                 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
30122               }
30123             }
30124
30125             return [];
30126           }
30127
30128           action.disabled = function (graph) {
30129             var way = graph.entity(wayID);
30130             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
30131
30132             graph = graph.replace(way);
30133             var isClosed = way.isClosed();
30134             var nodes = graph.childNodes(way).slice(); // shallow copy
30135
30136             if (isClosed) nodes.pop();
30137             var allowStraightAngles = false;
30138
30139             if (vertexID !== undefined) {
30140               allowStraightAngles = true;
30141               nodes = nodeSubset(nodes, vertexID, isClosed);
30142               if (nodes.length !== 3) return 'end_vertex';
30143             }
30144
30145             var coords = nodes.map(function (n) {
30146               return projection(n.loc);
30147             });
30148             var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
30149
30150             if (score === null) {
30151               return 'not_squarish';
30152             } else if (score === 0) {
30153               return 'square_enough';
30154             } else {
30155               return false;
30156             }
30157           };
30158
30159           action.transitionable = true;
30160           return action;
30161         }
30162
30163         //
30164         // `turn` must be an `osmTurn` object
30165         // see osm/intersection.js, pathToTurn()
30166         //
30167         // This specifies a restriction of type `restriction` when traveling from
30168         // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
30169         // (The action does not check that these entities form a valid intersection.)
30170         //
30171         // From, to, and via ways should be split before calling this action.
30172         // (old versions of the code would split the ways here, but we no longer do it)
30173         //
30174         // For testing convenience, accepts a restrictionID to assign to the new
30175         // relation. Normally, this will be undefined and the relation will
30176         // automatically be assigned a new ID.
30177         //
30178
30179         function actionRestrictTurn(turn, restrictionType, restrictionID) {
30180           return function (graph) {
30181             var fromWay = graph.entity(turn.from.way);
30182             var toWay = graph.entity(turn.to.way);
30183             var viaNode = turn.via.node && graph.entity(turn.via.node);
30184             var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
30185               return graph.entity(id);
30186             });
30187             var members = [];
30188             members.push({
30189               id: fromWay.id,
30190               type: 'way',
30191               role: 'from'
30192             });
30193
30194             if (viaNode) {
30195               members.push({
30196                 id: viaNode.id,
30197                 type: 'node',
30198                 role: 'via'
30199               });
30200             } else if (viaWays) {
30201               viaWays.forEach(function (viaWay) {
30202                 members.push({
30203                   id: viaWay.id,
30204                   type: 'way',
30205                   role: 'via'
30206                 });
30207               });
30208             }
30209
30210             members.push({
30211               id: toWay.id,
30212               type: 'way',
30213               role: 'to'
30214             });
30215             return graph.replace(osmRelation({
30216               id: restrictionID,
30217               tags: {
30218                 type: 'restriction',
30219                 restriction: restrictionType
30220               },
30221               members: members
30222             }));
30223           };
30224         }
30225
30226         function actionRevert(id) {
30227           var action = function action(graph) {
30228             var entity = graph.hasEntity(id),
30229                 base = graph.base().entities[id];
30230
30231             if (entity && !base) {
30232               // entity will be removed..
30233               if (entity.type === 'node') {
30234                 graph.parentWays(entity).forEach(function (parent) {
30235                   parent = parent.removeNode(id);
30236                   graph = graph.replace(parent);
30237
30238                   if (parent.isDegenerate()) {
30239                     graph = actionDeleteWay(parent.id)(graph);
30240                   }
30241                 });
30242               }
30243
30244               graph.parentRelations(entity).forEach(function (parent) {
30245                 parent = parent.removeMembersWithID(id);
30246                 graph = graph.replace(parent);
30247
30248                 if (parent.isDegenerate()) {
30249                   graph = actionDeleteRelation(parent.id)(graph);
30250                 }
30251               });
30252             }
30253
30254             return graph.revert(id);
30255           };
30256
30257           return action;
30258         }
30259
30260         function actionRotate(rotateIds, pivot, angle, projection) {
30261           var action = function action(graph) {
30262             return graph.update(function (graph) {
30263               utilGetAllNodes(rotateIds, graph).forEach(function (node) {
30264                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
30265                 graph = graph.replace(node.move(projection.invert(point)));
30266               });
30267             });
30268           };
30269
30270           return action;
30271         }
30272
30273         function actionScale(ids, pivotLoc, scaleFactor, projection) {
30274           return function (graph) {
30275             return graph.update(function (graph) {
30276               var point, radial;
30277               utilGetAllNodes(ids, graph).forEach(function (node) {
30278                 point = projection(node.loc);
30279                 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
30280                 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
30281                 graph = graph.replace(node.move(projection.invert(point)));
30282               });
30283             });
30284           };
30285         }
30286
30287         /* Align nodes along their common axis */
30288
30289         function actionStraightenNodes(nodeIDs, projection) {
30290           function positionAlongWay(a, o, b) {
30291             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30292           } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
30293
30294
30295           function getEndpoints(points) {
30296             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30297             // The shape's surrounding rectangle has 2 axes of symmetry.
30298             // Snap points to the long axis
30299
30300             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30301             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30302             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30303             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30304             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30305
30306             if (isLong) {
30307               return [p1, q1];
30308             }
30309
30310             return [p2, q2];
30311           }
30312
30313           var action = function action(graph, t) {
30314             if (t === null || !isFinite(t)) t = 1;
30315             t = Math.min(Math.max(+t, 0), 1);
30316             var nodes = nodeIDs.map(function (id) {
30317               return graph.entity(id);
30318             });
30319             var points = nodes.map(function (n) {
30320               return projection(n.loc);
30321             });
30322             var endpoints = getEndpoints(points);
30323             var startPoint = endpoints[0];
30324             var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
30325
30326             for (var i = 0; i < points.length; i++) {
30327               var node = nodes[i];
30328               var point = points[i];
30329               var u = positionAlongWay(point, startPoint, endPoint);
30330               var point2 = geoVecInterp(startPoint, endPoint, u);
30331               var loc2 = projection.invert(point2);
30332               graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30333             }
30334
30335             return graph;
30336           };
30337
30338           action.disabled = function (graph) {
30339             var nodes = nodeIDs.map(function (id) {
30340               return graph.entity(id);
30341             });
30342             var points = nodes.map(function (n) {
30343               return projection(n.loc);
30344             });
30345             var endpoints = getEndpoints(points);
30346             var startPoint = endpoints[0];
30347             var endPoint = endpoints[1];
30348             var maxDistance = 0;
30349
30350             for (var i = 0; i < points.length; i++) {
30351               var point = points[i];
30352               var u = positionAlongWay(point, startPoint, endPoint);
30353               var p = geoVecInterp(startPoint, endPoint, u);
30354               var dist = geoVecLength(p, point);
30355
30356               if (!isNaN(dist) && dist > maxDistance) {
30357                 maxDistance = dist;
30358               }
30359             }
30360
30361             if (maxDistance < 0.0001) {
30362               return 'straight_enough';
30363             }
30364           };
30365
30366           action.transitionable = true;
30367           return action;
30368         }
30369
30370         /*
30371          * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
30372          */
30373
30374         function actionStraightenWay(selectedIDs, projection) {
30375           function positionAlongWay(a, o, b) {
30376             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30377           } // Return all selected ways as a continuous, ordered array of nodes
30378
30379
30380           function allNodes(graph) {
30381             var nodes = [];
30382             var startNodes = [];
30383             var endNodes = [];
30384             var remainingWays = [];
30385             var selectedWays = selectedIDs.filter(function (w) {
30386               return graph.entity(w).type === 'way';
30387             });
30388             var selectedNodes = selectedIDs.filter(function (n) {
30389               return graph.entity(n).type === 'node';
30390             });
30391
30392             for (var i = 0; i < selectedWays.length; i++) {
30393               var way = graph.entity(selectedWays[i]);
30394               nodes = way.nodes.slice(0);
30395               remainingWays.push(nodes);
30396               startNodes.push(nodes[0]);
30397               endNodes.push(nodes[nodes.length - 1]);
30398             } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
30399             //   and need to be removed so currNode difference calculation below works)
30400             // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
30401
30402
30403             startNodes = startNodes.filter(function (n) {
30404               return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
30405             });
30406             endNodes = endNodes.filter(function (n) {
30407               return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
30408             }); // Choose the initial endpoint to start from
30409
30410             var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
30411             var nextWay = [];
30412             nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
30413
30414             var getNextWay = function getNextWay(currNode, remainingWays) {
30415               return remainingWays.filter(function (way) {
30416                 return way[0] === currNode || way[way.length - 1] === currNode;
30417               })[0];
30418             }; // Add nodes to end of nodes array, until all ways are added
30419
30420
30421             while (remainingWays.length) {
30422               nextWay = getNextWay(currNode, remainingWays);
30423               remainingWays = utilArrayDifference(remainingWays, [nextWay]);
30424
30425               if (nextWay[0] !== currNode) {
30426                 nextWay.reverse();
30427               }
30428
30429               nodes = nodes.concat(nextWay);
30430               currNode = nodes[nodes.length - 1];
30431             } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
30432
30433
30434             if (selectedNodes.length === 2) {
30435               var startNodeIdx = nodes.indexOf(selectedNodes[0]);
30436               var endNodeIdx = nodes.indexOf(selectedNodes[1]);
30437               var sortedStartEnd = [startNodeIdx, endNodeIdx];
30438               sortedStartEnd.sort(function (a, b) {
30439                 return a - b;
30440               });
30441               nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
30442             }
30443
30444             return nodes.map(function (n) {
30445               return graph.entity(n);
30446             });
30447           }
30448
30449           function shouldKeepNode(node, graph) {
30450             return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
30451           }
30452
30453           var action = function action(graph, t) {
30454             if (t === null || !isFinite(t)) t = 1;
30455             t = Math.min(Math.max(+t, 0), 1);
30456             var nodes = allNodes(graph);
30457             var points = nodes.map(function (n) {
30458               return projection(n.loc);
30459             });
30460             var startPoint = points[0];
30461             var endPoint = points[points.length - 1];
30462             var toDelete = [];
30463             var i;
30464
30465             for (i = 1; i < points.length - 1; i++) {
30466               var node = nodes[i];
30467               var point = points[i];
30468
30469               if (t < 1 || shouldKeepNode(node, graph)) {
30470                 var u = positionAlongWay(point, startPoint, endPoint);
30471                 var p = geoVecInterp(startPoint, endPoint, u);
30472                 var loc2 = projection.invert(p);
30473                 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30474               } else {
30475                 // safe to delete
30476                 if (toDelete.indexOf(node) === -1) {
30477                   toDelete.push(node);
30478                 }
30479               }
30480             }
30481
30482             for (i = 0; i < toDelete.length; i++) {
30483               graph = actionDeleteNode(toDelete[i].id)(graph);
30484             }
30485
30486             return graph;
30487           };
30488
30489           action.disabled = function (graph) {
30490             // check way isn't too bendy
30491             var nodes = allNodes(graph);
30492             var points = nodes.map(function (n) {
30493               return projection(n.loc);
30494             });
30495             var startPoint = points[0];
30496             var endPoint = points[points.length - 1];
30497             var threshold = 0.2 * geoVecLength(startPoint, endPoint);
30498             var i;
30499
30500             if (threshold === 0) {
30501               return 'too_bendy';
30502             }
30503
30504             var maxDistance = 0;
30505
30506             for (i = 1; i < points.length - 1; i++) {
30507               var point = points[i];
30508               var u = positionAlongWay(point, startPoint, endPoint);
30509               var p = geoVecInterp(startPoint, endPoint, u);
30510               var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
30511
30512               if (isNaN(dist) || dist > threshold) {
30513                 return 'too_bendy';
30514               } else if (dist > maxDistance) {
30515                 maxDistance = dist;
30516               }
30517             }
30518
30519             var keepingAllNodes = nodes.every(function (node, i) {
30520               return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
30521             });
30522
30523             if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
30524             keepingAllNodes) {
30525               return 'straight_enough';
30526             }
30527           };
30528
30529           action.transitionable = true;
30530           return action;
30531         }
30532
30533         //
30534         // `turn` must be an `osmTurn` object with a `restrictionID` property.
30535         // see osm/intersection.js, pathToTurn()
30536         //
30537
30538         function actionUnrestrictTurn(turn) {
30539           return function (graph) {
30540             return actionDeleteRelation(turn.restrictionID)(graph);
30541           };
30542         }
30543
30544         /* Reflect the given area around its axis of symmetry */
30545
30546         function actionReflect(reflectIds, projection) {
30547           var _useLongAxis = true;
30548
30549           var action = function action(graph, t) {
30550             if (t === null || !isFinite(t)) t = 1;
30551             t = Math.min(Math.max(+t, 0), 1);
30552             var nodes = utilGetAllNodes(reflectIds, graph);
30553             var points = nodes.map(function (n) {
30554               return projection(n.loc);
30555             });
30556             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30557             // The shape's surrounding rectangle has 2 axes of symmetry.
30558             // Reflect across the longer axis by default.
30559
30560             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30561             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30562             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30563             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30564             var p, q;
30565             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30566
30567             if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
30568               p = p1;
30569               q = q1;
30570             } else {
30571               p = p2;
30572               q = q2;
30573             } // reflect c across pq
30574             // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
30575
30576
30577             var dx = q[0] - p[0];
30578             var dy = q[1] - p[1];
30579             var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
30580             var b = 2 * dx * dy / (dx * dx + dy * dy);
30581
30582             for (var i = 0; i < nodes.length; i++) {
30583               var node = nodes[i];
30584               var c = projection(node.loc);
30585               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]];
30586               var loc2 = projection.invert(c2);
30587               node = node.move(geoVecInterp(node.loc, loc2, t));
30588               graph = graph.replace(node);
30589             }
30590
30591             return graph;
30592           };
30593
30594           action.useLongAxis = function (val) {
30595             if (!arguments.length) return _useLongAxis;
30596             _useLongAxis = val;
30597             return action;
30598           };
30599
30600           action.transitionable = true;
30601           return action;
30602         }
30603
30604         function actionUpgradeTags(entityId, oldTags, replaceTags) {
30605           return function (graph) {
30606             var entity = graph.entity(entityId);
30607             var tags = Object.assign({}, entity.tags); // shallow copy
30608
30609             var transferValue;
30610             var semiIndex;
30611
30612             for (var oldTagKey in oldTags) {
30613               if (!(oldTagKey in tags)) continue; // wildcard match
30614
30615               if (oldTags[oldTagKey] === '*') {
30616                 // note the value since we might need to transfer it
30617                 transferValue = tags[oldTagKey];
30618                 delete tags[oldTagKey]; // exact match
30619               } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
30620                 delete tags[oldTagKey]; // match is within semicolon-delimited values
30621               } else {
30622                 var vals = tags[oldTagKey].split(';').filter(Boolean);
30623                 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
30624
30625                 if (vals.length === 1 || oldIndex === -1) {
30626                   delete tags[oldTagKey];
30627                 } else {
30628                   if (replaceTags && replaceTags[oldTagKey]) {
30629                     // replacing a value within a semicolon-delimited value, note the index
30630                     semiIndex = oldIndex;
30631                   }
30632
30633                   vals.splice(oldIndex, 1);
30634                   tags[oldTagKey] = vals.join(';');
30635                 }
30636               }
30637             }
30638
30639             if (replaceTags) {
30640               for (var replaceKey in replaceTags) {
30641                 var replaceValue = replaceTags[replaceKey];
30642
30643                 if (replaceValue === '*') {
30644                   if (tags[replaceKey] && tags[replaceKey] !== 'no') {
30645                     // allow any pre-existing value except `no` (troll tag)
30646                     continue;
30647                   } else {
30648                     // otherwise assume `yes` is okay
30649                     tags[replaceKey] = 'yes';
30650                   }
30651                 } else if (replaceValue === '$1') {
30652                   tags[replaceKey] = transferValue;
30653                 } else {
30654                   if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
30655                     // don't override preexisting values
30656                     var existingVals = tags[replaceKey].split(';').filter(Boolean);
30657
30658                     if (existingVals.indexOf(replaceValue) === -1) {
30659                       existingVals.splice(semiIndex, 0, replaceValue);
30660                       tags[replaceKey] = existingVals.join(';');
30661                     }
30662                   } else {
30663                     tags[replaceKey] = replaceValue;
30664                   }
30665                 }
30666               }
30667             }
30668
30669             return graph.replace(entity.update({
30670               tags: tags
30671             }));
30672           };
30673         }
30674
30675         function behaviorEdit(context) {
30676           function behavior() {
30677             context.map().minzoom(context.minEditableZoom());
30678           }
30679
30680           behavior.off = function () {
30681             context.map().minzoom(0);
30682           };
30683
30684           return behavior;
30685         }
30686
30687         /*
30688            The hover behavior adds the `.hover` class on pointerover to all elements to which
30689            the identical datum is bound, and removes it on pointerout.
30690
30691            The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
30692            representation may consist of several elements scattered throughout the DOM hierarchy.
30693            Only one of these elements can have the :hover pseudo-class, but all of them will
30694            have the .hover class.
30695          */
30696
30697         function behaviorHover(context) {
30698           var dispatch$1 = dispatch('hover');
30699
30700           var _selection = select(null);
30701
30702           var _newNodeId = null;
30703           var _initialNodeID = null;
30704
30705           var _altDisables;
30706
30707           var _ignoreVertex;
30708
30709           var _targets = []; // use pointer events on supported platforms; fallback to mouse events
30710
30711           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
30712
30713           function keydown(d3_event) {
30714             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30715               _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
30716
30717               _selection.classed('hover-disabled', true);
30718
30719               dispatch$1.call('hover', this, null);
30720             }
30721           }
30722
30723           function keyup(d3_event) {
30724             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30725               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
30726
30727               _selection.classed('hover-disabled', false);
30728
30729               dispatch$1.call('hover', this, _targets);
30730             }
30731           }
30732
30733           function behavior(selection) {
30734             _selection = selection;
30735             _targets = [];
30736
30737             if (_initialNodeID) {
30738               _newNodeId = _initialNodeID;
30739               _initialNodeID = null;
30740             } else {
30741               _newNodeId = null;
30742             }
30743
30744             _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
30745             .on(_pointerPrefix + 'down.hover', pointerover);
30746
30747             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
30748
30749             function eventTarget(d3_event) {
30750               var datum = d3_event.target && d3_event.target.__data__;
30751               if (_typeof(datum) !== 'object') return null;
30752
30753               if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
30754                 return datum.properties.entity;
30755               }
30756
30757               return datum;
30758             }
30759
30760             function pointerover(d3_event) {
30761               // ignore mouse hovers with buttons pressed unless dragging
30762               if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
30763               var target = eventTarget(d3_event);
30764
30765               if (target && _targets.indexOf(target) === -1) {
30766                 _targets.push(target);
30767
30768                 updateHover(d3_event, _targets);
30769               }
30770             }
30771
30772             function pointerout(d3_event) {
30773               var target = eventTarget(d3_event);
30774
30775               var index = _targets.indexOf(target);
30776
30777               if (index !== -1) {
30778                 _targets.splice(index);
30779
30780                 updateHover(d3_event, _targets);
30781               }
30782             }
30783
30784             function allowsVertex(d) {
30785               return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30786             }
30787
30788             function modeAllowsHover(target) {
30789               var mode = context.mode();
30790
30791               if (mode.id === 'add-point') {
30792                 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
30793               }
30794
30795               return true;
30796             }
30797
30798             function updateHover(d3_event, targets) {
30799               _selection.selectAll('.hover').classed('hover', false);
30800
30801               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30802
30803               var mode = context.mode();
30804
30805               if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
30806                 var node = targets.find(function (target) {
30807                   return target instanceof osmEntity && target.type === 'node';
30808                 });
30809                 _newNodeId = node && node.id;
30810               }
30811
30812               targets = targets.filter(function (datum) {
30813                 if (datum instanceof osmEntity) {
30814                   // If drawing a way, don't hover on a node that was just placed. #3974
30815                   return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
30816                 }
30817
30818                 return true;
30819               });
30820               var selector = '';
30821
30822               for (var i in targets) {
30823                 var datum = targets[i]; // What are we hovering over?
30824
30825                 if (datum.__featurehash__) {
30826                   // hovering custom data
30827                   selector += ', .data' + datum.__featurehash__;
30828                 } else if (datum instanceof QAItem) {
30829                   selector += ', .' + datum.service + '.itemId-' + datum.id;
30830                 } else if (datum instanceof osmNote) {
30831                   selector += ', .note-' + datum.id;
30832                 } else if (datum instanceof osmEntity) {
30833                   selector += ', .' + datum.id;
30834
30835                   if (datum.type === 'relation') {
30836                     for (var j in datum.members) {
30837                       selector += ', .' + datum.members[j].id;
30838                     }
30839                   }
30840                 }
30841               }
30842
30843               var suppressed = _altDisables && d3_event && d3_event.altKey;
30844
30845               if (selector.trim().length) {
30846                 // remove the first comma
30847                 selector = selector.slice(1);
30848
30849                 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
30850               }
30851
30852               dispatch$1.call('hover', this, !suppressed && targets);
30853             }
30854           }
30855
30856           behavior.off = function (selection) {
30857             selection.selectAll('.hover').classed('hover', false);
30858             selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30859             selection.classed('hover-disabled', false);
30860             selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
30861             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
30862           };
30863
30864           behavior.altDisables = function (val) {
30865             if (!arguments.length) return _altDisables;
30866             _altDisables = val;
30867             return behavior;
30868           };
30869
30870           behavior.ignoreVertex = function (val) {
30871             if (!arguments.length) return _ignoreVertex;
30872             _ignoreVertex = val;
30873             return behavior;
30874           };
30875
30876           behavior.initialNodeID = function (nodeId) {
30877             _initialNodeID = nodeId;
30878             return behavior;
30879           };
30880
30881           return utilRebind(behavior, dispatch$1, 'on');
30882         }
30883
30884         var _disableSpace = false;
30885         var _lastSpace = null;
30886         function behaviorDraw(context) {
30887           var dispatch$1 = dispatch('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
30888           var keybinding = utilKeybinding('draw');
30889
30890           var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
30891
30892           var _edit = behaviorEdit(context);
30893
30894           var _closeTolerance = 4;
30895           var _tolerance = 12;
30896           var _mouseLeave = false;
30897           var _lastMouse = null;
30898
30899           var _lastPointerUpEvent;
30900
30901           var _downPointer; // use pointer events on supported platforms; fallback to mouse events
30902
30903
30904           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
30905           // - `mode/drag_node.js` `datum()`
30906
30907
30908           function datum(d3_event) {
30909             var mode = context.mode();
30910             var isNote = mode && mode.id.indexOf('note') !== -1;
30911             if (d3_event.altKey || isNote) return {};
30912             var element;
30913
30914             if (d3_event.type === 'keydown') {
30915               element = _lastMouse && _lastMouse.target;
30916             } else {
30917               element = d3_event.target;
30918             } // When drawing, snap only to touch targets..
30919             // (this excludes area fills and active drawing elements)
30920
30921
30922             var d = element.__data__;
30923             return d && d.properties && d.properties.target ? d : {};
30924           }
30925
30926           function pointerdown(d3_event) {
30927             if (_downPointer) return;
30928             var pointerLocGetter = utilFastMouse(this);
30929             _downPointer = {
30930               id: d3_event.pointerId || 'mouse',
30931               pointerLocGetter: pointerLocGetter,
30932               downTime: +new Date(),
30933               downLoc: pointerLocGetter(d3_event)
30934             };
30935             dispatch$1.call('down', this, d3_event, datum(d3_event));
30936           }
30937
30938           function pointerup(d3_event) {
30939             if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
30940             var downPointer = _downPointer;
30941             _downPointer = null;
30942             _lastPointerUpEvent = d3_event;
30943             if (downPointer.isCancelled) return;
30944             var t2 = +new Date();
30945             var p2 = downPointer.pointerLocGetter(d3_event);
30946             var dist = geoVecLength(downPointer.downLoc, p2);
30947
30948             if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
30949               // Prevent a quick second click
30950               select(window).on('click.draw-block', function () {
30951                 d3_event.stopPropagation();
30952               }, true);
30953               context.map().dblclickZoomEnable(false);
30954               window.setTimeout(function () {
30955                 context.map().dblclickZoomEnable(true);
30956                 select(window).on('click.draw-block', null);
30957               }, 500);
30958               click(d3_event, p2);
30959             }
30960           }
30961
30962           function pointermove(d3_event) {
30963             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
30964               var p2 = _downPointer.pointerLocGetter(d3_event);
30965
30966               var dist = geoVecLength(_downPointer.downLoc, p2);
30967
30968               if (dist >= _closeTolerance) {
30969                 _downPointer.isCancelled = true;
30970                 dispatch$1.call('downcancel', this);
30971               }
30972             }
30973
30974             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
30975             // events immediately after non-mouse pointerup events; detect and ignore them.
30976
30977             if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
30978             _lastMouse = d3_event;
30979             dispatch$1.call('move', this, d3_event, datum(d3_event));
30980           }
30981
30982           function pointercancel(d3_event) {
30983             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
30984               if (!_downPointer.isCancelled) {
30985                 dispatch$1.call('downcancel', this);
30986               }
30987
30988               _downPointer = null;
30989             }
30990           }
30991
30992           function mouseenter() {
30993             _mouseLeave = false;
30994           }
30995
30996           function mouseleave() {
30997             _mouseLeave = true;
30998           }
30999
31000           function allowsVertex(d) {
31001             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
31002           } // related code
31003           // - `mode/drag_node.js`     `doMove()`
31004           // - `behavior/draw.js`      `click()`
31005           // - `behavior/draw_way.js`  `move()`
31006
31007
31008           function click(d3_event, loc) {
31009             var d = datum(d3_event);
31010             var target = d && d.properties && d.properties.entity;
31011             var mode = context.mode();
31012
31013             if (target && target.type === 'node' && allowsVertex(target)) {
31014               // Snap to a node
31015               dispatch$1.call('clickNode', this, target, d);
31016               return;
31017             } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
31018               // Snap to a way
31019               var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
31020
31021               if (choice) {
31022                 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
31023                 dispatch$1.call('clickWay', this, choice.loc, edge, d);
31024                 return;
31025               }
31026             } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
31027               var locLatLng = context.projection.invert(loc);
31028               dispatch$1.call('click', this, locLatLng, d);
31029             }
31030           } // treat a spacebar press like a click
31031
31032
31033           function space(d3_event) {
31034             d3_event.preventDefault();
31035             d3_event.stopPropagation();
31036             var currSpace = context.map().mouse();
31037
31038             if (_disableSpace && _lastSpace) {
31039               var dist = geoVecLength(_lastSpace, currSpace);
31040
31041               if (dist > _tolerance) {
31042                 _disableSpace = false;
31043               }
31044             }
31045
31046             if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
31047
31048             _lastSpace = currSpace;
31049             _disableSpace = true;
31050             select(window).on('keyup.space-block', function () {
31051               d3_event.preventDefault();
31052               d3_event.stopPropagation();
31053               _disableSpace = false;
31054               select(window).on('keyup.space-block', null);
31055             }); // get the current mouse position
31056
31057             var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
31058             context.projection(context.map().center());
31059             click(d3_event, loc);
31060           }
31061
31062           function backspace(d3_event) {
31063             d3_event.preventDefault();
31064             dispatch$1.call('undo');
31065           }
31066
31067           function del(d3_event) {
31068             d3_event.preventDefault();
31069             dispatch$1.call('cancel');
31070           }
31071
31072           function ret(d3_event) {
31073             d3_event.preventDefault();
31074             dispatch$1.call('finish');
31075           }
31076
31077           function behavior(selection) {
31078             context.install(_hover);
31079             context.install(_edit);
31080             _downPointer = null;
31081             keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
31082             selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
31083             select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
31084             select(document).call(keybinding);
31085             return behavior;
31086           }
31087
31088           behavior.off = function (selection) {
31089             context.ui().sidebar.hover.cancel();
31090             context.uninstall(_hover);
31091             context.uninstall(_edit);
31092             selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
31093             select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
31094
31095             select(document).call(keybinding.unbind);
31096           };
31097
31098           behavior.hover = function () {
31099             return _hover;
31100           };
31101
31102           return utilRebind(behavior, dispatch$1, 'on');
31103         }
31104
31105         function initRange(domain, range) {
31106           switch (arguments.length) {
31107             case 0:
31108               break;
31109
31110             case 1:
31111               this.range(domain);
31112               break;
31113
31114             default:
31115               this.range(range).domain(domain);
31116               break;
31117           }
31118
31119           return this;
31120         }
31121
31122         function constants(x) {
31123           return function () {
31124             return x;
31125           };
31126         }
31127
31128         function number$1(x) {
31129           return +x;
31130         }
31131
31132         var unit = [0, 1];
31133         function identity$3(x) {
31134           return x;
31135         }
31136
31137         function normalize$1(a, b) {
31138           return (b -= a = +a) ? function (x) {
31139             return (x - a) / b;
31140           } : constants(isNaN(b) ? NaN : 0.5);
31141         }
31142
31143         function clamper(a, b) {
31144           var t;
31145           if (a > b) t = a, a = b, b = t;
31146           return function (x) {
31147             return Math.max(a, Math.min(b, x));
31148           };
31149         } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
31150         // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
31151
31152
31153         function bimap(domain, range, interpolate) {
31154           var d0 = domain[0],
31155               d1 = domain[1],
31156               r0 = range[0],
31157               r1 = range[1];
31158           if (d1 < d0) d0 = normalize$1(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize$1(d0, d1), r0 = interpolate(r0, r1);
31159           return function (x) {
31160             return r0(d0(x));
31161           };
31162         }
31163
31164         function polymap(domain, range, interpolate) {
31165           var j = Math.min(domain.length, range.length) - 1,
31166               d = new Array(j),
31167               r = new Array(j),
31168               i = -1; // Reverse descending domains.
31169
31170           if (domain[j] < domain[0]) {
31171             domain = domain.slice().reverse();
31172             range = range.slice().reverse();
31173           }
31174
31175           while (++i < j) {
31176             d[i] = normalize$1(domain[i], domain[i + 1]);
31177             r[i] = interpolate(range[i], range[i + 1]);
31178           }
31179
31180           return function (x) {
31181             var i = bisectRight(domain, x, 1, j) - 1;
31182             return r[i](d[i](x));
31183           };
31184         }
31185
31186         function copy(source, target) {
31187           return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
31188         }
31189         function transformer$1() {
31190           var domain = unit,
31191               range = unit,
31192               interpolate$1 = interpolate,
31193               transform,
31194               untransform,
31195               unknown,
31196               clamp = identity$3,
31197               piecewise,
31198               output,
31199               input;
31200
31201           function rescale() {
31202             var n = Math.min(domain.length, range.length);
31203             if (clamp !== identity$3) clamp = clamper(domain[0], domain[n - 1]);
31204             piecewise = n > 2 ? polymap : bimap;
31205             output = input = null;
31206             return scale;
31207           }
31208
31209           function scale(x) {
31210             return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate$1)))(transform(clamp(x)));
31211           }
31212
31213           scale.invert = function (y) {
31214             return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
31215           };
31216
31217           scale.domain = function (_) {
31218             return arguments.length ? (domain = Array.from(_, number$1), rescale()) : domain.slice();
31219           };
31220
31221           scale.range = function (_) {
31222             return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
31223           };
31224
31225           scale.rangeRound = function (_) {
31226             return range = Array.from(_), interpolate$1 = interpolateRound, rescale();
31227           };
31228
31229           scale.clamp = function (_) {
31230             return arguments.length ? (clamp = _ ? true : identity$3, rescale()) : clamp !== identity$3;
31231           };
31232
31233           scale.interpolate = function (_) {
31234             return arguments.length ? (interpolate$1 = _, rescale()) : interpolate$1;
31235           };
31236
31237           scale.unknown = function (_) {
31238             return arguments.length ? (unknown = _, scale) : unknown;
31239           };
31240
31241           return function (t, u) {
31242             transform = t, untransform = u;
31243             return rescale();
31244           };
31245         }
31246         function continuous() {
31247           return transformer$1()(identity$3, identity$3);
31248         }
31249
31250         function formatDecimal (x) {
31251           return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
31252         } // Computes the decimal coefficient and exponent of the specified number x with
31253         // significant digits p, where x is positive and p is in [1, 21] or undefined.
31254         // For example, formatDecimalParts(1.23) returns ["123", 0].
31255
31256         function formatDecimalParts(x, p) {
31257           if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
31258
31259           var i,
31260               coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
31261           // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
31262
31263           return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
31264         }
31265
31266         function exponent (x) {
31267           return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
31268         }
31269
31270         function formatGroup (grouping, thousands) {
31271           return function (value, width) {
31272             var i = value.length,
31273                 t = [],
31274                 j = 0,
31275                 g = grouping[0],
31276                 length = 0;
31277
31278             while (i > 0 && g > 0) {
31279               if (length + g + 1 > width) g = Math.max(1, width - length);
31280               t.push(value.substring(i -= g, i + g));
31281               if ((length += g + 1) > width) break;
31282               g = grouping[j = (j + 1) % grouping.length];
31283             }
31284
31285             return t.reverse().join(thousands);
31286           };
31287         }
31288
31289         function formatNumerals (numerals) {
31290           return function (value) {
31291             return value.replace(/[0-9]/g, function (i) {
31292               return numerals[+i];
31293             });
31294           };
31295         }
31296
31297         // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
31298         var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
31299         function formatSpecifier(specifier) {
31300           if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
31301           var match;
31302           return new FormatSpecifier({
31303             fill: match[1],
31304             align: match[2],
31305             sign: match[3],
31306             symbol: match[4],
31307             zero: match[5],
31308             width: match[6],
31309             comma: match[7],
31310             precision: match[8] && match[8].slice(1),
31311             trim: match[9],
31312             type: match[10]
31313           });
31314         }
31315         formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
31316
31317         function FormatSpecifier(specifier) {
31318           this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
31319           this.align = specifier.align === undefined ? ">" : specifier.align + "";
31320           this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
31321           this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
31322           this.zero = !!specifier.zero;
31323           this.width = specifier.width === undefined ? undefined : +specifier.width;
31324           this.comma = !!specifier.comma;
31325           this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
31326           this.trim = !!specifier.trim;
31327           this.type = specifier.type === undefined ? "" : specifier.type + "";
31328         }
31329
31330         FormatSpecifier.prototype.toString = function () {
31331           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;
31332         };
31333
31334         // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
31335         function formatTrim (s) {
31336           out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
31337             switch (s[i]) {
31338               case ".":
31339                 i0 = i1 = i;
31340                 break;
31341
31342               case "0":
31343                 if (i0 === 0) i0 = i;
31344                 i1 = i;
31345                 break;
31346
31347               default:
31348                 if (!+s[i]) break out;
31349                 if (i0 > 0) i0 = 0;
31350                 break;
31351             }
31352           }
31353
31354           return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
31355         }
31356
31357         // `thisNumberValue` abstract operation
31358         // https://tc39.es/ecma262/#sec-thisnumbervalue
31359         var thisNumberValue = function (value) {
31360           if (typeof value != 'number' && classofRaw(value) != 'Number') {
31361             throw TypeError('Incorrect invocation');
31362           }
31363           return +value;
31364         };
31365
31366         // `String.prototype.repeat` method implementation
31367         // https://tc39.es/ecma262/#sec-string.prototype.repeat
31368         var stringRepeat = ''.repeat || function repeat(count) {
31369           var str = String(requireObjectCoercible(this));
31370           var result = '';
31371           var n = toInteger(count);
31372           if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
31373           for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
31374           return result;
31375         };
31376
31377         var nativeToFixed = 1.0.toFixed;
31378         var floor$6 = Math.floor;
31379
31380         var pow$2 = function (x, n, acc) {
31381           return n === 0 ? acc : n % 2 === 1 ? pow$2(x, n - 1, acc * x) : pow$2(x * x, n / 2, acc);
31382         };
31383
31384         var log$2 = function (x) {
31385           var n = 0;
31386           var x2 = x;
31387           while (x2 >= 4096) {
31388             n += 12;
31389             x2 /= 4096;
31390           }
31391           while (x2 >= 2) {
31392             n += 1;
31393             x2 /= 2;
31394           } return n;
31395         };
31396
31397         var multiply = function (data, n, c) {
31398           var index = -1;
31399           var c2 = c;
31400           while (++index < 6) {
31401             c2 += n * data[index];
31402             data[index] = c2 % 1e7;
31403             c2 = floor$6(c2 / 1e7);
31404           }
31405         };
31406
31407         var divide = function (data, n) {
31408           var index = 6;
31409           var c = 0;
31410           while (--index >= 0) {
31411             c += data[index];
31412             data[index] = floor$6(c / n);
31413             c = (c % n) * 1e7;
31414           }
31415         };
31416
31417         var dataToString = function (data) {
31418           var index = 6;
31419           var s = '';
31420           while (--index >= 0) {
31421             if (s !== '' || index === 0 || data[index] !== 0) {
31422               var t = String(data[index]);
31423               s = s === '' ? t : s + stringRepeat.call('0', 7 - t.length) + t;
31424             }
31425           } return s;
31426         };
31427
31428         var FORCED$c = nativeToFixed && (
31429           0.00008.toFixed(3) !== '0.000' ||
31430           0.9.toFixed(0) !== '1' ||
31431           1.255.toFixed(2) !== '1.25' ||
31432           1000000000000000128.0.toFixed(0) !== '1000000000000000128'
31433         ) || !fails(function () {
31434           // V8 ~ Android 4.3-
31435           nativeToFixed.call({});
31436         });
31437
31438         // `Number.prototype.toFixed` method
31439         // https://tc39.es/ecma262/#sec-number.prototype.tofixed
31440         _export({ target: 'Number', proto: true, forced: FORCED$c }, {
31441           toFixed: function toFixed(fractionDigits) {
31442             var number = thisNumberValue(this);
31443             var fractDigits = toInteger(fractionDigits);
31444             var data = [0, 0, 0, 0, 0, 0];
31445             var sign = '';
31446             var result = '0';
31447             var e, z, j, k;
31448
31449             if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
31450             // eslint-disable-next-line no-self-compare -- NaN check
31451             if (number != number) return 'NaN';
31452             if (number <= -1e21 || number >= 1e21) return String(number);
31453             if (number < 0) {
31454               sign = '-';
31455               number = -number;
31456             }
31457             if (number > 1e-21) {
31458               e = log$2(number * pow$2(2, 69, 1)) - 69;
31459               z = e < 0 ? number * pow$2(2, -e, 1) : number / pow$2(2, e, 1);
31460               z *= 0x10000000000000;
31461               e = 52 - e;
31462               if (e > 0) {
31463                 multiply(data, 0, z);
31464                 j = fractDigits;
31465                 while (j >= 7) {
31466                   multiply(data, 1e7, 0);
31467                   j -= 7;
31468                 }
31469                 multiply(data, pow$2(10, j, 1), 0);
31470                 j = e - 1;
31471                 while (j >= 23) {
31472                   divide(data, 1 << 23);
31473                   j -= 23;
31474                 }
31475                 divide(data, 1 << j);
31476                 multiply(data, 1, 1);
31477                 divide(data, 2);
31478                 result = dataToString(data);
31479               } else {
31480                 multiply(data, 0, z);
31481                 multiply(data, 1 << -e, 0);
31482                 result = dataToString(data) + stringRepeat.call('0', fractDigits);
31483               }
31484             }
31485             if (fractDigits > 0) {
31486               k = result.length;
31487               result = sign + (k <= fractDigits
31488                 ? '0.' + stringRepeat.call('0', fractDigits - k) + result
31489                 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
31490             } else {
31491               result = sign + result;
31492             } return result;
31493           }
31494         });
31495
31496         var nativeToPrecision = 1.0.toPrecision;
31497
31498         var FORCED$d = fails(function () {
31499           // IE7-
31500           return nativeToPrecision.call(1, undefined) !== '1';
31501         }) || !fails(function () {
31502           // V8 ~ Android 4.3-
31503           nativeToPrecision.call({});
31504         });
31505
31506         // `Number.prototype.toPrecision` method
31507         // https://tc39.es/ecma262/#sec-number.prototype.toprecision
31508         _export({ target: 'Number', proto: true, forced: FORCED$d }, {
31509           toPrecision: function toPrecision(precision) {
31510             return precision === undefined
31511               ? nativeToPrecision.call(thisNumberValue(this))
31512               : nativeToPrecision.call(thisNumberValue(this), precision);
31513           }
31514         });
31515
31516         var prefixExponent;
31517         function formatPrefixAuto (x, p) {
31518           var d = formatDecimalParts(x, p);
31519           if (!d) return x + "";
31520           var coefficient = d[0],
31521               exponent = d[1],
31522               i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
31523               n = coefficient.length;
31524           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!
31525         }
31526
31527         function formatRounded (x, p) {
31528           var d = formatDecimalParts(x, p);
31529           if (!d) return x + "";
31530           var coefficient = d[0],
31531               exponent = d[1];
31532           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");
31533         }
31534
31535         var formatTypes = {
31536           "%": function _(x, p) {
31537             return (x * 100).toFixed(p);
31538           },
31539           "b": function b(x) {
31540             return Math.round(x).toString(2);
31541           },
31542           "c": function c(x) {
31543             return x + "";
31544           },
31545           "d": formatDecimal,
31546           "e": function e(x, p) {
31547             return x.toExponential(p);
31548           },
31549           "f": function f(x, p) {
31550             return x.toFixed(p);
31551           },
31552           "g": function g(x, p) {
31553             return x.toPrecision(p);
31554           },
31555           "o": function o(x) {
31556             return Math.round(x).toString(8);
31557           },
31558           "p": function p(x, _p) {
31559             return formatRounded(x * 100, _p);
31560           },
31561           "r": formatRounded,
31562           "s": formatPrefixAuto,
31563           "X": function X(x) {
31564             return Math.round(x).toString(16).toUpperCase();
31565           },
31566           "x": function x(_x) {
31567             return Math.round(_x).toString(16);
31568           }
31569         };
31570
31571         function identity$4 (x) {
31572           return x;
31573         }
31574
31575         var map = Array.prototype.map,
31576             prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
31577         function formatLocale (locale) {
31578           var group = locale.grouping === undefined || locale.thousands === undefined ? identity$4 : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
31579               currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
31580               currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
31581               decimal = locale.decimal === undefined ? "." : locale.decimal + "",
31582               numerals = locale.numerals === undefined ? identity$4 : formatNumerals(map.call(locale.numerals, String)),
31583               percent = locale.percent === undefined ? "%" : locale.percent + "",
31584               minus = locale.minus === undefined ? "−" : locale.minus + "",
31585               nan = locale.nan === undefined ? "NaN" : locale.nan + "";
31586
31587           function newFormat(specifier) {
31588             specifier = formatSpecifier(specifier);
31589             var fill = specifier.fill,
31590                 align = specifier.align,
31591                 sign = specifier.sign,
31592                 symbol = specifier.symbol,
31593                 zero = specifier.zero,
31594                 width = specifier.width,
31595                 comma = specifier.comma,
31596                 precision = specifier.precision,
31597                 trim = specifier.trim,
31598                 type = specifier.type; // The "n" type is an alias for ",g".
31599
31600             if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
31601             else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
31602
31603             if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
31604             // For SI-prefix, the suffix is lazily computed.
31605
31606             var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
31607                 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
31608             // Is this an integer type?
31609             // Can this type generate exponential notation?
31610
31611             var formatType = formatTypes[type],
31612                 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
31613             // or clamp the specified precision to the supported range.
31614             // For significant precision, it must be in [1, 21].
31615             // For fixed precision, it must be in [0, 20].
31616
31617             precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
31618
31619             function format(value) {
31620               var valuePrefix = prefix,
31621                   valueSuffix = suffix,
31622                   i,
31623                   n,
31624                   c;
31625
31626               if (type === "c") {
31627                 valueSuffix = formatType(value) + valueSuffix;
31628                 value = "";
31629               } else {
31630                 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
31631
31632                 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
31633
31634                 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
31635
31636                 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
31637
31638                 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
31639
31640                 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
31641                 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
31642                 // grouped, and fractional or exponential “suffix” part that is not.
31643
31644                 if (maybeSuffix) {
31645                   i = -1, n = value.length;
31646
31647                   while (++i < n) {
31648                     if (c = value.charCodeAt(i), 48 > c || c > 57) {
31649                       valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
31650                       value = value.slice(0, i);
31651                       break;
31652                     }
31653                   }
31654                 }
31655               } // If the fill character is not "0", grouping is applied before padding.
31656
31657
31658               if (comma && !zero) value = group(value, Infinity); // Compute the padding.
31659
31660               var length = valuePrefix.length + value.length + valueSuffix.length,
31661                   padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
31662
31663               if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
31664
31665               switch (align) {
31666                 case "<":
31667                   value = valuePrefix + value + valueSuffix + padding;
31668                   break;
31669
31670                 case "=":
31671                   value = valuePrefix + padding + value + valueSuffix;
31672                   break;
31673
31674                 case "^":
31675                   value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
31676                   break;
31677
31678                 default:
31679                   value = padding + valuePrefix + value + valueSuffix;
31680                   break;
31681               }
31682
31683               return numerals(value);
31684             }
31685
31686             format.toString = function () {
31687               return specifier + "";
31688             };
31689
31690             return format;
31691           }
31692
31693           function formatPrefix(specifier, value) {
31694             var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
31695                 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
31696                 k = Math.pow(10, -e),
31697                 prefix = prefixes[8 + e / 3];
31698             return function (value) {
31699               return f(k * value) + prefix;
31700             };
31701           }
31702
31703           return {
31704             format: newFormat,
31705             formatPrefix: formatPrefix
31706           };
31707         }
31708
31709         var locale;
31710         var format;
31711         var formatPrefix;
31712         defaultLocale({
31713           thousands: ",",
31714           grouping: [3],
31715           currency: ["$", ""]
31716         });
31717         function defaultLocale(definition) {
31718           locale = formatLocale(definition);
31719           format = locale.format;
31720           formatPrefix = locale.formatPrefix;
31721           return locale;
31722         }
31723
31724         function precisionFixed (step) {
31725           return Math.max(0, -exponent(Math.abs(step)));
31726         }
31727
31728         function precisionPrefix (step, value) {
31729           return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
31730         }
31731
31732         function precisionRound (step, max) {
31733           step = Math.abs(step), max = Math.abs(max) - step;
31734           return Math.max(0, exponent(max) - exponent(step)) + 1;
31735         }
31736
31737         function tickFormat(start, stop, count, specifier) {
31738           var step = tickStep(start, stop, count),
31739               precision;
31740           specifier = formatSpecifier(specifier == null ? ",f" : specifier);
31741
31742           switch (specifier.type) {
31743             case "s":
31744               {
31745                 var value = Math.max(Math.abs(start), Math.abs(stop));
31746                 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
31747                 return formatPrefix(specifier, value);
31748               }
31749
31750             case "":
31751             case "e":
31752             case "g":
31753             case "p":
31754             case "r":
31755               {
31756                 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
31757                 break;
31758               }
31759
31760             case "f":
31761             case "%":
31762               {
31763                 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
31764                 break;
31765               }
31766           }
31767
31768           return format(specifier);
31769         }
31770
31771         function linearish(scale) {
31772           var domain = scale.domain;
31773
31774           scale.ticks = function (count) {
31775             var d = domain();
31776             return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
31777           };
31778
31779           scale.tickFormat = function (count, specifier) {
31780             var d = domain();
31781             return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
31782           };
31783
31784           scale.nice = function (count) {
31785             if (count == null) count = 10;
31786             var d = domain();
31787             var i0 = 0;
31788             var i1 = d.length - 1;
31789             var start = d[i0];
31790             var stop = d[i1];
31791             var prestep;
31792             var step;
31793             var maxIter = 10;
31794
31795             if (stop < start) {
31796               step = start, start = stop, stop = step;
31797               step = i0, i0 = i1, i1 = step;
31798             }
31799
31800             while (maxIter-- > 0) {
31801               step = tickIncrement(start, stop, count);
31802
31803               if (step === prestep) {
31804                 d[i0] = start;
31805                 d[i1] = stop;
31806                 return domain(d);
31807               } else if (step > 0) {
31808                 start = Math.floor(start / step) * step;
31809                 stop = Math.ceil(stop / step) * step;
31810               } else if (step < 0) {
31811                 start = Math.ceil(start * step) / step;
31812                 stop = Math.floor(stop * step) / step;
31813               } else {
31814                 break;
31815               }
31816
31817               prestep = step;
31818             }
31819
31820             return scale;
31821           };
31822
31823           return scale;
31824         }
31825         function linear$2() {
31826           var scale = continuous();
31827
31828           scale.copy = function () {
31829             return copy(scale, linear$2());
31830           };
31831
31832           initRange.apply(scale, arguments);
31833           return linearish(scale);
31834         }
31835
31836         var nativeExpm1 = Math.expm1;
31837         var exp$1 = Math.exp;
31838
31839         // `Math.expm1` method implementation
31840         // https://tc39.es/ecma262/#sec-math.expm1
31841         var mathExpm1 = (!nativeExpm1
31842           // Old FF bug
31843           || nativeExpm1(10) > 22025.465794806719 || nativeExpm1(10) < 22025.4657948067165168
31844           // Tor Browser bug
31845           || nativeExpm1(-2e-17) != -2e-17
31846         ) ? function expm1(x) {
31847           return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
31848         } : nativeExpm1;
31849
31850         function quantize() {
31851           var x0 = 0,
31852               x1 = 1,
31853               n = 1,
31854               domain = [0.5],
31855               range = [0, 1],
31856               unknown;
31857
31858           function scale(x) {
31859             return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
31860           }
31861
31862           function rescale() {
31863             var i = -1;
31864             domain = new Array(n);
31865
31866             while (++i < n) {
31867               domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31868             }
31869
31870             return scale;
31871           }
31872
31873           scale.domain = function (_) {
31874             var _ref, _ref2;
31875
31876             return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
31877           };
31878
31879           scale.range = function (_) {
31880             return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
31881           };
31882
31883           scale.invertExtent = function (y) {
31884             var i = range.indexOf(y);
31885             return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
31886           };
31887
31888           scale.unknown = function (_) {
31889             return arguments.length ? (unknown = _, scale) : scale;
31890           };
31891
31892           scale.thresholds = function () {
31893             return domain.slice();
31894           };
31895
31896           scale.copy = function () {
31897             return quantize().domain([x0, x1]).range(range).unknown(unknown);
31898           };
31899
31900           return initRange.apply(linearish(scale), arguments);
31901         }
31902
31903         // https://github.com/tc39/proposal-string-pad-start-end
31904
31905
31906
31907
31908         var ceil$1 = Math.ceil;
31909
31910         // `String.prototype.{ padStart, padEnd }` methods implementation
31911         var createMethod$6 = function (IS_END) {
31912           return function ($this, maxLength, fillString) {
31913             var S = String(requireObjectCoercible($this));
31914             var stringLength = S.length;
31915             var fillStr = fillString === undefined ? ' ' : String(fillString);
31916             var intMaxLength = toLength(maxLength);
31917             var fillLen, stringFiller;
31918             if (intMaxLength <= stringLength || fillStr == '') return S;
31919             fillLen = intMaxLength - stringLength;
31920             stringFiller = stringRepeat.call(fillStr, ceil$1(fillLen / fillStr.length));
31921             if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
31922             return IS_END ? S + stringFiller : stringFiller + S;
31923           };
31924         };
31925
31926         var stringPad = {
31927           // `String.prototype.padStart` method
31928           // https://tc39.es/ecma262/#sec-string.prototype.padstart
31929           start: createMethod$6(false),
31930           // `String.prototype.padEnd` method
31931           // https://tc39.es/ecma262/#sec-string.prototype.padend
31932           end: createMethod$6(true)
31933         };
31934
31935         var padStart = stringPad.start;
31936
31937         var abs$3 = Math.abs;
31938         var DatePrototype$1 = Date.prototype;
31939         var getTime$1 = DatePrototype$1.getTime;
31940         var nativeDateToISOString = DatePrototype$1.toISOString;
31941
31942         // `Date.prototype.toISOString` method implementation
31943         // https://tc39.es/ecma262/#sec-date.prototype.toisostring
31944         // PhantomJS / old WebKit fails here:
31945         var dateToIsoString = (fails(function () {
31946           return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
31947         }) || !fails(function () {
31948           nativeDateToISOString.call(new Date(NaN));
31949         })) ? function toISOString() {
31950           if (!isFinite(getTime$1.call(this))) throw RangeError('Invalid time value');
31951           var date = this;
31952           var year = date.getUTCFullYear();
31953           var milliseconds = date.getUTCMilliseconds();
31954           var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
31955           return sign + padStart(abs$3(year), sign ? 6 : 4, 0) +
31956             '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
31957             '-' + padStart(date.getUTCDate(), 2, 0) +
31958             'T' + padStart(date.getUTCHours(), 2, 0) +
31959             ':' + padStart(date.getUTCMinutes(), 2, 0) +
31960             ':' + padStart(date.getUTCSeconds(), 2, 0) +
31961             '.' + padStart(milliseconds, 3, 0) +
31962             'Z';
31963         } : nativeDateToISOString;
31964
31965         // `Date.prototype.toISOString` method
31966         // https://tc39.es/ecma262/#sec-date.prototype.toisostring
31967         // PhantomJS / old WebKit has a broken implementations
31968         _export({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== dateToIsoString }, {
31969           toISOString: dateToIsoString
31970         });
31971
31972         function behaviorBreathe() {
31973           var duration = 800;
31974           var steps = 4;
31975           var selector = '.selected.shadow, .selected .shadow';
31976
31977           var _selected = select(null);
31978
31979           var _classed = '';
31980           var _params = {};
31981           var _done = false;
31982
31983           var _timer;
31984
31985           function ratchetyInterpolator(a, b, steps, units) {
31986             a = parseFloat(a);
31987             b = parseFloat(b);
31988             var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
31989             return function (t) {
31990               return String(sample(t)) + (units || '');
31991             };
31992           }
31993
31994           function reset(selection) {
31995             selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
31996           }
31997
31998           function setAnimationParams(transition, fromTo) {
31999             var toFrom = fromTo === 'from' ? 'to' : 'from';
32000             transition.styleTween('stroke-opacity', function (d) {
32001               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
32002             }).styleTween('stroke-width', function (d) {
32003               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
32004             }).styleTween('fill-opacity', function (d) {
32005               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
32006             }).styleTween('r', function (d) {
32007               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
32008             });
32009           }
32010
32011           function calcAnimationParams(selection) {
32012             selection.call(reset).each(function (d) {
32013               var s = select(this);
32014               var tag = s.node().tagName;
32015               var p = {
32016                 'from': {},
32017                 'to': {}
32018               };
32019               var opacity;
32020               var width; // determine base opacity and width
32021
32022               if (tag === 'circle') {
32023                 opacity = parseFloat(s.style('fill-opacity') || 0.5);
32024                 width = parseFloat(s.style('r') || 15.5);
32025               } else {
32026                 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
32027                 width = parseFloat(s.style('stroke-width') || 10);
32028               } // calculate from/to interpolation params..
32029
32030
32031               p.tag = tag;
32032               p.from.opacity = opacity * 0.6;
32033               p.to.opacity = opacity * 1.25;
32034               p.from.width = width * 0.7;
32035               p.to.width = width * (tag === 'circle' ? 1.5 : 1);
32036               _params[d.id] = p;
32037             });
32038           }
32039
32040           function run(surface, fromTo) {
32041             var toFrom = fromTo === 'from' ? 'to' : 'from';
32042             var currSelected = surface.selectAll(selector);
32043             var currClassed = surface.attr('class');
32044
32045             if (_done || currSelected.empty()) {
32046               _selected.call(reset);
32047
32048               _selected = select(null);
32049               return;
32050             }
32051
32052             if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
32053               _selected.call(reset);
32054
32055               _classed = currClassed;
32056               _selected = currSelected.call(calcAnimationParams);
32057             }
32058
32059             var didCallNextRun = false;
32060
32061             _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
32062               // `end` event is called for each selected element, but we want
32063               // it to run only once
32064               if (!didCallNextRun) {
32065                 surface.call(run, toFrom);
32066                 didCallNextRun = true;
32067               } // if entity was deselected, remove breathe styling
32068
32069
32070               if (!select(this).classed('selected')) {
32071                 reset(select(this));
32072               }
32073             });
32074           }
32075
32076           function behavior(surface) {
32077             _done = false;
32078             _timer = timer(function () {
32079               // wait for elements to actually become selected
32080               if (surface.selectAll(selector).empty()) {
32081                 return false;
32082               }
32083
32084               surface.call(run, 'from');
32085
32086               _timer.stop();
32087
32088               return true;
32089             }, 20);
32090           }
32091
32092           behavior.restartIfNeeded = function (surface) {
32093             if (_selected.empty()) {
32094               surface.call(run, 'from');
32095
32096               if (_timer) {
32097                 _timer.stop();
32098               }
32099             }
32100           };
32101
32102           behavior.off = function () {
32103             _done = true;
32104
32105             if (_timer) {
32106               _timer.stop();
32107             }
32108
32109             _selected.interrupt().call(reset);
32110           };
32111
32112           return behavior;
32113         }
32114
32115         /* Creates a keybinding behavior for an operation */
32116         function behaviorOperation(context) {
32117           var _operation;
32118
32119           function keypress(d3_event) {
32120             // prevent operations during low zoom selection
32121             if (!context.map().withinEditableZoom()) return;
32122             if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
32123             d3_event.preventDefault();
32124
32125             var disabled = _operation.disabled();
32126
32127             if (disabled) {
32128               context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
32129             } else {
32130               context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
32131               if (_operation.point) _operation.point(null);
32132
32133               _operation();
32134             }
32135           }
32136
32137           function behavior() {
32138             if (_operation && _operation.available()) {
32139               context.keybinding().on(_operation.keys, keypress);
32140             }
32141
32142             return behavior;
32143           }
32144
32145           behavior.off = function () {
32146             context.keybinding().off(_operation.keys);
32147           };
32148
32149           behavior.which = function (_) {
32150             if (!arguments.length) return _operation;
32151             _operation = _;
32152             return behavior;
32153           };
32154
32155           return behavior;
32156         }
32157
32158         function operationCircularize(context, selectedIDs) {
32159           var _extent;
32160
32161           var _actions = selectedIDs.map(getAction).filter(Boolean);
32162
32163           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32164
32165           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32166             return n.loc;
32167           });
32168
32169           function getAction(entityID) {
32170             var entity = context.entity(entityID);
32171             if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
32172
32173             if (!_extent) {
32174               _extent = entity.extent(context.graph());
32175             } else {
32176               _extent = _extent.extend(entity.extent(context.graph()));
32177             }
32178
32179             return actionCircularize(entityID, context.projection);
32180           }
32181
32182           var operation = function operation() {
32183             if (!_actions.length) return;
32184
32185             var combinedAction = function combinedAction(graph, t) {
32186               _actions.forEach(function (action) {
32187                 if (!action.disabled(graph)) {
32188                   graph = action(graph, t);
32189                 }
32190               });
32191
32192               return graph;
32193             };
32194
32195             combinedAction.transitionable = true;
32196             context.perform(combinedAction, operation.annotation());
32197             window.setTimeout(function () {
32198               context.validator().validate();
32199             }, 300); // after any transition
32200           };
32201
32202           operation.available = function () {
32203             return _actions.length && selectedIDs.length === _actions.length;
32204           }; // don't cache this because the visible extent could change
32205
32206
32207           operation.disabled = function () {
32208             if (!_actions.length) return '';
32209
32210             var actionDisableds = _actions.map(function (action) {
32211               return action.disabled(context.graph());
32212             }).filter(Boolean);
32213
32214             if (actionDisableds.length === _actions.length) {
32215               // none of the features can be circularized
32216               if (new Set(actionDisableds).size > 1) {
32217                 return 'multiple_blockers';
32218               }
32219
32220               return actionDisableds[0];
32221             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
32222               return 'too_large';
32223             } else if (someMissing()) {
32224               return 'not_downloaded';
32225             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32226               return 'connected_to_hidden';
32227             }
32228
32229             return false;
32230
32231             function someMissing() {
32232               if (context.inIntro()) return false;
32233               var osm = context.connection();
32234
32235               if (osm) {
32236                 var missing = _coords.filter(function (loc) {
32237                   return !osm.isDataLoaded(loc);
32238                 });
32239
32240                 if (missing.length) {
32241                   missing.forEach(function (loc) {
32242                     context.loadTileAtLoc(loc);
32243                   });
32244                   return true;
32245                 }
32246               }
32247
32248               return false;
32249             }
32250           };
32251
32252           operation.tooltip = function () {
32253             var disable = operation.disabled();
32254             return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
32255           };
32256
32257           operation.annotation = function () {
32258             return _t('operations.circularize.annotation.feature', {
32259               n: _actions.length
32260             });
32261           };
32262
32263           operation.id = 'circularize';
32264           operation.keys = [_t('operations.circularize.key')];
32265           operation.title = _t('operations.circularize.title');
32266           operation.behavior = behaviorOperation(context).which(operation);
32267           return operation;
32268         }
32269
32270         // For example, ⌘Z -> Ctrl+Z
32271
32272         var uiCmd = function uiCmd(code) {
32273           var detected = utilDetect();
32274
32275           if (detected.os === 'mac') {
32276             return code;
32277           }
32278
32279           if (detected.os === 'win') {
32280             if (code === '⌘⇧Z') return 'Ctrl+Y';
32281           }
32282
32283           var result = '',
32284               replacements = {
32285             '⌘': 'Ctrl',
32286             '⇧': 'Shift',
32287             '⌥': 'Alt',
32288             '⌫': 'Backspace',
32289             '⌦': 'Delete'
32290           };
32291
32292           for (var i = 0; i < code.length; i++) {
32293             if (code[i] in replacements) {
32294               result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
32295             } else {
32296               result += code[i];
32297             }
32298           }
32299
32300           return result;
32301         }; // return a display-focused string for a given keyboard code
32302
32303         uiCmd.display = function (code) {
32304           if (code.length !== 1) return code;
32305           var detected = utilDetect();
32306           var mac = detected.os === 'mac';
32307           var replacements = {
32308             '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
32309             '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
32310             '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
32311             '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
32312             '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
32313             '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
32314             '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
32315             '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
32316             '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
32317             '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
32318             '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
32319             '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
32320             '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
32321           };
32322           return replacements[code] || code;
32323         };
32324
32325         function operationDelete(context, selectedIDs) {
32326           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32327           var action = actionDeleteMultiple(selectedIDs);
32328           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32329           var coords = nodes.map(function (n) {
32330             return n.loc;
32331           });
32332           var extent = utilTotalExtent(selectedIDs, context.graph());
32333
32334           var operation = function operation() {
32335             var nextSelectedID;
32336             var nextSelectedLoc;
32337
32338             if (selectedIDs.length === 1) {
32339               var id = selectedIDs[0];
32340               var entity = context.entity(id);
32341               var geometry = entity.geometry(context.graph());
32342               var parents = context.graph().parentWays(entity);
32343               var parent = parents[0]; // Select the next closest node in the way.
32344
32345               if (geometry === 'vertex') {
32346                 var nodes = parent.nodes;
32347                 var i = nodes.indexOf(id);
32348
32349                 if (i === 0) {
32350                   i++;
32351                 } else if (i === nodes.length - 1) {
32352                   i--;
32353                 } else {
32354                   var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
32355                   var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
32356                   i = a < b ? i - 1 : i + 1;
32357                 }
32358
32359                 nextSelectedID = nodes[i];
32360                 nextSelectedLoc = context.entity(nextSelectedID).loc;
32361               }
32362             }
32363
32364             context.perform(action, operation.annotation());
32365             context.validator().validate();
32366
32367             if (nextSelectedID && nextSelectedLoc) {
32368               if (context.hasEntity(nextSelectedID)) {
32369                 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
32370               } else {
32371                 context.map().centerEase(nextSelectedLoc);
32372                 context.enter(modeBrowse(context));
32373               }
32374             } else {
32375               context.enter(modeBrowse(context));
32376             }
32377           };
32378
32379           operation.available = function () {
32380             return true;
32381           };
32382
32383           operation.disabled = function () {
32384             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32385               return 'too_large';
32386             } else if (someMissing()) {
32387               return 'not_downloaded';
32388             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32389               return 'connected_to_hidden';
32390             } else if (selectedIDs.some(protectedMember)) {
32391               return 'part_of_relation';
32392             } else if (selectedIDs.some(incompleteRelation)) {
32393               return 'incomplete_relation';
32394             } else if (selectedIDs.some(hasWikidataTag)) {
32395               return 'has_wikidata_tag';
32396             }
32397
32398             return false;
32399
32400             function someMissing() {
32401               if (context.inIntro()) return false;
32402               var osm = context.connection();
32403
32404               if (osm) {
32405                 var missing = coords.filter(function (loc) {
32406                   return !osm.isDataLoaded(loc);
32407                 });
32408
32409                 if (missing.length) {
32410                   missing.forEach(function (loc) {
32411                     context.loadTileAtLoc(loc);
32412                   });
32413                   return true;
32414                 }
32415               }
32416
32417               return false;
32418             }
32419
32420             function hasWikidataTag(id) {
32421               var entity = context.entity(id);
32422               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
32423             }
32424
32425             function incompleteRelation(id) {
32426               var entity = context.entity(id);
32427               return entity.type === 'relation' && !entity.isComplete(context.graph());
32428             }
32429
32430             function protectedMember(id) {
32431               var entity = context.entity(id);
32432               if (entity.type !== 'way') return false;
32433               var parents = context.graph().parentRelations(entity);
32434
32435               for (var i = 0; i < parents.length; i++) {
32436                 var parent = parents[i];
32437                 var type = parent.tags.type;
32438                 var role = parent.memberById(id).role || 'outer';
32439
32440                 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
32441                   return true;
32442                 }
32443               }
32444
32445               return false;
32446             }
32447           };
32448
32449           operation.tooltip = function () {
32450             var disable = operation.disabled();
32451             return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
32452           };
32453
32454           operation.annotation = function () {
32455             return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
32456               n: selectedIDs.length
32457             });
32458           };
32459
32460           operation.id = 'delete';
32461           operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
32462           operation.title = _t('operations.delete.title');
32463           operation.behavior = behaviorOperation(context).which(operation);
32464           return operation;
32465         }
32466
32467         function operationOrthogonalize(context, selectedIDs) {
32468           var _extent;
32469
32470           var _type;
32471
32472           var _actions = selectedIDs.map(chooseAction).filter(Boolean);
32473
32474           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32475
32476           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32477             return n.loc;
32478           });
32479
32480           function chooseAction(entityID) {
32481             var entity = context.entity(entityID);
32482             var geometry = entity.geometry(context.graph());
32483
32484             if (!_extent) {
32485               _extent = entity.extent(context.graph());
32486             } else {
32487               _extent = _extent.extend(entity.extent(context.graph()));
32488             } // square a line/area
32489
32490
32491             if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
32492               if (_type && _type !== 'feature') return null;
32493               _type = 'feature';
32494               return actionOrthogonalize(entityID, context.projection); // square a single vertex
32495             } else if (geometry === 'vertex') {
32496               if (_type && _type !== 'corner') return null;
32497               _type = 'corner';
32498               var graph = context.graph();
32499               var parents = graph.parentWays(entity);
32500
32501               if (parents.length === 1) {
32502                 var way = parents[0];
32503
32504                 if (way.nodes.indexOf(entityID) !== -1) {
32505                   return actionOrthogonalize(way.id, context.projection, entityID);
32506                 }
32507               }
32508             }
32509
32510             return null;
32511           }
32512
32513           var operation = function operation() {
32514             if (!_actions.length) return;
32515
32516             var combinedAction = function combinedAction(graph, t) {
32517               _actions.forEach(function (action) {
32518                 if (!action.disabled(graph)) {
32519                   graph = action(graph, t);
32520                 }
32521               });
32522
32523               return graph;
32524             };
32525
32526             combinedAction.transitionable = true;
32527             context.perform(combinedAction, operation.annotation());
32528             window.setTimeout(function () {
32529               context.validator().validate();
32530             }, 300); // after any transition
32531           };
32532
32533           operation.available = function () {
32534             return _actions.length && selectedIDs.length === _actions.length;
32535           }; // don't cache this because the visible extent could change
32536
32537
32538           operation.disabled = function () {
32539             if (!_actions.length) return '';
32540
32541             var actionDisableds = _actions.map(function (action) {
32542               return action.disabled(context.graph());
32543             }).filter(Boolean);
32544
32545             if (actionDisableds.length === _actions.length) {
32546               // none of the features can be squared
32547               if (new Set(actionDisableds).size > 1) {
32548                 return 'multiple_blockers';
32549               }
32550
32551               return actionDisableds[0];
32552             } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
32553               return 'too_large';
32554             } else if (someMissing()) {
32555               return 'not_downloaded';
32556             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32557               return 'connected_to_hidden';
32558             }
32559
32560             return false;
32561
32562             function someMissing() {
32563               if (context.inIntro()) return false;
32564               var osm = context.connection();
32565
32566               if (osm) {
32567                 var missing = _coords.filter(function (loc) {
32568                   return !osm.isDataLoaded(loc);
32569                 });
32570
32571                 if (missing.length) {
32572                   missing.forEach(function (loc) {
32573                     context.loadTileAtLoc(loc);
32574                   });
32575                   return true;
32576                 }
32577               }
32578
32579               return false;
32580             }
32581           };
32582
32583           operation.tooltip = function () {
32584             var disable = operation.disabled();
32585             return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
32586           };
32587
32588           operation.annotation = function () {
32589             return _t('operations.orthogonalize.annotation.' + _type, {
32590               n: _actions.length
32591             });
32592           };
32593
32594           operation.id = 'orthogonalize';
32595           operation.keys = [_t('operations.orthogonalize.key')];
32596           operation.title = _t('operations.orthogonalize.title');
32597           operation.behavior = behaviorOperation(context).which(operation);
32598           return operation;
32599         }
32600
32601         function operationReflectShort(context, selectedIDs) {
32602           return operationReflect(context, selectedIDs, 'short');
32603         }
32604         function operationReflectLong(context, selectedIDs) {
32605           return operationReflect(context, selectedIDs, 'long');
32606         }
32607         function operationReflect(context, selectedIDs, axis) {
32608           axis = axis || 'long';
32609           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32610           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32611           var coords = nodes.map(function (n) {
32612             return n.loc;
32613           });
32614           var extent = utilTotalExtent(selectedIDs, context.graph());
32615
32616           var operation = function operation() {
32617             var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
32618             context.perform(action, operation.annotation());
32619             window.setTimeout(function () {
32620               context.validator().validate();
32621             }, 300); // after any transition
32622           };
32623
32624           operation.available = function () {
32625             return nodes.length >= 3;
32626           }; // don't cache this because the visible extent could change
32627
32628
32629           operation.disabled = function () {
32630             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32631               return 'too_large';
32632             } else if (someMissing()) {
32633               return 'not_downloaded';
32634             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32635               return 'connected_to_hidden';
32636             } else if (selectedIDs.some(incompleteRelation)) {
32637               return 'incomplete_relation';
32638             }
32639
32640             return false;
32641
32642             function someMissing() {
32643               if (context.inIntro()) return false;
32644               var osm = context.connection();
32645
32646               if (osm) {
32647                 var missing = coords.filter(function (loc) {
32648                   return !osm.isDataLoaded(loc);
32649                 });
32650
32651                 if (missing.length) {
32652                   missing.forEach(function (loc) {
32653                     context.loadTileAtLoc(loc);
32654                   });
32655                   return true;
32656                 }
32657               }
32658
32659               return false;
32660             }
32661
32662             function incompleteRelation(id) {
32663               var entity = context.entity(id);
32664               return entity.type === 'relation' && !entity.isComplete(context.graph());
32665             }
32666           };
32667
32668           operation.tooltip = function () {
32669             var disable = operation.disabled();
32670             return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
32671           };
32672
32673           operation.annotation = function () {
32674             return _t('operations.reflect.annotation.' + axis + '.feature', {
32675               n: selectedIDs.length
32676             });
32677           };
32678
32679           operation.id = 'reflect-' + axis;
32680           operation.keys = [_t('operations.reflect.key.' + axis)];
32681           operation.title = _t('operations.reflect.title.' + axis);
32682           operation.behavior = behaviorOperation(context).which(operation);
32683           return operation;
32684         }
32685
32686         function operationMove(context, selectedIDs) {
32687           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32688           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32689           var coords = nodes.map(function (n) {
32690             return n.loc;
32691           });
32692           var extent = utilTotalExtent(selectedIDs, context.graph());
32693
32694           var operation = function operation() {
32695             context.enter(modeMove(context, selectedIDs));
32696           };
32697
32698           operation.available = function () {
32699             return selectedIDs.length > 1 || context.entity(selectedIDs[0]).type !== 'node';
32700           };
32701
32702           operation.disabled = function () {
32703             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32704               return 'too_large';
32705             } else if (someMissing()) {
32706               return 'not_downloaded';
32707             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32708               return 'connected_to_hidden';
32709             } else if (selectedIDs.some(incompleteRelation)) {
32710               return 'incomplete_relation';
32711             }
32712
32713             return false;
32714
32715             function someMissing() {
32716               if (context.inIntro()) return false;
32717               var osm = context.connection();
32718
32719               if (osm) {
32720                 var missing = coords.filter(function (loc) {
32721                   return !osm.isDataLoaded(loc);
32722                 });
32723
32724                 if (missing.length) {
32725                   missing.forEach(function (loc) {
32726                     context.loadTileAtLoc(loc);
32727                   });
32728                   return true;
32729                 }
32730               }
32731
32732               return false;
32733             }
32734
32735             function incompleteRelation(id) {
32736               var entity = context.entity(id);
32737               return entity.type === 'relation' && !entity.isComplete(context.graph());
32738             }
32739           };
32740
32741           operation.tooltip = function () {
32742             var disable = operation.disabled();
32743             return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
32744           };
32745
32746           operation.annotation = function () {
32747             return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
32748               n: selectedIDs.length
32749             });
32750           };
32751
32752           operation.id = 'move';
32753           operation.keys = [_t('operations.move.key')];
32754           operation.title = _t('operations.move.title');
32755           operation.behavior = behaviorOperation(context).which(operation);
32756           operation.mouseOnly = true;
32757           return operation;
32758         }
32759
32760         function modeRotate(context, entityIDs) {
32761           var mode = {
32762             id: 'rotate',
32763             button: 'browse'
32764           };
32765           var keybinding = utilKeybinding('rotate');
32766           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];
32767           var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
32768             n: entityIDs.length
32769           });
32770
32771           var _prevGraph;
32772
32773           var _prevAngle;
32774
32775           var _prevTransform;
32776
32777           var _pivot;
32778
32779           function doRotate() {
32780             var fn;
32781
32782             if (context.graph() !== _prevGraph) {
32783               fn = context.perform;
32784             } else {
32785               fn = context.replace;
32786             } // projection changed, recalculate _pivot
32787
32788
32789             var projection = context.projection;
32790             var currTransform = projection.transform();
32791
32792             if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
32793               var nodes = utilGetAllNodes(entityIDs, context.graph());
32794               var points = nodes.map(function (n) {
32795                 return projection(n.loc);
32796               });
32797               _pivot = getPivot(points);
32798               _prevAngle = undefined;
32799             }
32800
32801             var currMouse = context.map().mouse();
32802             var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
32803             if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
32804             var delta = currAngle - _prevAngle;
32805             fn(actionRotate(entityIDs, _pivot, delta, projection));
32806             _prevTransform = currTransform;
32807             _prevAngle = currAngle;
32808             _prevGraph = context.graph();
32809           }
32810
32811           function getPivot(points) {
32812             var _pivot;
32813
32814             if (points.length === 1) {
32815               _pivot = points[0];
32816             } else if (points.length === 2) {
32817               _pivot = geoVecInterp(points[0], points[1], 0.5);
32818             } else {
32819               var polygonHull = d3_polygonHull(points);
32820
32821               if (polygonHull.length === 2) {
32822                 _pivot = geoVecInterp(points[0], points[1], 0.5);
32823               } else {
32824                 _pivot = d3_polygonCentroid(d3_polygonHull(points));
32825               }
32826             }
32827
32828             return _pivot;
32829           }
32830
32831           function finish(d3_event) {
32832             d3_event.stopPropagation();
32833             context.replace(actionNoop(), annotation);
32834             context.enter(modeSelect(context, entityIDs));
32835           }
32836
32837           function cancel() {
32838             context.pop();
32839             context.enter(modeSelect(context, entityIDs));
32840           }
32841
32842           function undone() {
32843             context.enter(modeBrowse(context));
32844           }
32845
32846           mode.enter = function () {
32847             context.features().forceVisible(entityIDs);
32848             behaviors.forEach(context.install);
32849             context.surface().on('mousemove.rotate', doRotate).on('click.rotate', finish);
32850             context.history().on('undone.rotate', undone);
32851             keybinding.on('⎋', cancel).on('↩', finish);
32852             select(document).call(keybinding);
32853           };
32854
32855           mode.exit = function () {
32856             behaviors.forEach(context.uninstall);
32857             context.surface().on('mousemove.rotate', null).on('click.rotate', null);
32858             context.history().on('undone.rotate', null);
32859             select(document).call(keybinding.unbind);
32860             context.features().forceVisible([]);
32861           };
32862
32863           mode.selectedIDs = function () {
32864             if (!arguments.length) return entityIDs; // no assign
32865
32866             return mode;
32867           };
32868
32869           return mode;
32870         }
32871
32872         function operationRotate(context, selectedIDs) {
32873           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32874           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32875           var coords = nodes.map(function (n) {
32876             return n.loc;
32877           });
32878           var extent = utilTotalExtent(selectedIDs, context.graph());
32879
32880           var operation = function operation() {
32881             context.enter(modeRotate(context, selectedIDs));
32882           };
32883
32884           operation.available = function () {
32885             return nodes.length >= 2;
32886           };
32887
32888           operation.disabled = function () {
32889             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32890               return 'too_large';
32891             } else if (someMissing()) {
32892               return 'not_downloaded';
32893             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32894               return 'connected_to_hidden';
32895             } else if (selectedIDs.some(incompleteRelation)) {
32896               return 'incomplete_relation';
32897             }
32898
32899             return false;
32900
32901             function someMissing() {
32902               if (context.inIntro()) return false;
32903               var osm = context.connection();
32904
32905               if (osm) {
32906                 var missing = coords.filter(function (loc) {
32907                   return !osm.isDataLoaded(loc);
32908                 });
32909
32910                 if (missing.length) {
32911                   missing.forEach(function (loc) {
32912                     context.loadTileAtLoc(loc);
32913                   });
32914                   return true;
32915                 }
32916               }
32917
32918               return false;
32919             }
32920
32921             function incompleteRelation(id) {
32922               var entity = context.entity(id);
32923               return entity.type === 'relation' && !entity.isComplete(context.graph());
32924             }
32925           };
32926
32927           operation.tooltip = function () {
32928             var disable = operation.disabled();
32929             return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
32930           };
32931
32932           operation.annotation = function () {
32933             return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
32934               n: selectedIDs.length
32935             });
32936           };
32937
32938           operation.id = 'rotate';
32939           operation.keys = [_t('operations.rotate.key')];
32940           operation.title = _t('operations.rotate.title');
32941           operation.behavior = behaviorOperation(context).which(operation);
32942           operation.mouseOnly = true;
32943           return operation;
32944         }
32945
32946         function modeMove(context, entityIDs, baseGraph) {
32947           var mode = {
32948             id: 'move',
32949             button: 'browse'
32950           };
32951           var keybinding = utilKeybinding('move');
32952           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];
32953           var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
32954             n: entityIDs.length
32955           });
32956
32957           var _prevGraph;
32958
32959           var _cache;
32960
32961           var _origin;
32962
32963           var _nudgeInterval;
32964
32965           function doMove(nudge) {
32966             nudge = nudge || [0, 0];
32967             var fn;
32968
32969             if (_prevGraph !== context.graph()) {
32970               _cache = {};
32971               _origin = context.map().mouseCoordinates();
32972               fn = context.perform;
32973             } else {
32974               fn = context.overwrite;
32975             }
32976
32977             var currMouse = context.map().mouse();
32978             var origMouse = context.projection(_origin);
32979             var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
32980             fn(actionMove(entityIDs, delta, context.projection, _cache));
32981             _prevGraph = context.graph();
32982           }
32983
32984           function startNudge(nudge) {
32985             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
32986             _nudgeInterval = window.setInterval(function () {
32987               context.map().pan(nudge);
32988               doMove(nudge);
32989             }, 50);
32990           }
32991
32992           function stopNudge() {
32993             if (_nudgeInterval) {
32994               window.clearInterval(_nudgeInterval);
32995               _nudgeInterval = null;
32996             }
32997           }
32998
32999           function move() {
33000             doMove();
33001             var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
33002
33003             if (nudge) {
33004               startNudge(nudge);
33005             } else {
33006               stopNudge();
33007             }
33008           }
33009
33010           function finish(d3_event) {
33011             d3_event.stopPropagation();
33012             context.replace(actionNoop(), annotation);
33013             context.enter(modeSelect(context, entityIDs));
33014             stopNudge();
33015           }
33016
33017           function cancel() {
33018             if (baseGraph) {
33019               while (context.graph() !== baseGraph) {
33020                 context.pop();
33021               }
33022
33023               context.enter(modeBrowse(context));
33024             } else {
33025               context.pop();
33026               context.enter(modeSelect(context, entityIDs));
33027             }
33028
33029             stopNudge();
33030           }
33031
33032           function undone() {
33033             context.enter(modeBrowse(context));
33034           }
33035
33036           mode.enter = function () {
33037             _origin = context.map().mouseCoordinates();
33038             _prevGraph = null;
33039             _cache = {};
33040             context.features().forceVisible(entityIDs);
33041             behaviors.forEach(context.install);
33042             context.surface().on('mousemove.move', move).on('click.move', finish);
33043             context.history().on('undone.move', undone);
33044             keybinding.on('⎋', cancel).on('↩', finish);
33045             select(document).call(keybinding);
33046           };
33047
33048           mode.exit = function () {
33049             stopNudge();
33050             behaviors.forEach(function (behavior) {
33051               context.uninstall(behavior);
33052             });
33053             context.surface().on('mousemove.move', null).on('click.move', null);
33054             context.history().on('undone.move', null);
33055             select(document).call(keybinding.unbind);
33056             context.features().forceVisible([]);
33057           };
33058
33059           mode.selectedIDs = function () {
33060             if (!arguments.length) return entityIDs; // no assign
33061
33062             return mode;
33063           };
33064
33065           return mode;
33066         }
33067
33068         function behaviorPaste(context) {
33069           function doPaste(d3_event) {
33070             // prevent paste during low zoom selection
33071             if (!context.map().withinEditableZoom()) return;
33072             d3_event.preventDefault();
33073             var baseGraph = context.graph();
33074             var mouse = context.map().mouse();
33075             var projection = context.projection;
33076             var viewport = geoExtent(projection.clipExtent()).polygon();
33077             if (!geoPointInPolygon(mouse, viewport)) return;
33078             var oldIDs = context.copyIDs();
33079             if (!oldIDs.length) return;
33080             var extent = geoExtent();
33081             var oldGraph = context.copyGraph();
33082             var newIDs = [];
33083             var action = actionCopyEntities(oldIDs, oldGraph);
33084             context.perform(action);
33085             var copies = action.copies();
33086             var originals = new Set();
33087             Object.values(copies).forEach(function (entity) {
33088               originals.add(entity.id);
33089             });
33090
33091             for (var id in copies) {
33092               var oldEntity = oldGraph.entity(id);
33093               var newEntity = copies[id];
33094
33095               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
33096
33097
33098               var parents = context.graph().parentWays(newEntity);
33099               var parentCopied = parents.some(function (parent) {
33100                 return originals.has(parent.id);
33101               });
33102
33103               if (!parentCopied) {
33104                 newIDs.push(newEntity.id);
33105               }
33106             } // Put pasted objects where mouse pointer is..
33107
33108
33109             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
33110             var delta = geoVecSubtract(mouse, copyPoint);
33111             context.perform(actionMove(newIDs, delta, projection));
33112             context.enter(modeMove(context, newIDs, baseGraph));
33113           }
33114
33115           function behavior() {
33116             context.keybinding().on(uiCmd('⌘V'), doPaste);
33117             return behavior;
33118           }
33119
33120           behavior.off = function () {
33121             context.keybinding().off(uiCmd('⌘V'));
33122           };
33123
33124           return behavior;
33125         }
33126
33127         // `String.prototype.repeat` method
33128         // https://tc39.es/ecma262/#sec-string.prototype.repeat
33129         _export({ target: 'String', proto: true }, {
33130           repeat: stringRepeat
33131         });
33132
33133         /*
33134             `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
33135
33136             * The `origin` function is expected to return an [x, y] tuple rather than an
33137               {x, y} object.
33138             * The events are `start`, `move`, and `end`.
33139               (https://github.com/mbostock/d3/issues/563)
33140             * The `start` event is not dispatched until the first cursor movement occurs.
33141               (https://github.com/mbostock/d3/pull/368)
33142             * The `move` event has a `point` and `delta` [x, y] tuple properties rather
33143               than `x`, `y`, `dx`, and `dy` properties.
33144             * The `end` event is not dispatched if no movement occurs.
33145             * An `off` function is available that unbinds the drag's internal event handlers.
33146          */
33147
33148         function behaviorDrag() {
33149           var dispatch$1 = dispatch('start', 'move', 'end'); // see also behaviorSelect
33150
33151           var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
33152
33153           var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
33154
33155           var _origin = null;
33156           var _selector = '';
33157
33158           var _targetNode;
33159
33160           var _targetEntity;
33161
33162           var _surface;
33163
33164           var _pointerId; // use pointer events on supported platforms; fallback to mouse events
33165
33166
33167           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
33168
33169           var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
33170
33171           var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
33172             var selection$1 = selection();
33173             var select = selection$1.style(d3_event_userSelectProperty);
33174             selection$1.style(d3_event_userSelectProperty, 'none');
33175             return function () {
33176               selection$1.style(d3_event_userSelectProperty, select);
33177             };
33178           };
33179
33180           function pointerdown(d3_event) {
33181             if (_pointerId) return;
33182             _pointerId = d3_event.pointerId || 'mouse';
33183             _targetNode = this; // only force reflow once per drag
33184
33185             var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
33186             var offset;
33187             var startOrigin = pointerLocGetter(d3_event);
33188             var started = false;
33189             var selectEnable = d3_event_userSelectSuppress();
33190             select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
33191
33192             if (_origin) {
33193               offset = _origin.call(_targetNode, _targetEntity);
33194               offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
33195             } else {
33196               offset = [0, 0];
33197             }
33198
33199             d3_event.stopPropagation();
33200
33201             function pointermove(d3_event) {
33202               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33203               var p = pointerLocGetter(d3_event);
33204
33205               if (!started) {
33206                 var dist = geoVecLength(startOrigin, p);
33207                 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
33208
33209                 if (dist < tolerance) return;
33210                 started = true;
33211                 dispatch$1.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
33212                 // a midpoint will convert the target to a node.
33213               } else {
33214                 startOrigin = p;
33215                 d3_event.stopPropagation();
33216                 d3_event.preventDefault();
33217                 var dx = p[0] - startOrigin[0];
33218                 var dy = p[1] - startOrigin[1];
33219                 dispatch$1.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
33220               }
33221             }
33222
33223             function pointerup(d3_event) {
33224               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33225               _pointerId = null;
33226
33227               if (started) {
33228                 dispatch$1.call('end', this, d3_event, _targetEntity);
33229                 d3_event.preventDefault();
33230               }
33231
33232               select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33233               selectEnable();
33234             }
33235           }
33236
33237           function behavior(selection) {
33238             var matchesSelector = utilPrefixDOMProperty('matchesSelector');
33239             var delegate = pointerdown;
33240
33241             if (_selector) {
33242               delegate = function delegate(d3_event) {
33243                 var root = this;
33244                 var target = d3_event.target;
33245
33246                 for (; target && target !== root; target = target.parentNode) {
33247                   var datum = target.__data__;
33248                   _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
33249
33250                   if (_targetEntity && target[matchesSelector](_selector)) {
33251                     return pointerdown.call(target, d3_event);
33252                   }
33253                 }
33254               };
33255             }
33256
33257             selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
33258           }
33259
33260           behavior.off = function (selection) {
33261             selection.on(_pointerPrefix + 'down.drag' + _selector, null);
33262           };
33263
33264           behavior.selector = function (_) {
33265             if (!arguments.length) return _selector;
33266             _selector = _;
33267             return behavior;
33268           };
33269
33270           behavior.origin = function (_) {
33271             if (!arguments.length) return _origin;
33272             _origin = _;
33273             return behavior;
33274           };
33275
33276           behavior.cancel = function () {
33277             select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33278             return behavior;
33279           };
33280
33281           behavior.targetNode = function (_) {
33282             if (!arguments.length) return _targetNode;
33283             _targetNode = _;
33284             return behavior;
33285           };
33286
33287           behavior.targetEntity = function (_) {
33288             if (!arguments.length) return _targetEntity;
33289             _targetEntity = _;
33290             return behavior;
33291           };
33292
33293           behavior.surface = function (_) {
33294             if (!arguments.length) return _surface;
33295             _surface = _;
33296             return behavior;
33297           };
33298
33299           return utilRebind(behavior, dispatch$1, 'on');
33300         }
33301
33302         function modeDragNode(context) {
33303           var mode = {
33304             id: 'drag-node',
33305             button: 'browse'
33306           };
33307           var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
33308           var edit = behaviorEdit(context);
33309
33310           var _nudgeInterval;
33311
33312           var _restoreSelectedIDs = [];
33313           var _wasMidpoint = false;
33314           var _isCancelled = false;
33315
33316           var _activeEntity;
33317
33318           var _startLoc;
33319
33320           var _lastLoc;
33321
33322           function startNudge(d3_event, entity, nudge) {
33323             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
33324             _nudgeInterval = window.setInterval(function () {
33325               context.map().pan(nudge);
33326               doMove(d3_event, entity, nudge);
33327             }, 50);
33328           }
33329
33330           function stopNudge() {
33331             if (_nudgeInterval) {
33332               window.clearInterval(_nudgeInterval);
33333               _nudgeInterval = null;
33334             }
33335           }
33336
33337           function moveAnnotation(entity) {
33338             return _t('operations.move.annotation.' + entity.geometry(context.graph()));
33339           }
33340
33341           function connectAnnotation(nodeEntity, targetEntity) {
33342             var nodeGeometry = nodeEntity.geometry(context.graph());
33343             var targetGeometry = targetEntity.geometry(context.graph());
33344
33345             if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
33346               var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
33347               var targetParentWayIDs = context.graph().parentWays(targetEntity);
33348               var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
33349
33350               if (sharedParentWays.length !== 0) {
33351                 // if the nodes are next to each other, they are merged
33352                 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
33353                   return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
33354                 }
33355
33356                 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
33357               }
33358             }
33359
33360             return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
33361           }
33362
33363           function shouldSnapToNode(target) {
33364             if (!_activeEntity) return false;
33365             return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
33366           }
33367
33368           function origin(entity) {
33369             return context.projection(entity.loc);
33370           }
33371
33372           function keydown(d3_event) {
33373             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33374               if (context.surface().classed('nope')) {
33375                 context.surface().classed('nope-suppressed', true);
33376               }
33377
33378               context.surface().classed('nope', false).classed('nope-disabled', true);
33379             }
33380           }
33381
33382           function keyup(d3_event) {
33383             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33384               if (context.surface().classed('nope-suppressed')) {
33385                 context.surface().classed('nope', true);
33386               }
33387
33388               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
33389             }
33390           }
33391
33392           function start(d3_event, entity) {
33393             _wasMidpoint = entity.type === 'midpoint';
33394             var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
33395             _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
33396
33397             if (_isCancelled) {
33398               if (hasHidden) {
33399                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
33400               }
33401
33402               return drag.cancel();
33403             }
33404
33405             if (_wasMidpoint) {
33406               var midpoint = entity;
33407               entity = osmNode();
33408               context.perform(actionAddMidpoint(midpoint, entity));
33409               entity = context.entity(entity.id); // get post-action entity
33410
33411               var vertex = context.surface().selectAll('.' + entity.id);
33412               drag.targetNode(vertex.node()).targetEntity(entity);
33413             } else {
33414               context.perform(actionNoop());
33415             }
33416
33417             _activeEntity = entity;
33418             _startLoc = entity.loc;
33419             hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
33420             context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
33421             context.enter(mode);
33422           } // related code
33423           // - `behavior/draw.js` `datum()`
33424
33425
33426           function datum(d3_event) {
33427             if (!d3_event || d3_event.altKey) {
33428               return {};
33429             } else {
33430               // When dragging, snap only to touch targets..
33431               // (this excludes area fills and active drawing elements)
33432               var d = d3_event.target.__data__;
33433               return d && d.properties && d.properties.target ? d : {};
33434             }
33435           }
33436
33437           function doMove(d3_event, entity, nudge) {
33438             nudge = nudge || [0, 0];
33439             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
33440             var currMouse = geoVecSubtract(currPoint, nudge);
33441             var loc = context.projection.invert(currMouse);
33442             var target, edge;
33443
33444             if (!_nudgeInterval) {
33445               // If not nudging at the edge of the viewport, try to snap..
33446               // related code
33447               // - `mode/drag_node.js`     `doMove()`
33448               // - `behavior/draw.js`      `click()`
33449               // - `behavior/draw_way.js`  `move()`
33450               var d = datum(d3_event);
33451               target = d && d.properties && d.properties.entity;
33452               var targetLoc = target && target.loc;
33453               var targetNodes = d && d.properties && d.properties.nodes;
33454
33455               if (targetLoc) {
33456                 // snap to node/vertex - a point target with `.loc`
33457                 if (shouldSnapToNode(target)) {
33458                   loc = targetLoc;
33459                 }
33460               } else if (targetNodes) {
33461                 // snap to way - a line target with `.nodes`
33462                 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
33463
33464                 if (edge) {
33465                   loc = edge.loc;
33466                 }
33467               }
33468             }
33469
33470             context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
33471
33472             var isInvalid = false; // Check if this connection to `target` could cause relations to break..
33473
33474             if (target) {
33475               isInvalid = hasRelationConflict(entity, target, edge, context.graph());
33476             } // Check if this drag causes the geometry to break..
33477
33478
33479             if (!isInvalid) {
33480               isInvalid = hasInvalidGeometry(entity, context.graph());
33481             }
33482
33483             var nope = context.surface().classed('nope');
33484
33485             if (isInvalid === 'relation' || isInvalid === 'restriction') {
33486               if (!nope) {
33487                 // about to nope - show hint
33488                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
33489                   relation: _mainPresetIndex.item('type/restriction').name()
33490                 }))();
33491               }
33492             } else if (isInvalid) {
33493               var errorID = isInvalid === 'line' ? 'lines' : 'areas';
33494               context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
33495             } else {
33496               if (nope) {
33497                 // about to un-nope, remove hint
33498                 context.ui().flash.duration(1).label('')();
33499               }
33500             }
33501
33502             var nopeDisabled = context.surface().classed('nope-disabled');
33503
33504             if (nopeDisabled) {
33505               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
33506             } else {
33507               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
33508             }
33509
33510             _lastLoc = loc;
33511           } // Uses `actionConnect.disabled()` to know whether this connection is ok..
33512
33513
33514           function hasRelationConflict(entity, target, edge, graph) {
33515             var testGraph = graph.update(); // copy
33516             // if snapping to way - add midpoint there and consider that the target..
33517
33518             if (edge) {
33519               var midpoint = osmNode();
33520               var action = actionAddMidpoint({
33521                 loc: edge.loc,
33522                 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
33523               }, midpoint);
33524               testGraph = action(testGraph);
33525               target = midpoint;
33526             } // can we connect to it?
33527
33528
33529             var ids = [entity.id, target.id];
33530             return actionConnect(ids).disabled(testGraph);
33531           }
33532
33533           function hasInvalidGeometry(entity, graph) {
33534             var parents = graph.parentWays(entity);
33535             var i, j, k;
33536
33537             for (i = 0; i < parents.length; i++) {
33538               var parent = parents[i];
33539               var nodes = [];
33540               var activeIndex = null; // which multipolygon ring contains node being dragged
33541               // test any parent multipolygons for valid geometry
33542
33543               var relations = graph.parentRelations(parent);
33544
33545               for (j = 0; j < relations.length; j++) {
33546                 if (!relations[j].isMultipolygon()) continue;
33547                 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
33548
33549                 for (k = 0; k < rings.length; k++) {
33550                   nodes = rings[k].nodes;
33551
33552                   if (nodes.find(function (n) {
33553                     return n.id === entity.id;
33554                   })) {
33555                     activeIndex = k;
33556
33557                     if (geoHasSelfIntersections(nodes, entity.id)) {
33558                       return 'multipolygonMember';
33559                     }
33560                   }
33561
33562                   rings[k].coords = nodes.map(function (n) {
33563                     return n.loc;
33564                   });
33565                 } // test active ring for intersections with other rings in the multipolygon
33566
33567
33568                 for (k = 0; k < rings.length; k++) {
33569                   if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
33570
33571                   if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
33572                     return 'multipolygonRing';
33573                   }
33574                 }
33575               } // If we still haven't tested this node's parent way for self-intersections.
33576               // (because it's not a member of a multipolygon), test it now.
33577
33578
33579               if (activeIndex === null) {
33580                 nodes = parent.nodes.map(function (nodeID) {
33581                   return graph.entity(nodeID);
33582                 });
33583
33584                 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
33585                   return parent.geometry(graph);
33586                 }
33587               }
33588             }
33589
33590             return false;
33591           }
33592
33593           function move(d3_event, entity, point) {
33594             if (_isCancelled) return;
33595             d3_event.stopPropagation();
33596             context.surface().classed('nope-disabled', d3_event.altKey);
33597             _lastLoc = context.projection.invert(point);
33598             doMove(d3_event, entity);
33599             var nudge = geoViewportEdge(point, context.map().dimensions());
33600
33601             if (nudge) {
33602               startNudge(d3_event, entity, nudge);
33603             } else {
33604               stopNudge();
33605             }
33606           }
33607
33608           function end(d3_event, entity) {
33609             if (_isCancelled) return;
33610             var wasPoint = entity.geometry(context.graph()) === 'point';
33611             var d = datum(d3_event);
33612             var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
33613             var target = d && d.properties && d.properties.entity; // entity to snap to
33614
33615             if (nope) {
33616               // bounce back
33617               context.perform(_actionBounceBack(entity.id, _startLoc));
33618             } else if (target && target.type === 'way') {
33619               var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
33620               context.replace(actionAddMidpoint({
33621                 loc: choice.loc,
33622                 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
33623               }, entity), connectAnnotation(entity, target));
33624             } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
33625               context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
33626             } else if (_wasMidpoint) {
33627               context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
33628             } else {
33629               context.replace(actionNoop(), moveAnnotation(entity));
33630             }
33631
33632             if (wasPoint) {
33633               context.enter(modeSelect(context, [entity.id]));
33634             } else {
33635               var reselection = _restoreSelectedIDs.filter(function (id) {
33636                 return context.graph().hasEntity(id);
33637               });
33638
33639               if (reselection.length) {
33640                 context.enter(modeSelect(context, reselection));
33641               } else {
33642                 context.enter(modeBrowse(context));
33643               }
33644             }
33645           }
33646
33647           function _actionBounceBack(nodeID, toLoc) {
33648             var moveNode = actionMoveNode(nodeID, toLoc);
33649
33650             var action = function action(graph, t) {
33651               // last time through, pop off the bounceback perform.
33652               // it will then overwrite the initial perform with a moveNode that does nothing
33653               if (t === 1) context.pop();
33654               return moveNode(graph, t);
33655             };
33656
33657             action.transitionable = true;
33658             return action;
33659           }
33660
33661           function cancel() {
33662             drag.cancel();
33663             context.enter(modeBrowse(context));
33664           }
33665
33666           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);
33667
33668           mode.enter = function () {
33669             context.install(hover);
33670             context.install(edit);
33671             select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
33672             context.history().on('undone.drag-node', cancel);
33673           };
33674
33675           mode.exit = function () {
33676             context.ui().sidebar.hover.cancel();
33677             context.uninstall(hover);
33678             context.uninstall(edit);
33679             select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
33680             context.history().on('undone.drag-node', null);
33681             _activeEntity = null;
33682             context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
33683             stopNudge();
33684           };
33685
33686           mode.selectedIDs = function () {
33687             if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
33688
33689             return mode;
33690           };
33691
33692           mode.activeID = function () {
33693             if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
33694
33695             return mode;
33696           };
33697
33698           mode.restoreSelectedIDs = function (_) {
33699             if (!arguments.length) return _restoreSelectedIDs;
33700             _restoreSelectedIDs = _;
33701             return mode;
33702           };
33703
33704           mode.behavior = drag;
33705           return mode;
33706         }
33707
33708         // @@search logic
33709         fixRegexpWellKnownSymbolLogic('search', 1, function (SEARCH, nativeSearch, maybeCallNative) {
33710           return [
33711             // `String.prototype.search` method
33712             // https://tc39.es/ecma262/#sec-string.prototype.search
33713             function search(regexp) {
33714               var O = requireObjectCoercible(this);
33715               var searcher = regexp == undefined ? undefined : regexp[SEARCH];
33716               return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
33717             },
33718             // `RegExp.prototype[@@search]` method
33719             // https://tc39.es/ecma262/#sec-regexp.prototype-@@search
33720             function (regexp) {
33721               var res = maybeCallNative(nativeSearch, regexp, this);
33722               if (res.done) return res.value;
33723
33724               var rx = anObject(regexp);
33725               var S = String(this);
33726
33727               var previousLastIndex = rx.lastIndex;
33728               if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
33729               var result = regexpExecAbstract(rx, S);
33730               if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
33731               return result === null ? -1 : result.index;
33732             }
33733           ];
33734         });
33735
33736         // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
33737         var NON_GENERIC = !!nativePromiseConstructor && fails(function () {
33738           nativePromiseConstructor.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
33739         });
33740
33741         // `Promise.prototype.finally` method
33742         // https://tc39.es/ecma262/#sec-promise.prototype.finally
33743         _export({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
33744           'finally': function (onFinally) {
33745             var C = speciesConstructor(this, getBuiltIn('Promise'));
33746             var isFunction = typeof onFinally == 'function';
33747             return this.then(
33748               isFunction ? function (x) {
33749                 return promiseResolve(C, onFinally()).then(function () { return x; });
33750               } : onFinally,
33751               isFunction ? function (e) {
33752                 return promiseResolve(C, onFinally()).then(function () { throw e; });
33753               } : onFinally
33754             );
33755           }
33756         });
33757
33758         // patch native Promise.prototype for native async functions
33759         if ( typeof nativePromiseConstructor == 'function' && !nativePromiseConstructor.prototype['finally']) {
33760           redefine(nativePromiseConstructor.prototype, 'finally', getBuiltIn('Promise').prototype['finally']);
33761         }
33762
33763         function quickselect$1(arr, k, left, right, compare) {
33764           quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
33765         }
33766
33767         function quickselectStep(arr, k, left, right, compare) {
33768           while (right > left) {
33769             if (right - left > 600) {
33770               var n = right - left + 1;
33771               var m = k - left + 1;
33772               var z = Math.log(n);
33773               var s = 0.5 * Math.exp(2 * z / 3);
33774               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
33775               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
33776               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
33777               quickselectStep(arr, k, newLeft, newRight, compare);
33778             }
33779
33780             var t = arr[k];
33781             var i = left;
33782             var j = right;
33783             swap$1(arr, left, k);
33784             if (compare(arr[right], t) > 0) swap$1(arr, left, right);
33785
33786             while (i < j) {
33787               swap$1(arr, i, j);
33788               i++;
33789               j--;
33790
33791               while (compare(arr[i], t) < 0) {
33792                 i++;
33793               }
33794
33795               while (compare(arr[j], t) > 0) {
33796                 j--;
33797               }
33798             }
33799
33800             if (compare(arr[left], t) === 0) swap$1(arr, left, j);else {
33801               j++;
33802               swap$1(arr, j, right);
33803             }
33804             if (j <= k) left = j + 1;
33805             if (k <= j) right = j - 1;
33806           }
33807         }
33808
33809         function swap$1(arr, i, j) {
33810           var tmp = arr[i];
33811           arr[i] = arr[j];
33812           arr[j] = tmp;
33813         }
33814
33815         function defaultCompare(a, b) {
33816           return a < b ? -1 : a > b ? 1 : 0;
33817         }
33818
33819         var RBush = /*#__PURE__*/function () {
33820           function RBush() {
33821             var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
33822
33823             _classCallCheck(this, RBush);
33824
33825             // max entries in a node is 9 by default; min node fill is 40% for best performance
33826             this._maxEntries = Math.max(4, maxEntries);
33827             this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
33828             this.clear();
33829           }
33830
33831           _createClass(RBush, [{
33832             key: "all",
33833             value: function all() {
33834               return this._all(this.data, []);
33835             }
33836           }, {
33837             key: "search",
33838             value: function search(bbox) {
33839               var node = this.data;
33840               var result = [];
33841               if (!intersects(bbox, node)) return result;
33842               var toBBox = this.toBBox;
33843               var nodesToSearch = [];
33844
33845               while (node) {
33846                 for (var i = 0; i < node.children.length; i++) {
33847                   var child = node.children[i];
33848                   var childBBox = node.leaf ? toBBox(child) : child;
33849
33850                   if (intersects(bbox, childBBox)) {
33851                     if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
33852                   }
33853                 }
33854
33855                 node = nodesToSearch.pop();
33856               }
33857
33858               return result;
33859             }
33860           }, {
33861             key: "collides",
33862             value: function collides(bbox) {
33863               var node = this.data;
33864               if (!intersects(bbox, node)) return false;
33865               var nodesToSearch = [];
33866
33867               while (node) {
33868                 for (var i = 0; i < node.children.length; i++) {
33869                   var child = node.children[i];
33870                   var childBBox = node.leaf ? this.toBBox(child) : child;
33871
33872                   if (intersects(bbox, childBBox)) {
33873                     if (node.leaf || contains(bbox, childBBox)) return true;
33874                     nodesToSearch.push(child);
33875                   }
33876                 }
33877
33878                 node = nodesToSearch.pop();
33879               }
33880
33881               return false;
33882             }
33883           }, {
33884             key: "load",
33885             value: function load(data) {
33886               if (!(data && data.length)) return this;
33887
33888               if (data.length < this._minEntries) {
33889                 for (var i = 0; i < data.length; i++) {
33890                   this.insert(data[i]);
33891                 }
33892
33893                 return this;
33894               } // recursively build the tree with the given data from scratch using OMT algorithm
33895
33896
33897               var node = this._build(data.slice(), 0, data.length - 1, 0);
33898
33899               if (!this.data.children.length) {
33900                 // save as is if tree is empty
33901                 this.data = node;
33902               } else if (this.data.height === node.height) {
33903                 // split root if trees have the same height
33904                 this._splitRoot(this.data, node);
33905               } else {
33906                 if (this.data.height < node.height) {
33907                   // swap trees if inserted one is bigger
33908                   var tmpNode = this.data;
33909                   this.data = node;
33910                   node = tmpNode;
33911                 } // insert the small tree into the large tree at appropriate level
33912
33913
33914                 this._insert(node, this.data.height - node.height - 1, true);
33915               }
33916
33917               return this;
33918             }
33919           }, {
33920             key: "insert",
33921             value: function insert(item) {
33922               if (item) this._insert(item, this.data.height - 1);
33923               return this;
33924             }
33925           }, {
33926             key: "clear",
33927             value: function clear() {
33928               this.data = createNode([]);
33929               return this;
33930             }
33931           }, {
33932             key: "remove",
33933             value: function remove(item, equalsFn) {
33934               if (!item) return this;
33935               var node = this.data;
33936               var bbox = this.toBBox(item);
33937               var path = [];
33938               var indexes = [];
33939               var i, parent, goingUp; // depth-first iterative tree traversal
33940
33941               while (node || path.length) {
33942                 if (!node) {
33943                   // go up
33944                   node = path.pop();
33945                   parent = path[path.length - 1];
33946                   i = indexes.pop();
33947                   goingUp = true;
33948                 }
33949
33950                 if (node.leaf) {
33951                   // check current node
33952                   var index = findItem(item, node.children, equalsFn);
33953
33954                   if (index !== -1) {
33955                     // item found, remove the item and condense tree upwards
33956                     node.children.splice(index, 1);
33957                     path.push(node);
33958
33959                     this._condense(path);
33960
33961                     return this;
33962                   }
33963                 }
33964
33965                 if (!goingUp && !node.leaf && contains(node, bbox)) {
33966                   // go down
33967                   path.push(node);
33968                   indexes.push(i);
33969                   i = 0;
33970                   parent = node;
33971                   node = node.children[0];
33972                 } else if (parent) {
33973                   // go right
33974                   i++;
33975                   node = parent.children[i];
33976                   goingUp = false;
33977                 } else node = null; // nothing found
33978
33979               }
33980
33981               return this;
33982             }
33983           }, {
33984             key: "toBBox",
33985             value: function toBBox(item) {
33986               return item;
33987             }
33988           }, {
33989             key: "compareMinX",
33990             value: function compareMinX(a, b) {
33991               return a.minX - b.minX;
33992             }
33993           }, {
33994             key: "compareMinY",
33995             value: function compareMinY(a, b) {
33996               return a.minY - b.minY;
33997             }
33998           }, {
33999             key: "toJSON",
34000             value: function toJSON() {
34001               return this.data;
34002             }
34003           }, {
34004             key: "fromJSON",
34005             value: function fromJSON(data) {
34006               this.data = data;
34007               return this;
34008             }
34009           }, {
34010             key: "_all",
34011             value: function _all(node, result) {
34012               var nodesToSearch = [];
34013
34014               while (node) {
34015                 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
34016                 node = nodesToSearch.pop();
34017               }
34018
34019               return result;
34020             }
34021           }, {
34022             key: "_build",
34023             value: function _build(items, left, right, height) {
34024               var N = right - left + 1;
34025               var M = this._maxEntries;
34026               var node;
34027
34028               if (N <= M) {
34029                 // reached leaf level; return leaf
34030                 node = createNode(items.slice(left, right + 1));
34031                 calcBBox(node, this.toBBox);
34032                 return node;
34033               }
34034
34035               if (!height) {
34036                 // target height of the bulk-loaded tree
34037                 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
34038
34039                 M = Math.ceil(N / Math.pow(M, height - 1));
34040               }
34041
34042               node = createNode([]);
34043               node.leaf = false;
34044               node.height = height; // split the items into M mostly square tiles
34045
34046               var N2 = Math.ceil(N / M);
34047               var N1 = N2 * Math.ceil(Math.sqrt(M));
34048               multiSelect(items, left, right, N1, this.compareMinX);
34049
34050               for (var i = left; i <= right; i += N1) {
34051                 var right2 = Math.min(i + N1 - 1, right);
34052                 multiSelect(items, i, right2, N2, this.compareMinY);
34053
34054                 for (var j = i; j <= right2; j += N2) {
34055                   var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
34056
34057                   node.children.push(this._build(items, j, right3, height - 1));
34058                 }
34059               }
34060
34061               calcBBox(node, this.toBBox);
34062               return node;
34063             }
34064           }, {
34065             key: "_chooseSubtree",
34066             value: function _chooseSubtree(bbox, node, level, path) {
34067               while (true) {
34068                 path.push(node);
34069                 if (node.leaf || path.length - 1 === level) break;
34070                 var minArea = Infinity;
34071                 var minEnlargement = Infinity;
34072                 var targetNode = void 0;
34073
34074                 for (var i = 0; i < node.children.length; i++) {
34075                   var child = node.children[i];
34076                   var area = bboxArea(child);
34077                   var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
34078
34079                   if (enlargement < minEnlargement) {
34080                     minEnlargement = enlargement;
34081                     minArea = area < minArea ? area : minArea;
34082                     targetNode = child;
34083                   } else if (enlargement === minEnlargement) {
34084                     // otherwise choose one with the smallest area
34085                     if (area < minArea) {
34086                       minArea = area;
34087                       targetNode = child;
34088                     }
34089                   }
34090                 }
34091
34092                 node = targetNode || node.children[0];
34093               }
34094
34095               return node;
34096             }
34097           }, {
34098             key: "_insert",
34099             value: function _insert(item, level, isNode) {
34100               var bbox = isNode ? item : this.toBBox(item);
34101               var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
34102
34103               var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
34104
34105
34106               node.children.push(item);
34107               extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
34108
34109               while (level >= 0) {
34110                 if (insertPath[level].children.length > this._maxEntries) {
34111                   this._split(insertPath, level);
34112
34113                   level--;
34114                 } else break;
34115               } // adjust bboxes along the insertion path
34116
34117
34118               this._adjustParentBBoxes(bbox, insertPath, level);
34119             } // split overflowed node into two
34120
34121           }, {
34122             key: "_split",
34123             value: function _split(insertPath, level) {
34124               var node = insertPath[level];
34125               var M = node.children.length;
34126               var m = this._minEntries;
34127
34128               this._chooseSplitAxis(node, m, M);
34129
34130               var splitIndex = this._chooseSplitIndex(node, m, M);
34131
34132               var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
34133               newNode.height = node.height;
34134               newNode.leaf = node.leaf;
34135               calcBBox(node, this.toBBox);
34136               calcBBox(newNode, this.toBBox);
34137               if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
34138             }
34139           }, {
34140             key: "_splitRoot",
34141             value: function _splitRoot(node, newNode) {
34142               // split root node
34143               this.data = createNode([node, newNode]);
34144               this.data.height = node.height + 1;
34145               this.data.leaf = false;
34146               calcBBox(this.data, this.toBBox);
34147             }
34148           }, {
34149             key: "_chooseSplitIndex",
34150             value: function _chooseSplitIndex(node, m, M) {
34151               var index;
34152               var minOverlap = Infinity;
34153               var minArea = Infinity;
34154
34155               for (var i = m; i <= M - m; i++) {
34156                 var bbox1 = distBBox(node, 0, i, this.toBBox);
34157                 var bbox2 = distBBox(node, i, M, this.toBBox);
34158                 var overlap = intersectionArea(bbox1, bbox2);
34159                 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
34160
34161                 if (overlap < minOverlap) {
34162                   minOverlap = overlap;
34163                   index = i;
34164                   minArea = area < minArea ? area : minArea;
34165                 } else if (overlap === minOverlap) {
34166                   // otherwise choose distribution with minimum area
34167                   if (area < minArea) {
34168                     minArea = area;
34169                     index = i;
34170                   }
34171                 }
34172               }
34173
34174               return index || M - m;
34175             } // sorts node children by the best axis for split
34176
34177           }, {
34178             key: "_chooseSplitAxis",
34179             value: function _chooseSplitAxis(node, m, M) {
34180               var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
34181               var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
34182
34183               var xMargin = this._allDistMargin(node, m, M, compareMinX);
34184
34185               var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
34186               // otherwise it's already sorted by minY
34187
34188
34189               if (xMargin < yMargin) node.children.sort(compareMinX);
34190             } // total margin of all possible split distributions where each node is at least m full
34191
34192           }, {
34193             key: "_allDistMargin",
34194             value: function _allDistMargin(node, m, M, compare) {
34195               node.children.sort(compare);
34196               var toBBox = this.toBBox;
34197               var leftBBox = distBBox(node, 0, m, toBBox);
34198               var rightBBox = distBBox(node, M - m, M, toBBox);
34199               var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
34200
34201               for (var i = m; i < M - m; i++) {
34202                 var child = node.children[i];
34203                 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
34204                 margin += bboxMargin(leftBBox);
34205               }
34206
34207               for (var _i = M - m - 1; _i >= m; _i--) {
34208                 var _child = node.children[_i];
34209                 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
34210                 margin += bboxMargin(rightBBox);
34211               }
34212
34213               return margin;
34214             }
34215           }, {
34216             key: "_adjustParentBBoxes",
34217             value: function _adjustParentBBoxes(bbox, path, level) {
34218               // adjust bboxes along the given tree path
34219               for (var i = level; i >= 0; i--) {
34220                 extend$1(path[i], bbox);
34221               }
34222             }
34223           }, {
34224             key: "_condense",
34225             value: function _condense(path) {
34226               // go through the path, removing empty nodes and updating bboxes
34227               for (var i = path.length - 1, siblings; i >= 0; i--) {
34228                 if (path[i].children.length === 0) {
34229                   if (i > 0) {
34230                     siblings = path[i - 1].children;
34231                     siblings.splice(siblings.indexOf(path[i]), 1);
34232                   } else this.clear();
34233                 } else calcBBox(path[i], this.toBBox);
34234               }
34235             }
34236           }]);
34237
34238           return RBush;
34239         }();
34240
34241         function findItem(item, items, equalsFn) {
34242           if (!equalsFn) return items.indexOf(item);
34243
34244           for (var i = 0; i < items.length; i++) {
34245             if (equalsFn(item, items[i])) return i;
34246           }
34247
34248           return -1;
34249         } // calculate node's bbox from bboxes of its children
34250
34251
34252         function calcBBox(node, toBBox) {
34253           distBBox(node, 0, node.children.length, toBBox, node);
34254         } // min bounding rectangle of node children from k to p-1
34255
34256
34257         function distBBox(node, k, p, toBBox, destNode) {
34258           if (!destNode) destNode = createNode(null);
34259           destNode.minX = Infinity;
34260           destNode.minY = Infinity;
34261           destNode.maxX = -Infinity;
34262           destNode.maxY = -Infinity;
34263
34264           for (var i = k; i < p; i++) {
34265             var child = node.children[i];
34266             extend$1(destNode, node.leaf ? toBBox(child) : child);
34267           }
34268
34269           return destNode;
34270         }
34271
34272         function extend$1(a, b) {
34273           a.minX = Math.min(a.minX, b.minX);
34274           a.minY = Math.min(a.minY, b.minY);
34275           a.maxX = Math.max(a.maxX, b.maxX);
34276           a.maxY = Math.max(a.maxY, b.maxY);
34277           return a;
34278         }
34279
34280         function compareNodeMinX(a, b) {
34281           return a.minX - b.minX;
34282         }
34283
34284         function compareNodeMinY(a, b) {
34285           return a.minY - b.minY;
34286         }
34287
34288         function bboxArea(a) {
34289           return (a.maxX - a.minX) * (a.maxY - a.minY);
34290         }
34291
34292         function bboxMargin(a) {
34293           return a.maxX - a.minX + (a.maxY - a.minY);
34294         }
34295
34296         function enlargedArea(a, b) {
34297           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));
34298         }
34299
34300         function intersectionArea(a, b) {
34301           var minX = Math.max(a.minX, b.minX);
34302           var minY = Math.max(a.minY, b.minY);
34303           var maxX = Math.min(a.maxX, b.maxX);
34304           var maxY = Math.min(a.maxY, b.maxY);
34305           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
34306         }
34307
34308         function contains(a, b) {
34309           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
34310         }
34311
34312         function intersects(a, b) {
34313           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
34314         }
34315
34316         function createNode(children) {
34317           return {
34318             children: children,
34319             height: 1,
34320             leaf: true,
34321             minX: Infinity,
34322             minY: Infinity,
34323             maxX: -Infinity,
34324             maxY: -Infinity
34325           };
34326         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
34327         // combines selection algorithm with binary divide & conquer approach
34328
34329
34330         function multiSelect(arr, left, right, n, compare) {
34331           var stack = [left, right];
34332
34333           while (stack.length) {
34334             right = stack.pop();
34335             left = stack.pop();
34336             if (right - left <= n) continue;
34337             var mid = left + Math.ceil((right - left) / n / 2) * n;
34338             quickselect$1(arr, mid, left, right, compare);
34339             stack.push(left, mid, mid, right);
34340           }
34341         }
34342
34343         var tiler = utilTiler();
34344         var dispatch$1 = dispatch('loaded');
34345         var _tileZoom = 14;
34346         var _krUrlRoot = 'https://www.keepright.at';
34347         var _krData = {
34348           errorTypes: {},
34349           localizeStrings: {}
34350         }; // This gets reassigned if reset
34351
34352         var _cache;
34353
34354         var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
34355         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];
34356
34357         function abortRequest(controller) {
34358           if (controller) {
34359             controller.abort();
34360           }
34361         }
34362
34363         function abortUnwantedRequests(cache, tiles) {
34364           Object.keys(cache.inflightTile).forEach(function (k) {
34365             var wanted = tiles.find(function (tile) {
34366               return k === tile.id;
34367             });
34368
34369             if (!wanted) {
34370               abortRequest(cache.inflightTile[k]);
34371               delete cache.inflightTile[k];
34372             }
34373           });
34374         }
34375
34376         function encodeIssueRtree(d) {
34377           return {
34378             minX: d.loc[0],
34379             minY: d.loc[1],
34380             maxX: d.loc[0],
34381             maxY: d.loc[1],
34382             data: d
34383           };
34384         } // Replace or remove QAItem from rtree
34385
34386
34387         function updateRtree(item, replace) {
34388           _cache.rtree.remove(item, function (a, b) {
34389             return a.data.id === b.data.id;
34390           });
34391
34392           if (replace) {
34393             _cache.rtree.insert(item);
34394           }
34395         }
34396
34397         function tokenReplacements(d) {
34398           if (!(d instanceof QAItem)) return;
34399           var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
34400           var replacements = {};
34401           var issueTemplate = _krData.errorTypes[d.whichType];
34402
34403           if (!issueTemplate) {
34404             /* eslint-disable no-console */
34405             console.log('No Template: ', d.whichType);
34406             console.log('  ', d.description);
34407             /* eslint-enable no-console */
34408
34409             return;
34410           } // some descriptions are just fixed text
34411
34412
34413           if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
34414
34415           var errorRegex = new RegExp(issueTemplate.regex, 'i');
34416           var errorMatch = errorRegex.exec(d.description);
34417
34418           if (!errorMatch) {
34419             /* eslint-disable no-console */
34420             console.log('Unmatched: ', d.whichType);
34421             console.log('  ', d.description);
34422             console.log('  ', errorRegex);
34423             /* eslint-enable no-console */
34424
34425             return;
34426           }
34427
34428           for (var i = 1; i < errorMatch.length; i++) {
34429             // skip first
34430             var capture = errorMatch[i];
34431             var idType = void 0;
34432             idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
34433
34434             if (idType && capture) {
34435               // link IDs if present in the capture
34436               capture = parseError(capture, idType);
34437             } else if (htmlRegex.test(capture)) {
34438               // escape any html in non-IDs
34439               capture = '\\' + capture + '\\';
34440             } else {
34441               var compare = capture.toLowerCase();
34442
34443               if (_krData.localizeStrings[compare]) {
34444                 // some replacement strings can be localized
34445                 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34446               }
34447             }
34448
34449             replacements['var' + i] = capture;
34450           }
34451
34452           return replacements;
34453         }
34454
34455         function parseError(capture, idType) {
34456           var compare = capture.toLowerCase();
34457
34458           if (_krData.localizeStrings[compare]) {
34459             // some replacement strings can be localized
34460             capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34461           }
34462
34463           switch (idType) {
34464             // link a string like "this node"
34465             case 'this':
34466               capture = linkErrorObject(capture);
34467               break;
34468
34469             case 'url':
34470               capture = linkURL(capture);
34471               break;
34472             // link an entity ID
34473
34474             case 'n':
34475             case 'w':
34476             case 'r':
34477               capture = linkEntity(idType + capture);
34478               break;
34479             // some errors have more complex ID lists/variance
34480
34481             case '20':
34482               capture = parse20(capture);
34483               break;
34484
34485             case '211':
34486               capture = parse211(capture);
34487               break;
34488
34489             case '231':
34490               capture = parse231(capture);
34491               break;
34492
34493             case '294':
34494               capture = parse294(capture);
34495               break;
34496
34497             case '370':
34498               capture = parse370(capture);
34499               break;
34500           }
34501
34502           return capture;
34503
34504           function linkErrorObject(d) {
34505             return "<a class=\"error_object_link\">".concat(d, "</a>");
34506           }
34507
34508           function linkEntity(d) {
34509             return "<a class=\"error_entity_link\">".concat(d, "</a>");
34510           }
34511
34512           function linkURL(d) {
34513             return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
34514           } // arbitrary node list of form: #ID, #ID, #ID...
34515
34516
34517           function parse211(capture) {
34518             var newList = [];
34519             var items = capture.split(', ');
34520             items.forEach(function (item) {
34521               // ID has # at the front
34522               var id = linkEntity('n' + item.slice(1));
34523               newList.push(id);
34524             });
34525             return newList.join(', ');
34526           } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
34527
34528
34529           function parse231(capture) {
34530             var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
34531
34532             var items = capture.split('),');
34533             items.forEach(function (item) {
34534               var match = item.match(/\#(\d+)\((.+)\)?/);
34535
34536               if (match !== null && match.length > 2) {
34537                 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
34538                   layer: match[2]
34539                 }));
34540               }
34541             });
34542             return newList.join(', ');
34543           } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
34544
34545
34546           function parse294(capture) {
34547             var newList = [];
34548             var items = capture.split(',');
34549             items.forEach(function (item) {
34550               // item of form "from/to node/relation #ID"
34551               item = item.split(' '); // to/from role is more clear in quotes
34552
34553               var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
34554
34555               var idType = item[1].slice(0, 1); // ID has # at the front
34556
34557               var id = item[2].slice(1);
34558               id = linkEntity(idType + id);
34559               newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
34560             });
34561             return newList.join(', ');
34562           } // may or may not include the string "(including the name 'name')"
34563
34564
34565           function parse370(capture) {
34566             if (!capture) return '';
34567             var match = capture.match(/\(including the name (\'.+\')\)/);
34568
34569             if (match && match.length) {
34570               return _t('QA.keepRight.errorTypes.370.including_the_name', {
34571                 name: match[1]
34572               });
34573             }
34574
34575             return '';
34576           } // arbitrary node list of form: #ID,#ID,#ID...
34577
34578
34579           function parse20(capture) {
34580             var newList = [];
34581             var items = capture.split(',');
34582             items.forEach(function (item) {
34583               // ID has # at the front
34584               var id = linkEntity('n' + item.slice(1));
34585               newList.push(id);
34586             });
34587             return newList.join(', ');
34588           }
34589         }
34590
34591         var serviceKeepRight = {
34592           title: 'keepRight',
34593           init: function init() {
34594             _mainFileFetcher.get('keepRight').then(function (d) {
34595               return _krData = d;
34596             });
34597
34598             if (!_cache) {
34599               this.reset();
34600             }
34601
34602             this.event = utilRebind(this, dispatch$1, 'on');
34603           },
34604           reset: function reset() {
34605             if (_cache) {
34606               Object.values(_cache.inflightTile).forEach(abortRequest);
34607             }
34608
34609             _cache = {
34610               data: {},
34611               loadedTile: {},
34612               inflightTile: {},
34613               inflightPost: {},
34614               closed: {},
34615               rtree: new RBush()
34616             };
34617           },
34618           // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
34619           loadIssues: function loadIssues(projection) {
34620             var _this = this;
34621
34622             var options = {
34623               format: 'geojson',
34624               ch: _krRuleset
34625             }; // determine the needed tiles to cover the view
34626
34627             var tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
34628
34629             abortUnwantedRequests(_cache, tiles); // issue new requests..
34630
34631             tiles.forEach(function (tile) {
34632               if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
34633
34634               var _tile$extent$rectangl = tile.extent.rectangle(),
34635                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34636                   left = _tile$extent$rectangl2[0],
34637                   top = _tile$extent$rectangl2[1],
34638                   right = _tile$extent$rectangl2[2],
34639                   bottom = _tile$extent$rectangl2[3];
34640
34641               var params = Object.assign({}, options, {
34642                 left: left,
34643                 bottom: bottom,
34644                 right: right,
34645                 top: top
34646               });
34647               var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
34648               var controller = new AbortController();
34649               _cache.inflightTile[tile.id] = controller;
34650               d3_json(url, {
34651                 signal: controller.signal
34652               }).then(function (data) {
34653                 delete _cache.inflightTile[tile.id];
34654                 _cache.loadedTile[tile.id] = true;
34655
34656                 if (!data || !data.features || !data.features.length) {
34657                   throw new Error('No Data');
34658                 }
34659
34660                 data.features.forEach(function (feature) {
34661                   var _feature$properties = feature.properties,
34662                       itemType = _feature$properties.error_type,
34663                       id = _feature$properties.error_id,
34664                       _feature$properties$c = _feature$properties.comment,
34665                       comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
34666                       objectId = _feature$properties.object_id,
34667                       objectType = _feature$properties.object_type,
34668                       schema = _feature$properties.schema,
34669                       title = _feature$properties.title;
34670                   var loc = feature.geometry.coordinates,
34671                       _feature$properties$d = feature.properties.description,
34672                       description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
34673                   //  Error 191 = "highway-highway"
34674                   //  Error 190 = "intersections without junctions"  (parent)
34675
34676                   var issueTemplate = _krData.errorTypes[itemType];
34677                   var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
34678
34679                   var whichType = issueTemplate ? itemType : parentIssueType;
34680                   var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
34681                   // This is done to make them easier to linkify and translate.
34682
34683                   switch (whichType) {
34684                     case '170':
34685                       description = "This feature has a FIXME tag: ".concat(description);
34686                       break;
34687
34688                     case '292':
34689                     case '293':
34690                       description = description.replace('A turn-', 'This turn-');
34691                       break;
34692
34693                     case '294':
34694                     case '295':
34695                     case '296':
34696                     case '297':
34697                     case '298':
34698                       description = "This turn-restriction~".concat(description);
34699                       break;
34700
34701                     case '300':
34702                       description = 'This highway is missing a maxspeed tag';
34703                       break;
34704
34705                     case '411':
34706                     case '412':
34707                     case '413':
34708                       description = "This feature~".concat(description);
34709                       break;
34710                   } // move markers slightly so it doesn't obscure the geometry,
34711                   // then move markers away from other coincident markers
34712
34713
34714                   var coincident = false;
34715
34716                   do {
34717                     // first time, move marker up. after that, move marker right.
34718                     var delta = coincident ? [0.00001, 0] : [0, 0.00001];
34719                     loc = geoVecAdd(loc, delta);
34720                     var bbox = geoExtent(loc).bbox();
34721                     coincident = _cache.rtree.search(bbox).length;
34722                   } while (coincident);
34723
34724                   var d = new QAItem(loc, _this, itemType, id, {
34725                     comment: comment,
34726                     description: description,
34727                     whichType: whichType,
34728                     parentIssueType: parentIssueType,
34729                     severity: whichTemplate.severity || 'error',
34730                     objectId: objectId,
34731                     objectType: objectType,
34732                     schema: schema,
34733                     title: title
34734                   });
34735                   d.replacements = tokenReplacements(d);
34736                   _cache.data[id] = d;
34737
34738                   _cache.rtree.insert(encodeIssueRtree(d));
34739                 });
34740                 dispatch$1.call('loaded');
34741               })["catch"](function () {
34742                 delete _cache.inflightTile[tile.id];
34743                 _cache.loadedTile[tile.id] = true;
34744               });
34745             });
34746           },
34747           postUpdate: function postUpdate(d, callback) {
34748             var _this2 = this;
34749
34750             if (_cache.inflightPost[d.id]) {
34751               return callback({
34752                 message: 'Error update already inflight',
34753                 status: -2
34754               }, d);
34755             }
34756
34757             var params = {
34758               schema: d.schema,
34759               id: d.id
34760             };
34761
34762             if (d.newStatus) {
34763               params.st = d.newStatus;
34764             }
34765
34766             if (d.newComment !== undefined) {
34767               params.co = d.newComment;
34768             } // NOTE: This throws a CORS err, but it seems successful.
34769             // We don't care too much about the response, so this is fine.
34770
34771
34772             var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
34773             var controller = new AbortController();
34774             _cache.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
34775             // (worst case scenario the request truly fails and issue will show up if iD restarts)
34776
34777             d3_json(url, {
34778               signal: controller.signal
34779             })["finally"](function () {
34780               delete _cache.inflightPost[d.id];
34781
34782               if (d.newStatus === 'ignore') {
34783                 // ignore permanently (false positive)
34784                 _this2.removeItem(d);
34785               } else if (d.newStatus === 'ignore_t') {
34786                 // ignore temporarily (error fixed)
34787                 _this2.removeItem(d);
34788
34789                 _cache.closed["".concat(d.schema, ":").concat(d.id)] = true;
34790               } else {
34791                 d = _this2.replaceItem(d.update({
34792                   comment: d.newComment,
34793                   newComment: undefined,
34794                   newState: undefined
34795                 }));
34796               }
34797
34798               if (callback) callback(null, d);
34799             });
34800           },
34801           // Get all cached QAItems covering the viewport
34802           getItems: function getItems(projection) {
34803             var viewport = projection.clipExtent();
34804             var min = [viewport[0][0], viewport[1][1]];
34805             var max = [viewport[1][0], viewport[0][1]];
34806             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
34807             return _cache.rtree.search(bbox).map(function (d) {
34808               return d.data;
34809             });
34810           },
34811           // Get a QAItem from cache
34812           // NOTE: Don't change method name until UI v3 is merged
34813           getError: function getError(id) {
34814             return _cache.data[id];
34815           },
34816           // Replace a single QAItem in the cache
34817           replaceItem: function replaceItem(item) {
34818             if (!(item instanceof QAItem) || !item.id) return;
34819             _cache.data[item.id] = item;
34820             updateRtree(encodeIssueRtree(item), true); // true = replace
34821
34822             return item;
34823           },
34824           // Remove a single QAItem from the cache
34825           removeItem: function removeItem(item) {
34826             if (!(item instanceof QAItem) || !item.id) return;
34827             delete _cache.data[item.id];
34828             updateRtree(encodeIssueRtree(item), false); // false = remove
34829           },
34830           issueURL: function issueURL(item) {
34831             return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
34832           },
34833           // Get an array of issues closed during this session.
34834           // Used to populate `closed:keepright` changeset tag
34835           getClosedIDs: function getClosedIDs() {
34836             return Object.keys(_cache.closed).sort();
34837           }
34838         };
34839
34840         var tiler$1 = utilTiler();
34841         var dispatch$2 = dispatch('loaded');
34842         var _tileZoom$1 = 14;
34843         var _impOsmUrls = {
34844           ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
34845           mr: 'https://grab.community.improve-osm.org/missingGeoService',
34846           tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
34847         };
34848         var _impOsmData = {
34849           icons: {}
34850         }; // This gets reassigned if reset
34851
34852         var _cache$1;
34853
34854         function abortRequest$1(i) {
34855           Object.values(i).forEach(function (controller) {
34856             if (controller) {
34857               controller.abort();
34858             }
34859           });
34860         }
34861
34862         function abortUnwantedRequests$1(cache, tiles) {
34863           Object.keys(cache.inflightTile).forEach(function (k) {
34864             var wanted = tiles.find(function (tile) {
34865               return k === tile.id;
34866             });
34867
34868             if (!wanted) {
34869               abortRequest$1(cache.inflightTile[k]);
34870               delete cache.inflightTile[k];
34871             }
34872           });
34873         }
34874
34875         function encodeIssueRtree$1(d) {
34876           return {
34877             minX: d.loc[0],
34878             minY: d.loc[1],
34879             maxX: d.loc[0],
34880             maxY: d.loc[1],
34881             data: d
34882           };
34883         } // Replace or remove QAItem from rtree
34884
34885
34886         function updateRtree$1(item, replace) {
34887           _cache$1.rtree.remove(item, function (a, b) {
34888             return a.data.id === b.data.id;
34889           });
34890
34891           if (replace) {
34892             _cache$1.rtree.insert(item);
34893           }
34894         }
34895
34896         function linkErrorObject(d) {
34897           return "<a class=\"error_object_link\">".concat(d, "</a>");
34898         }
34899
34900         function linkEntity(d) {
34901           return "<a class=\"error_entity_link\">".concat(d, "</a>");
34902         }
34903
34904         function pointAverage(points) {
34905           if (points.length) {
34906             var sum = points.reduce(function (acc, point) {
34907               return geoVecAdd(acc, [point.lon, point.lat]);
34908             }, [0, 0]);
34909             return geoVecScale(sum, 1 / points.length);
34910           } else {
34911             return [0, 0];
34912           }
34913         }
34914
34915         function relativeBearing(p1, p2) {
34916           var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
34917
34918           if (angle < 0) {
34919             angle += 2 * Math.PI;
34920           } // Return degrees
34921
34922
34923           return angle * 180 / Math.PI;
34924         } // Assuming range [0,360)
34925
34926
34927         function cardinalDirection(bearing) {
34928           var dir = 45 * Math.round(bearing / 45);
34929           var compass = {
34930             0: 'north',
34931             45: 'northeast',
34932             90: 'east',
34933             135: 'southeast',
34934             180: 'south',
34935             225: 'southwest',
34936             270: 'west',
34937             315: 'northwest',
34938             360: 'north'
34939           };
34940           return _t("QA.improveOSM.directions.".concat(compass[dir]));
34941         } // Errors shouldn't obscure each other
34942
34943
34944         function preventCoincident(loc, bumpUp) {
34945           var coincident = false;
34946
34947           do {
34948             // first time, move marker up. after that, move marker right.
34949             var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
34950             loc = geoVecAdd(loc, delta);
34951             var bbox = geoExtent(loc).bbox();
34952             coincident = _cache$1.rtree.search(bbox).length;
34953           } while (coincident);
34954
34955           return loc;
34956         }
34957
34958         var serviceImproveOSM = {
34959           title: 'improveOSM',
34960           init: function init() {
34961             _mainFileFetcher.get('qa_data').then(function (d) {
34962               return _impOsmData = d.improveOSM;
34963             });
34964
34965             if (!_cache$1) {
34966               this.reset();
34967             }
34968
34969             this.event = utilRebind(this, dispatch$2, 'on');
34970           },
34971           reset: function reset() {
34972             if (_cache$1) {
34973               Object.values(_cache$1.inflightTile).forEach(abortRequest$1);
34974             }
34975
34976             _cache$1 = {
34977               data: {},
34978               loadedTile: {},
34979               inflightTile: {},
34980               inflightPost: {},
34981               closed: {},
34982               rtree: new RBush()
34983             };
34984           },
34985           loadIssues: function loadIssues(projection) {
34986             var _this = this;
34987
34988             var options = {
34989               client: 'iD',
34990               status: 'OPEN',
34991               zoom: '19' // Use a high zoom so that clusters aren't returned
34992
34993             }; // determine the needed tiles to cover the view
34994
34995             var tiles = tiler$1.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
34996
34997             abortUnwantedRequests$1(_cache$1, tiles); // issue new requests..
34998
34999             tiles.forEach(function (tile) {
35000               if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
35001
35002               var _tile$extent$rectangl = tile.extent.rectangle(),
35003                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
35004                   east = _tile$extent$rectangl2[0],
35005                   north = _tile$extent$rectangl2[1],
35006                   west = _tile$extent$rectangl2[2],
35007                   south = _tile$extent$rectangl2[3];
35008
35009               var params = Object.assign({}, options, {
35010                 east: east,
35011                 south: south,
35012                 west: west,
35013                 north: north
35014               }); // 3 separate requests to store for each tile
35015
35016               var requests = {};
35017               Object.keys(_impOsmUrls).forEach(function (k) {
35018                 // We exclude WATER from missing geometry as it doesn't seem useful
35019                 // We use most confident one-way and turn restrictions only, still have false positives
35020                 var kParams = Object.assign({}, params, k === 'mr' ? {
35021                   type: 'PARKING,ROAD,BOTH,PATH'
35022                 } : {
35023                   confidenceLevel: 'C1'
35024                 });
35025                 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
35026                 var controller = new AbortController();
35027                 requests[k] = controller;
35028                 d3_json(url, {
35029                   signal: controller.signal
35030                 }).then(function (data) {
35031                   delete _cache$1.inflightTile[tile.id][k];
35032
35033                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
35034                     delete _cache$1.inflightTile[tile.id];
35035                     _cache$1.loadedTile[tile.id] = true;
35036                   } // Road segments at high zoom == oneways
35037
35038
35039                   if (data.roadSegments) {
35040                     data.roadSegments.forEach(function (feature) {
35041                       // Position error at the approximate middle of the segment
35042                       var points = feature.points,
35043                           wayId = feature.wayId,
35044                           fromNodeId = feature.fromNodeId,
35045                           toNodeId = feature.toNodeId;
35046                       var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
35047                       var mid = points.length / 2;
35048                       var loc; // Even number of points, find midpoint of the middle two
35049                       // Odd number of points, use position of very middle point
35050
35051                       if (mid % 1 === 0) {
35052                         loc = pointAverage([points[mid - 1], points[mid]]);
35053                       } else {
35054                         mid = points[Math.floor(mid)];
35055                         loc = [mid.lon, mid.lat];
35056                       } // One-ways can land on same segment in opposite direction
35057
35058
35059                       loc = preventCoincident(loc, false);
35060                       var d = new QAItem(loc, _this, k, itemId, {
35061                         issueKey: k,
35062                         // used as a category
35063                         identifier: {
35064                           // used to post changes
35065                           wayId: wayId,
35066                           fromNodeId: fromNodeId,
35067                           toNodeId: toNodeId
35068                         },
35069                         objectId: wayId,
35070                         objectType: 'way'
35071                       }); // Variables used in the description
35072
35073                       d.replacements = {
35074                         percentage: feature.percentOfTrips,
35075                         num_trips: feature.numberOfTrips,
35076                         highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
35077                         from_node: linkEntity('n' + feature.fromNodeId),
35078                         to_node: linkEntity('n' + feature.toNodeId)
35079                       };
35080                       _cache$1.data[d.id] = d;
35081
35082                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35083                     });
35084                   } // Tiles at high zoom == missing roads
35085
35086
35087                   if (data.tiles) {
35088                     data.tiles.forEach(function (feature) {
35089                       var type = feature.type,
35090                           x = feature.x,
35091                           y = feature.y,
35092                           numberOfTrips = feature.numberOfTrips;
35093                       var geoType = type.toLowerCase();
35094                       var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
35095                       // Missing geometry could happen to land on another error
35096
35097                       var loc = pointAverage(feature.points);
35098                       loc = preventCoincident(loc, false);
35099                       var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
35100                         issueKey: k,
35101                         identifier: {
35102                           x: x,
35103                           y: y
35104                         }
35105                       });
35106                       d.replacements = {
35107                         num_trips: numberOfTrips,
35108                         geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
35109                       }; // -1 trips indicates data came from a 3rd party
35110
35111                       if (numberOfTrips === -1) {
35112                         d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
35113                       }
35114
35115                       _cache$1.data[d.id] = d;
35116
35117                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35118                     });
35119                   } // Entities at high zoom == turn restrictions
35120
35121
35122                   if (data.entities) {
35123                     data.entities.forEach(function (feature) {
35124                       var point = feature.point,
35125                           id = feature.id,
35126                           segments = feature.segments,
35127                           numberOfPasses = feature.numberOfPasses,
35128                           turnType = feature.turnType;
35129                       var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
35130                       // We also want to bump the error up so node is accessible
35131
35132                       var loc = preventCoincident([point.lon, point.lat], true); // Elements are presented in a strange way
35133
35134                       var ids = id.split(',');
35135                       var from_way = ids[0];
35136                       var via_node = ids[3];
35137                       var to_way = ids[2].split(':')[1];
35138                       var d = new QAItem(loc, _this, k, itemId, {
35139                         issueKey: k,
35140                         identifier: id,
35141                         objectId: via_node,
35142                         objectType: 'node'
35143                       }); // Travel direction along from_way clarifies the turn restriction
35144
35145                       var _segments$0$points = _slicedToArray(segments[0].points, 2),
35146                           p1 = _segments$0$points[0],
35147                           p2 = _segments$0$points[1];
35148
35149                       var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
35150
35151                       d.replacements = {
35152                         num_passed: numberOfPasses,
35153                         num_trips: segments[0].numberOfTrips,
35154                         turn_restriction: turnType.toLowerCase(),
35155                         from_way: linkEntity('w' + from_way),
35156                         to_way: linkEntity('w' + to_way),
35157                         travel_direction: dir_of_travel,
35158                         junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
35159                       };
35160                       _cache$1.data[d.id] = d;
35161
35162                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35163
35164                       dispatch$2.call('loaded');
35165                     });
35166                   }
35167                 })["catch"](function () {
35168                   delete _cache$1.inflightTile[tile.id][k];
35169
35170                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
35171                     delete _cache$1.inflightTile[tile.id];
35172                     _cache$1.loadedTile[tile.id] = true;
35173                   }
35174                 });
35175               });
35176               _cache$1.inflightTile[tile.id] = requests;
35177             });
35178           },
35179           getComments: function getComments(item) {
35180             var _this2 = this;
35181
35182             // If comments already retrieved no need to do so again
35183             if (item.comments) {
35184               return Promise.resolve(item);
35185             }
35186
35187             var key = item.issueKey;
35188             var qParams = {};
35189
35190             if (key === 'ow') {
35191               qParams = item.identifier;
35192             } else if (key === 'mr') {
35193               qParams.tileX = item.identifier.x;
35194               qParams.tileY = item.identifier.y;
35195             } else if (key === 'tr') {
35196               qParams.targetId = item.identifier;
35197             }
35198
35199             var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
35200
35201             var cacheComments = function cacheComments(data) {
35202               // Assign directly for immediate use afterwards
35203               // comments are served newest to oldest
35204               item.comments = data.comments ? data.comments.reverse() : [];
35205
35206               _this2.replaceItem(item);
35207             };
35208
35209             return d3_json(url).then(cacheComments).then(function () {
35210               return item;
35211             });
35212           },
35213           postUpdate: function postUpdate(d, callback) {
35214             if (!serviceOsm.authenticated()) {
35215               // Username required in payload
35216               return callback({
35217                 message: 'Not Authenticated',
35218                 status: -3
35219               }, d);
35220             }
35221
35222             if (_cache$1.inflightPost[d.id]) {
35223               return callback({
35224                 message: 'Error update already inflight',
35225                 status: -2
35226               }, d);
35227             } // Payload can only be sent once username is established
35228
35229
35230             serviceOsm.userDetails(sendPayload.bind(this));
35231
35232             function sendPayload(err, user) {
35233               var _this3 = this;
35234
35235               if (err) {
35236                 return callback(err, d);
35237               }
35238
35239               var key = d.issueKey;
35240               var url = "".concat(_impOsmUrls[key], "/comment");
35241               var payload = {
35242                 username: user.display_name,
35243                 targetIds: [d.identifier]
35244               };
35245
35246               if (d.newStatus) {
35247                 payload.status = d.newStatus;
35248                 payload.text = 'status changed';
35249               } // Comment take place of default text
35250
35251
35252               if (d.newComment) {
35253                 payload.text = d.newComment;
35254               }
35255
35256               var controller = new AbortController();
35257               _cache$1.inflightPost[d.id] = controller;
35258               var options = {
35259                 method: 'POST',
35260                 signal: controller.signal,
35261                 body: JSON.stringify(payload)
35262               };
35263               d3_json(url, options).then(function () {
35264                 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
35265
35266                 if (!d.newStatus) {
35267                   var now = new Date();
35268                   var comments = d.comments ? d.comments : [];
35269                   comments.push({
35270                     username: payload.username,
35271                     text: payload.text,
35272                     timestamp: now.getTime() / 1000
35273                   });
35274
35275                   _this3.replaceItem(d.update({
35276                     comments: comments,
35277                     newComment: undefined
35278                   }));
35279                 } else {
35280                   _this3.removeItem(d);
35281
35282                   if (d.newStatus === 'SOLVED') {
35283                     // Keep track of the number of issues closed per type to tag the changeset
35284                     if (!(d.issueKey in _cache$1.closed)) {
35285                       _cache$1.closed[d.issueKey] = 0;
35286                     }
35287
35288                     _cache$1.closed[d.issueKey] += 1;
35289                   }
35290                 }
35291
35292                 if (callback) callback(null, d);
35293               })["catch"](function (err) {
35294                 delete _cache$1.inflightPost[d.id];
35295                 if (callback) callback(err.message);
35296               });
35297             }
35298           },
35299           // Get all cached QAItems covering the viewport
35300           getItems: function getItems(projection) {
35301             var viewport = projection.clipExtent();
35302             var min = [viewport[0][0], viewport[1][1]];
35303             var max = [viewport[1][0], viewport[0][1]];
35304             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
35305             return _cache$1.rtree.search(bbox).map(function (d) {
35306               return d.data;
35307             });
35308           },
35309           // Get a QAItem from cache
35310           // NOTE: Don't change method name until UI v3 is merged
35311           getError: function getError(id) {
35312             return _cache$1.data[id];
35313           },
35314           // get the name of the icon to display for this item
35315           getIcon: function getIcon(itemType) {
35316             return _impOsmData.icons[itemType];
35317           },
35318           // Replace a single QAItem in the cache
35319           replaceItem: function replaceItem(issue) {
35320             if (!(issue instanceof QAItem) || !issue.id) return;
35321             _cache$1.data[issue.id] = issue;
35322             updateRtree$1(encodeIssueRtree$1(issue), true); // true = replace
35323
35324             return issue;
35325           },
35326           // Remove a single QAItem from the cache
35327           removeItem: function removeItem(issue) {
35328             if (!(issue instanceof QAItem) || !issue.id) return;
35329             delete _cache$1.data[issue.id];
35330             updateRtree$1(encodeIssueRtree$1(issue), false); // false = remove
35331           },
35332           // Used to populate `closed:improveosm:*` changeset tags
35333           getClosedCounts: function getClosedCounts() {
35334             return _cache$1.closed;
35335           }
35336         };
35337
35338         var quot = /"/g;
35339
35340         // B.2.3.2.1 CreateHTML(string, tag, attribute, value)
35341         // https://tc39.es/ecma262/#sec-createhtml
35342         var createHtml = function (string, tag, attribute, value) {
35343           var S = String(requireObjectCoercible(string));
35344           var p1 = '<' + tag;
35345           if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
35346           return p1 + '>' + S + '</' + tag + '>';
35347         };
35348
35349         // check the existence of a method, lowercase
35350         // of a tag and escaping quotes in arguments
35351         var stringHtmlForced = function (METHOD_NAME) {
35352           return fails(function () {
35353             var test = ''[METHOD_NAME]('"');
35354             return test !== test.toLowerCase() || test.split('"').length > 3;
35355           });
35356         };
35357
35358         // `String.prototype.link` method
35359         // https://tc39.es/ecma262/#sec-string.prototype.link
35360         _export({ target: 'String', proto: true, forced: stringHtmlForced('link') }, {
35361           link: function link(url) {
35362             return createHtml(this, 'a', 'href', url);
35363           }
35364         });
35365
35366         var $trimEnd = stringTrim.end;
35367
35368
35369         var FORCED$e = stringTrimForced('trimEnd');
35370
35371         var trimEnd = FORCED$e ? function trimEnd() {
35372           return $trimEnd(this);
35373         } : ''.trimEnd;
35374
35375         // `String.prototype.{ trimEnd, trimRight }` methods
35376         // https://tc39.es/ecma262/#sec-string.prototype.trimend
35377         // https://tc39.es/ecma262/#String.prototype.trimright
35378         _export({ target: 'String', proto: true, forced: FORCED$e }, {
35379           trimEnd: trimEnd,
35380           trimRight: trimEnd
35381         });
35382
35383         var defaults = createCommonjsModule(function (module) {
35384           function getDefaults() {
35385             return {
35386               baseUrl: null,
35387               breaks: false,
35388               gfm: true,
35389               headerIds: true,
35390               headerPrefix: '',
35391               highlight: null,
35392               langPrefix: 'language-',
35393               mangle: true,
35394               pedantic: false,
35395               renderer: null,
35396               sanitize: false,
35397               sanitizer: null,
35398               silent: false,
35399               smartLists: false,
35400               smartypants: false,
35401               tokenizer: null,
35402               walkTokens: null,
35403               xhtml: false
35404             };
35405           }
35406
35407           function changeDefaults(newDefaults) {
35408             module.exports.defaults = newDefaults;
35409           }
35410
35411           module.exports = {
35412             defaults: getDefaults(),
35413             getDefaults: getDefaults,
35414             changeDefaults: changeDefaults
35415           };
35416         });
35417
35418         /**
35419          * Helpers
35420          */
35421         var escapeTest = /[&<>"']/;
35422         var escapeReplace = /[&<>"']/g;
35423         var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
35424         var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
35425         var escapeReplacements = {
35426           '&': '&amp;',
35427           '<': '&lt;',
35428           '>': '&gt;',
35429           '"': '&quot;',
35430           "'": '&#39;'
35431         };
35432
35433         var getEscapeReplacement = function getEscapeReplacement(ch) {
35434           return escapeReplacements[ch];
35435         };
35436
35437         function escape$1(html, encode) {
35438           if (encode) {
35439             if (escapeTest.test(html)) {
35440               return html.replace(escapeReplace, getEscapeReplacement);
35441             }
35442           } else {
35443             if (escapeTestNoEncode.test(html)) {
35444               return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
35445             }
35446           }
35447
35448           return html;
35449         }
35450
35451         var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
35452
35453         function unescape$1(html) {
35454           // explicitly match decimal, hex, and named HTML entities
35455           return html.replace(unescapeTest, function (_, n) {
35456             n = n.toLowerCase();
35457             if (n === 'colon') return ':';
35458
35459             if (n.charAt(0) === '#') {
35460               return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
35461             }
35462
35463             return '';
35464           });
35465         }
35466
35467         var caret = /(^|[^\[])\^/g;
35468
35469         function edit(regex, opt) {
35470           regex = regex.source || regex;
35471           opt = opt || '';
35472           var obj = {
35473             replace: function replace(name, val) {
35474               val = val.source || val;
35475               val = val.replace(caret, '$1');
35476               regex = regex.replace(name, val);
35477               return obj;
35478             },
35479             getRegex: function getRegex() {
35480               return new RegExp(regex, opt);
35481             }
35482           };
35483           return obj;
35484         }
35485
35486         var nonWordAndColonTest = /[^\w:]/g;
35487         var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
35488
35489         function cleanUrl(sanitize, base, href) {
35490           if (sanitize) {
35491             var prot;
35492
35493             try {
35494               prot = decodeURIComponent(unescape$1(href)).replace(nonWordAndColonTest, '').toLowerCase();
35495             } catch (e) {
35496               return null;
35497             }
35498
35499             if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
35500               return null;
35501             }
35502           }
35503
35504           if (base && !originIndependentUrl.test(href)) {
35505             href = resolveUrl(base, href);
35506           }
35507
35508           try {
35509             href = encodeURI(href).replace(/%25/g, '%');
35510           } catch (e) {
35511             return null;
35512           }
35513
35514           return href;
35515         }
35516
35517         var baseUrls = {};
35518         var justDomain = /^[^:]+:\/*[^/]*$/;
35519         var protocol = /^([^:]+:)[\s\S]*$/;
35520         var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
35521
35522         function resolveUrl(base, href) {
35523           if (!baseUrls[' ' + base]) {
35524             // we can ignore everything in base after the last slash of its path component,
35525             // but we might need to add _that_
35526             // https://tools.ietf.org/html/rfc3986#section-3
35527             if (justDomain.test(base)) {
35528               baseUrls[' ' + base] = base + '/';
35529             } else {
35530               baseUrls[' ' + base] = rtrim$1(base, '/', true);
35531             }
35532           }
35533
35534           base = baseUrls[' ' + base];
35535           var relativeBase = base.indexOf(':') === -1;
35536
35537           if (href.substring(0, 2) === '//') {
35538             if (relativeBase) {
35539               return href;
35540             }
35541
35542             return base.replace(protocol, '$1') + href;
35543           } else if (href.charAt(0) === '/') {
35544             if (relativeBase) {
35545               return href;
35546             }
35547
35548             return base.replace(domain, '$1') + href;
35549           } else {
35550             return base + href;
35551           }
35552         }
35553
35554         var noopTest = {
35555           exec: function noopTest() {}
35556         };
35557
35558         function merge$1(obj) {
35559           var i = 1,
35560               target,
35561               key;
35562
35563           for (; i < arguments.length; i++) {
35564             target = arguments[i];
35565
35566             for (key in target) {
35567               if (Object.prototype.hasOwnProperty.call(target, key)) {
35568                 obj[key] = target[key];
35569               }
35570             }
35571           }
35572
35573           return obj;
35574         }
35575
35576         function splitCells(tableRow, count) {
35577           // ensure that every cell-delimiting pipe has a space
35578           // before it to distinguish it from an escaped pipe
35579           var row = tableRow.replace(/\|/g, function (match, offset, str) {
35580             var escaped = false,
35581                 curr = offset;
35582
35583             while (--curr >= 0 && str[curr] === '\\') {
35584               escaped = !escaped;
35585             }
35586
35587             if (escaped) {
35588               // odd number of slashes means | is escaped
35589               // so we leave it alone
35590               return '|';
35591             } else {
35592               // add space before unescaped |
35593               return ' |';
35594             }
35595           }),
35596               cells = row.split(/ \|/);
35597           var i = 0;
35598
35599           if (cells.length > count) {
35600             cells.splice(count);
35601           } else {
35602             while (cells.length < count) {
35603               cells.push('');
35604             }
35605           }
35606
35607           for (; i < cells.length; i++) {
35608             // leading or trailing whitespace is ignored per the gfm spec
35609             cells[i] = cells[i].trim().replace(/\\\|/g, '|');
35610           }
35611
35612           return cells;
35613         } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
35614         // /c*$/ is vulnerable to REDOS.
35615         // invert: Remove suffix of non-c chars instead. Default falsey.
35616
35617
35618         function rtrim$1(str, c, invert) {
35619           var l = str.length;
35620
35621           if (l === 0) {
35622             return '';
35623           } // Length of suffix matching the invert condition.
35624
35625
35626           var suffLen = 0; // Step left until we fail to match the invert condition.
35627
35628           while (suffLen < l) {
35629             var currChar = str.charAt(l - suffLen - 1);
35630
35631             if (currChar === c && !invert) {
35632               suffLen++;
35633             } else if (currChar !== c && invert) {
35634               suffLen++;
35635             } else {
35636               break;
35637             }
35638           }
35639
35640           return str.substr(0, l - suffLen);
35641         }
35642
35643         function findClosingBracket(str, b) {
35644           if (str.indexOf(b[1]) === -1) {
35645             return -1;
35646           }
35647
35648           var l = str.length;
35649           var level = 0,
35650               i = 0;
35651
35652           for (; i < l; i++) {
35653             if (str[i] === '\\') {
35654               i++;
35655             } else if (str[i] === b[0]) {
35656               level++;
35657             } else if (str[i] === b[1]) {
35658               level--;
35659
35660               if (level < 0) {
35661                 return i;
35662               }
35663             }
35664           }
35665
35666           return -1;
35667         }
35668
35669         function checkSanitizeDeprecation(opt) {
35670           if (opt && opt.sanitize && !opt.silent) {
35671             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');
35672           }
35673         } // copied from https://stackoverflow.com/a/5450113/806777
35674
35675
35676         function repeatString(pattern, count) {
35677           if (count < 1) {
35678             return '';
35679           }
35680
35681           var result = '';
35682
35683           while (count > 1) {
35684             if (count & 1) {
35685               result += pattern;
35686             }
35687
35688             count >>= 1;
35689             pattern += pattern;
35690           }
35691
35692           return result + pattern;
35693         }
35694
35695         var helpers = {
35696           escape: escape$1,
35697           unescape: unescape$1,
35698           edit: edit,
35699           cleanUrl: cleanUrl,
35700           resolveUrl: resolveUrl,
35701           noopTest: noopTest,
35702           merge: merge$1,
35703           splitCells: splitCells,
35704           rtrim: rtrim$1,
35705           findClosingBracket: findClosingBracket,
35706           checkSanitizeDeprecation: checkSanitizeDeprecation,
35707           repeatString: repeatString
35708         };
35709
35710         var defaults$1 = defaults.defaults;
35711         var rtrim$2 = helpers.rtrim,
35712             splitCells$1 = helpers.splitCells,
35713             _escape = helpers.escape,
35714             findClosingBracket$1 = helpers.findClosingBracket;
35715
35716         function outputLink(cap, link, raw) {
35717           var href = link.href;
35718           var title = link.title ? _escape(link.title) : null;
35719           var text = cap[1].replace(/\\([\[\]])/g, '$1');
35720
35721           if (cap[0].charAt(0) !== '!') {
35722             return {
35723               type: 'link',
35724               raw: raw,
35725               href: href,
35726               title: title,
35727               text: text
35728             };
35729           } else {
35730             return {
35731               type: 'image',
35732               raw: raw,
35733               href: href,
35734               title: title,
35735               text: _escape(text)
35736             };
35737           }
35738         }
35739
35740         function indentCodeCompensation(raw, text) {
35741           var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
35742
35743           if (matchIndentToCode === null) {
35744             return text;
35745           }
35746
35747           var indentToCode = matchIndentToCode[1];
35748           return text.split('\n').map(function (node) {
35749             var matchIndentInNode = node.match(/^\s+/);
35750
35751             if (matchIndentInNode === null) {
35752               return node;
35753             }
35754
35755             var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
35756                 indentInNode = _matchIndentInNode[0];
35757
35758             if (indentInNode.length >= indentToCode.length) {
35759               return node.slice(indentToCode.length);
35760             }
35761
35762             return node;
35763           }).join('\n');
35764         }
35765         /**
35766          * Tokenizer
35767          */
35768
35769
35770         var Tokenizer_1 = /*#__PURE__*/function () {
35771           function Tokenizer(options) {
35772             _classCallCheck(this, Tokenizer);
35773
35774             this.options = options || defaults$1;
35775           }
35776
35777           _createClass(Tokenizer, [{
35778             key: "space",
35779             value: function space(src) {
35780               var cap = this.rules.block.newline.exec(src);
35781
35782               if (cap) {
35783                 if (cap[0].length > 1) {
35784                   return {
35785                     type: 'space',
35786                     raw: cap[0]
35787                   };
35788                 }
35789
35790                 return {
35791                   raw: '\n'
35792                 };
35793               }
35794             }
35795           }, {
35796             key: "code",
35797             value: function code(src, tokens) {
35798               var cap = this.rules.block.code.exec(src);
35799
35800               if (cap) {
35801                 var lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
35802
35803                 if (lastToken && lastToken.type === 'paragraph') {
35804                   return {
35805                     raw: cap[0],
35806                     text: cap[0].trimRight()
35807                   };
35808                 }
35809
35810                 var text = cap[0].replace(/^ {1,4}/gm, '');
35811                 return {
35812                   type: 'code',
35813                   raw: cap[0],
35814                   codeBlockStyle: 'indented',
35815                   text: !this.options.pedantic ? rtrim$2(text, '\n') : text
35816                 };
35817               }
35818             }
35819           }, {
35820             key: "fences",
35821             value: function fences(src) {
35822               var cap = this.rules.block.fences.exec(src);
35823
35824               if (cap) {
35825                 var raw = cap[0];
35826                 var text = indentCodeCompensation(raw, cap[3] || '');
35827                 return {
35828                   type: 'code',
35829                   raw: raw,
35830                   lang: cap[2] ? cap[2].trim() : cap[2],
35831                   text: text
35832                 };
35833               }
35834             }
35835           }, {
35836             key: "heading",
35837             value: function heading(src) {
35838               var cap = this.rules.block.heading.exec(src);
35839
35840               if (cap) {
35841                 var text = cap[2].trim(); // remove trailing #s
35842
35843                 if (/#$/.test(text)) {
35844                   var trimmed = rtrim$2(text, '#');
35845
35846                   if (this.options.pedantic) {
35847                     text = trimmed.trim();
35848                   } else if (!trimmed || / $/.test(trimmed)) {
35849                     // CommonMark requires space before trailing #s
35850                     text = trimmed.trim();
35851                   }
35852                 }
35853
35854                 return {
35855                   type: 'heading',
35856                   raw: cap[0],
35857                   depth: cap[1].length,
35858                   text: text
35859                 };
35860               }
35861             }
35862           }, {
35863             key: "nptable",
35864             value: function nptable(src) {
35865               var cap = this.rules.block.nptable.exec(src);
35866
35867               if (cap) {
35868                 var item = {
35869                   type: 'table',
35870                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
35871                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
35872                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
35873                   raw: cap[0]
35874                 };
35875
35876                 if (item.header.length === item.align.length) {
35877                   var l = item.align.length;
35878                   var i;
35879
35880                   for (i = 0; i < l; i++) {
35881                     if (/^ *-+: *$/.test(item.align[i])) {
35882                       item.align[i] = 'right';
35883                     } else if (/^ *:-+: *$/.test(item.align[i])) {
35884                       item.align[i] = 'center';
35885                     } else if (/^ *:-+ *$/.test(item.align[i])) {
35886                       item.align[i] = 'left';
35887                     } else {
35888                       item.align[i] = null;
35889                     }
35890                   }
35891
35892                   l = item.cells.length;
35893
35894                   for (i = 0; i < l; i++) {
35895                     item.cells[i] = splitCells$1(item.cells[i], item.header.length);
35896                   }
35897
35898                   return item;
35899                 }
35900               }
35901             }
35902           }, {
35903             key: "hr",
35904             value: function hr(src) {
35905               var cap = this.rules.block.hr.exec(src);
35906
35907               if (cap) {
35908                 return {
35909                   type: 'hr',
35910                   raw: cap[0]
35911                 };
35912               }
35913             }
35914           }, {
35915             key: "blockquote",
35916             value: function blockquote(src) {
35917               var cap = this.rules.block.blockquote.exec(src);
35918
35919               if (cap) {
35920                 var text = cap[0].replace(/^ *> ?/gm, '');
35921                 return {
35922                   type: 'blockquote',
35923                   raw: cap[0],
35924                   text: text
35925                 };
35926               }
35927             }
35928           }, {
35929             key: "list",
35930             value: function list(src) {
35931               var cap = this.rules.block.list.exec(src);
35932
35933               if (cap) {
35934                 var raw = cap[0];
35935                 var bull = cap[2];
35936                 var isordered = bull.length > 1;
35937                 var list = {
35938                   type: 'list',
35939                   raw: raw,
35940                   ordered: isordered,
35941                   start: isordered ? +bull.slice(0, -1) : '',
35942                   loose: false,
35943                   items: []
35944                 }; // Get each top-level item.
35945
35946                 var itemMatch = cap[0].match(this.rules.block.item);
35947                 var next = false,
35948                     item,
35949                     space,
35950                     bcurr,
35951                     bnext,
35952                     addBack,
35953                     loose,
35954                     istask,
35955                     ischecked;
35956                 var l = itemMatch.length;
35957                 bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
35958
35959                 for (var i = 0; i < l; i++) {
35960                   item = itemMatch[i];
35961                   raw = item; // Determine whether the next list item belongs here.
35962                   // Backpedal if it does not belong in this list.
35963
35964                   if (i !== l - 1) {
35965                     bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
35966
35967                     if (!this.options.pedantic ? bnext[1].length > bcurr[0].length || bnext[1].length > 3 : bnext[1].length > bcurr[1].length) {
35968                       // nested list
35969                       itemMatch.splice(i, 2, itemMatch[i] + '\n' + itemMatch[i + 1]);
35970                       i--;
35971                       l--;
35972                       continue;
35973                     } else {
35974                       if ( // different bullet style
35975                       !this.options.pedantic || this.options.smartLists ? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1] : isordered === (bnext[2].length === 1)) {
35976                         addBack = itemMatch.slice(i + 1).join('\n');
35977                         list.raw = list.raw.substring(0, list.raw.length - addBack.length);
35978                         i = l - 1;
35979                       }
35980                     }
35981
35982                     bcurr = bnext;
35983                   } // Remove the list item's bullet
35984                   // so it is seen as the next token.
35985
35986
35987                   space = item.length;
35988                   item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
35989                   // list item contains. Hacky.
35990
35991                   if (~item.indexOf('\n ')) {
35992                     space -= item.length;
35993                     item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
35994                   } // Determine whether item is loose or not.
35995                   // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
35996                   // for discount behavior.
35997
35998
35999                   loose = next || /\n\n(?!\s*$)/.test(item);
36000
36001                   if (i !== l - 1) {
36002                     next = item.charAt(item.length - 1) === '\n';
36003                     if (!loose) loose = next;
36004                   }
36005
36006                   if (loose) {
36007                     list.loose = true;
36008                   } // Check for task list items
36009
36010
36011                   if (this.options.gfm) {
36012                     istask = /^\[[ xX]\] /.test(item);
36013                     ischecked = undefined;
36014
36015                     if (istask) {
36016                       ischecked = item[1] !== ' ';
36017                       item = item.replace(/^\[[ xX]\] +/, '');
36018                     }
36019                   }
36020
36021                   list.items.push({
36022                     type: 'list_item',
36023                     raw: raw,
36024                     task: istask,
36025                     checked: ischecked,
36026                     loose: loose,
36027                     text: item
36028                   });
36029                 }
36030
36031                 return list;
36032               }
36033             }
36034           }, {
36035             key: "html",
36036             value: function html(src) {
36037               var cap = this.rules.block.html.exec(src);
36038
36039               if (cap) {
36040                 return {
36041                   type: this.options.sanitize ? 'paragraph' : 'html',
36042                   raw: cap[0],
36043                   pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
36044                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36045                 };
36046               }
36047             }
36048           }, {
36049             key: "def",
36050             value: function def(src) {
36051               var cap = this.rules.block.def.exec(src);
36052
36053               if (cap) {
36054                 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
36055                 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
36056                 return {
36057                   tag: tag,
36058                   raw: cap[0],
36059                   href: cap[2],
36060                   title: cap[3]
36061                 };
36062               }
36063             }
36064           }, {
36065             key: "table",
36066             value: function table(src) {
36067               var cap = this.rules.block.table.exec(src);
36068
36069               if (cap) {
36070                 var item = {
36071                   type: 'table',
36072                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
36073                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
36074                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
36075                 };
36076
36077                 if (item.header.length === item.align.length) {
36078                   item.raw = cap[0];
36079                   var l = item.align.length;
36080                   var i;
36081
36082                   for (i = 0; i < l; i++) {
36083                     if (/^ *-+: *$/.test(item.align[i])) {
36084                       item.align[i] = 'right';
36085                     } else if (/^ *:-+: *$/.test(item.align[i])) {
36086                       item.align[i] = 'center';
36087                     } else if (/^ *:-+ *$/.test(item.align[i])) {
36088                       item.align[i] = 'left';
36089                     } else {
36090                       item.align[i] = null;
36091                     }
36092                   }
36093
36094                   l = item.cells.length;
36095
36096                   for (i = 0; i < l; i++) {
36097                     item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
36098                   }
36099
36100                   return item;
36101                 }
36102               }
36103             }
36104           }, {
36105             key: "lheading",
36106             value: function lheading(src) {
36107               var cap = this.rules.block.lheading.exec(src);
36108
36109               if (cap) {
36110                 return {
36111                   type: 'heading',
36112                   raw: cap[0],
36113                   depth: cap[2].charAt(0) === '=' ? 1 : 2,
36114                   text: cap[1]
36115                 };
36116               }
36117             }
36118           }, {
36119             key: "paragraph",
36120             value: function paragraph(src) {
36121               var cap = this.rules.block.paragraph.exec(src);
36122
36123               if (cap) {
36124                 return {
36125                   type: 'paragraph',
36126                   raw: cap[0],
36127                   text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
36128                 };
36129               }
36130             }
36131           }, {
36132             key: "text",
36133             value: function text(src, tokens) {
36134               var cap = this.rules.block.text.exec(src);
36135
36136               if (cap) {
36137                 var lastToken = tokens[tokens.length - 1];
36138
36139                 if (lastToken && lastToken.type === 'text') {
36140                   return {
36141                     raw: cap[0],
36142                     text: cap[0]
36143                   };
36144                 }
36145
36146                 return {
36147                   type: 'text',
36148                   raw: cap[0],
36149                   text: cap[0]
36150                 };
36151               }
36152             }
36153           }, {
36154             key: "escape",
36155             value: function escape(src) {
36156               var cap = this.rules.inline.escape.exec(src);
36157
36158               if (cap) {
36159                 return {
36160                   type: 'escape',
36161                   raw: cap[0],
36162                   text: _escape(cap[1])
36163                 };
36164               }
36165             }
36166           }, {
36167             key: "tag",
36168             value: function tag(src, inLink, inRawBlock) {
36169               var cap = this.rules.inline.tag.exec(src);
36170
36171               if (cap) {
36172                 if (!inLink && /^<a /i.test(cap[0])) {
36173                   inLink = true;
36174                 } else if (inLink && /^<\/a>/i.test(cap[0])) {
36175                   inLink = false;
36176                 }
36177
36178                 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36179                   inRawBlock = true;
36180                 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36181                   inRawBlock = false;
36182                 }
36183
36184                 return {
36185                   type: this.options.sanitize ? 'text' : 'html',
36186                   raw: cap[0],
36187                   inLink: inLink,
36188                   inRawBlock: inRawBlock,
36189                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36190                 };
36191               }
36192             }
36193           }, {
36194             key: "link",
36195             value: function link(src) {
36196               var cap = this.rules.inline.link.exec(src);
36197
36198               if (cap) {
36199                 var trimmedUrl = cap[2].trim();
36200
36201                 if (!this.options.pedantic && /^</.test(trimmedUrl)) {
36202                   // commonmark requires matching angle brackets
36203                   if (!/>$/.test(trimmedUrl)) {
36204                     return;
36205                   } // ending angle bracket cannot be escaped
36206
36207
36208                   var rtrimSlash = rtrim$2(trimmedUrl.slice(0, -1), '\\');
36209
36210                   if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
36211                     return;
36212                   }
36213                 } else {
36214                   // find closing parenthesis
36215                   var lastParenIndex = findClosingBracket$1(cap[2], '()');
36216
36217                   if (lastParenIndex > -1) {
36218                     var start = cap[0].indexOf('!') === 0 ? 5 : 4;
36219                     var linkLen = start + cap[1].length + lastParenIndex;
36220                     cap[2] = cap[2].substring(0, lastParenIndex);
36221                     cap[0] = cap[0].substring(0, linkLen).trim();
36222                     cap[3] = '';
36223                   }
36224                 }
36225
36226                 var href = cap[2];
36227                 var title = '';
36228
36229                 if (this.options.pedantic) {
36230                   // split pedantic href and title
36231                   var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
36232
36233                   if (link) {
36234                     href = link[1];
36235                     title = link[3];
36236                   }
36237                 } else {
36238                   title = cap[3] ? cap[3].slice(1, -1) : '';
36239                 }
36240
36241                 href = href.trim();
36242
36243                 if (/^</.test(href)) {
36244                   if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
36245                     // pedantic allows starting angle bracket without ending angle bracket
36246                     href = href.slice(1);
36247                   } else {
36248                     href = href.slice(1, -1);
36249                   }
36250                 }
36251
36252                 return outputLink(cap, {
36253                   href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
36254                   title: title ? title.replace(this.rules.inline._escapes, '$1') : title
36255                 }, cap[0]);
36256               }
36257             }
36258           }, {
36259             key: "reflink",
36260             value: function reflink(src, links) {
36261               var cap;
36262
36263               if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
36264                 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
36265                 link = links[link.toLowerCase()];
36266
36267                 if (!link || !link.href) {
36268                   var text = cap[0].charAt(0);
36269                   return {
36270                     type: 'text',
36271                     raw: text,
36272                     text: text
36273                   };
36274                 }
36275
36276                 return outputLink(cap, link, cap[0]);
36277               }
36278             }
36279           }, {
36280             key: "strong",
36281             value: function strong(src, maskedSrc) {
36282               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36283               var match = this.rules.inline.strong.start.exec(src);
36284
36285               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36286                 maskedSrc = maskedSrc.slice(-1 * src.length);
36287                 var endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;
36288                 endReg.lastIndex = 0;
36289                 var cap;
36290
36291                 while ((match = endReg.exec(maskedSrc)) != null) {
36292                   cap = this.rules.inline.strong.middle.exec(maskedSrc.slice(0, match.index + 3));
36293
36294                   if (cap) {
36295                     return {
36296                       type: 'strong',
36297                       raw: src.slice(0, cap[0].length),
36298                       text: src.slice(2, cap[0].length - 2)
36299                     };
36300                   }
36301                 }
36302               }
36303             }
36304           }, {
36305             key: "em",
36306             value: function em(src, maskedSrc) {
36307               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36308               var match = this.rules.inline.em.start.exec(src);
36309
36310               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36311                 maskedSrc = maskedSrc.slice(-1 * src.length);
36312                 var endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
36313                 endReg.lastIndex = 0;
36314                 var cap;
36315
36316                 while ((match = endReg.exec(maskedSrc)) != null) {
36317                   cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
36318
36319                   if (cap) {
36320                     return {
36321                       type: 'em',
36322                       raw: src.slice(0, cap[0].length),
36323                       text: src.slice(1, cap[0].length - 1)
36324                     };
36325                   }
36326                 }
36327               }
36328             }
36329           }, {
36330             key: "codespan",
36331             value: function codespan(src) {
36332               var cap = this.rules.inline.code.exec(src);
36333
36334               if (cap) {
36335                 var text = cap[2].replace(/\n/g, ' ');
36336                 var hasNonSpaceChars = /[^ ]/.test(text);
36337                 var hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
36338
36339                 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
36340                   text = text.substring(1, text.length - 1);
36341                 }
36342
36343                 text = _escape(text, true);
36344                 return {
36345                   type: 'codespan',
36346                   raw: cap[0],
36347                   text: text
36348                 };
36349               }
36350             }
36351           }, {
36352             key: "br",
36353             value: function br(src) {
36354               var cap = this.rules.inline.br.exec(src);
36355
36356               if (cap) {
36357                 return {
36358                   type: 'br',
36359                   raw: cap[0]
36360                 };
36361               }
36362             }
36363           }, {
36364             key: "del",
36365             value: function del(src) {
36366               var cap = this.rules.inline.del.exec(src);
36367
36368               if (cap) {
36369                 return {
36370                   type: 'del',
36371                   raw: cap[0],
36372                   text: cap[2]
36373                 };
36374               }
36375             }
36376           }, {
36377             key: "autolink",
36378             value: function autolink(src, mangle) {
36379               var cap = this.rules.inline.autolink.exec(src);
36380
36381               if (cap) {
36382                 var text, href;
36383
36384                 if (cap[2] === '@') {
36385                   text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
36386                   href = 'mailto:' + text;
36387                 } else {
36388                   text = _escape(cap[1]);
36389                   href = text;
36390                 }
36391
36392                 return {
36393                   type: 'link',
36394                   raw: cap[0],
36395                   text: text,
36396                   href: href,
36397                   tokens: [{
36398                     type: 'text',
36399                     raw: text,
36400                     text: text
36401                   }]
36402                 };
36403               }
36404             }
36405           }, {
36406             key: "url",
36407             value: function url(src, mangle) {
36408               var cap;
36409
36410               if (cap = this.rules.inline.url.exec(src)) {
36411                 var text, href;
36412
36413                 if (cap[2] === '@') {
36414                   text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
36415                   href = 'mailto:' + text;
36416                 } else {
36417                   // do extended autolink path validation
36418                   var prevCapZero;
36419
36420                   do {
36421                     prevCapZero = cap[0];
36422                     cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
36423                   } while (prevCapZero !== cap[0]);
36424
36425                   text = _escape(cap[0]);
36426
36427                   if (cap[1] === 'www.') {
36428                     href = 'http://' + text;
36429                   } else {
36430                     href = text;
36431                   }
36432                 }
36433
36434                 return {
36435                   type: 'link',
36436                   raw: cap[0],
36437                   text: text,
36438                   href: href,
36439                   tokens: [{
36440                     type: 'text',
36441                     raw: text,
36442                     text: text
36443                   }]
36444                 };
36445               }
36446             }
36447           }, {
36448             key: "inlineText",
36449             value: function inlineText(src, inRawBlock, smartypants) {
36450               var cap = this.rules.inline.text.exec(src);
36451
36452               if (cap) {
36453                 var text;
36454
36455                 if (inRawBlock) {
36456                   text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
36457                 } else {
36458                   text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
36459                 }
36460
36461                 return {
36462                   type: 'text',
36463                   raw: cap[0],
36464                   text: text
36465                 };
36466               }
36467             }
36468           }]);
36469
36470           return Tokenizer;
36471         }();
36472
36473         var noopTest$1 = helpers.noopTest,
36474             edit$1 = helpers.edit,
36475             merge$2 = helpers.merge;
36476         /**
36477          * Block-Level Grammar
36478          */
36479
36480         var block = {
36481           newline: /^(?: *(?:\n|$))+/,
36482           code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
36483           fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
36484           hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
36485           heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
36486           blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
36487           list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
36488           html: '^ {0,3}(?:' // optional indentation
36489           + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
36490           + '|comment[^\\n]*(\\n+|$)' // (2)
36491           + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
36492           + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
36493           + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
36494           + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
36495           + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
36496           + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
36497           + ')',
36498           def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
36499           nptable: noopTest$1,
36500           table: noopTest$1,
36501           lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
36502           // regex template, placeholders will be replaced according to different paragraph
36503           // interruption rules of commonmark and the original markdown spec:
36504           _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
36505           text: /^[^\n]+/
36506         };
36507         block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
36508         block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
36509         block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex();
36510         block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
36511         block.item = /^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/;
36512         block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex();
36513         block.listItemStart = edit$1(/^( *)(bull)/).replace('bull', block.bullet).getRegex();
36514         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();
36515         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';
36516         block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
36517         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();
36518         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
36519         .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
36520         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
36521         .getRegex();
36522         block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex();
36523         /**
36524          * Normal Block Grammar
36525          */
36526
36527         block.normal = merge$2({}, block);
36528         /**
36529          * GFM Block Grammar
36530          */
36531
36532         block.gfm = merge$2({}, block.normal, {
36533           nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
36534           + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
36535           + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
36536           // Cells
36537           table: '^ *\\|(.+)\\n' // Header
36538           + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
36539           + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
36540
36541         });
36542         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
36543         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36544         .getRegex();
36545         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
36546         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36547         .getRegex();
36548         /**
36549          * Pedantic grammar (original John Gruber's loose markdown specification)
36550          */
36551
36552         block.pedantic = merge$2({}, block.normal, {
36553           html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
36554           + '|<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(),
36555           def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
36556           heading: /^(#{1,6})(.*)(?:\n+|$)/,
36557           fences: noopTest$1,
36558           // fences not supported
36559           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()
36560         });
36561         /**
36562          * Inline-Level Grammar
36563          */
36564
36565         var inline = {
36566           escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
36567           autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
36568           url: noopTest$1,
36569           tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
36570           + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
36571           + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
36572           + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
36573           + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
36574           // CDATA section
36575           link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
36576           reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
36577           nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
36578           reflinkSearch: 'reflink|nolink(?!\\()',
36579           strong: {
36580             start: /^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,
36581             // (1) returns if starts w/ punctuation
36582             middle: /^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,
36583             endAst: /[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36584             // last char can't be punct, or final * must also be followed by punct (or endline)
36585             endUnd: /[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36586
36587           },
36588           em: {
36589             start: /^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,
36590             // (1) returns if starts w/ punctuation
36591             middle: /^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,
36592             endAst: /[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36593             // last char can't be punct, or final * must also be followed by punct (or endline)
36594             endUnd: /[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36595
36596           },
36597           code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
36598           br: /^( {2,}|\\)\n(?!\s*$)/,
36599           del: noopTest$1,
36600           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,
36601           punctuation: /^([\s*punctuation])/
36602         }; // list of punctuation marks from common mark spec
36603         // without * and _ to workaround cases with double emphasis
36604
36605         inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
36606         inline.punctuation = edit$1(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
36607
36608         inline._blockSkip = '\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>';
36609         inline._overlapSkip = '__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*';
36610         inline._comment = edit$1(block._comment).replace('(?:-->|$)', '-->').getRegex();
36611         inline.em.start = edit$1(inline.em.start).replace(/punctuation/g, inline._punctuation).getRegex();
36612         inline.em.middle = edit$1(inline.em.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36613         inline.em.endAst = edit$1(inline.em.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36614         inline.em.endUnd = edit$1(inline.em.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36615         inline.strong.start = edit$1(inline.strong.start).replace(/punctuation/g, inline._punctuation).getRegex();
36616         inline.strong.middle = edit$1(inline.strong.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36617         inline.strong.endAst = edit$1(inline.strong.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36618         inline.strong.endUnd = edit$1(inline.strong.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36619         inline.blockSkip = edit$1(inline._blockSkip, 'g').getRegex();
36620         inline.overlapSkip = edit$1(inline._overlapSkip, 'g').getRegex();
36621         inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
36622         inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
36623         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])?)+(?![-_])/;
36624         inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex();
36625         inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
36626         inline.tag = edit$1(inline.tag).replace('comment', inline._comment).replace('attribute', inline._attribute).getRegex();
36627         inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
36628         inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
36629         inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
36630         inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex();
36631         inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex();
36632         inline.reflinkSearch = edit$1(inline.reflinkSearch, 'g').replace('reflink', inline.reflink).replace('nolink', inline.nolink).getRegex();
36633         /**
36634          * Normal Inline Grammar
36635          */
36636
36637         inline.normal = merge$2({}, inline);
36638         /**
36639          * Pedantic Inline Grammar
36640          */
36641
36642         inline.pedantic = merge$2({}, inline.normal, {
36643           strong: {
36644             start: /^__|\*\*/,
36645             middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
36646             endAst: /\*\*(?!\*)/g,
36647             endUnd: /__(?!_)/g
36648           },
36649           em: {
36650             start: /^_|\*/,
36651             middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
36652             endAst: /\*(?!\*)/g,
36653             endUnd: /_(?!_)/g
36654           },
36655           link: edit$1(/^!?\[(label)\]\((.*?)\)/).replace('label', inline._label).getRegex(),
36656           reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline._label).getRegex()
36657         });
36658         /**
36659          * GFM Inline Grammar
36660          */
36661
36662         inline.gfm = merge$2({}, inline.normal, {
36663           escape: edit$1(inline.escape).replace('])', '~|])').getRegex(),
36664           _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
36665           url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
36666           _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
36667           del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
36668           text: /^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
36669         });
36670         inline.gfm.url = edit$1(inline.gfm.url, 'i').replace('email', inline.gfm._extended_email).getRegex();
36671         /**
36672          * GFM + Line Breaks Inline Grammar
36673          */
36674
36675         inline.breaks = merge$2({}, inline.gfm, {
36676           br: edit$1(inline.br).replace('{2,}', '*').getRegex(),
36677           text: edit$1(inline.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
36678         });
36679         var rules = {
36680           block: block,
36681           inline: inline
36682         };
36683
36684         var defaults$2 = defaults.defaults;
36685         var block$1 = rules.block,
36686             inline$1 = rules.inline;
36687         var repeatString$1 = helpers.repeatString;
36688         /**
36689          * smartypants text replacement
36690          */
36691
36692         function smartypants(text) {
36693           return text // em-dashes
36694           .replace(/---/g, "\u2014") // en-dashes
36695           .replace(/--/g, "\u2013") // opening singles
36696           .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
36697           .replace(/'/g, "\u2019") // opening doubles
36698           .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
36699           .replace(/"/g, "\u201D") // ellipses
36700           .replace(/\.{3}/g, "\u2026");
36701         }
36702         /**
36703          * mangle email addresses
36704          */
36705
36706
36707         function mangle(text) {
36708           var out = '',
36709               i,
36710               ch;
36711           var l = text.length;
36712
36713           for (i = 0; i < l; i++) {
36714             ch = text.charCodeAt(i);
36715
36716             if (Math.random() > 0.5) {
36717               ch = 'x' + ch.toString(16);
36718             }
36719
36720             out += '&#' + ch + ';';
36721           }
36722
36723           return out;
36724         }
36725         /**
36726          * Block Lexer
36727          */
36728
36729
36730         var Lexer_1 = /*#__PURE__*/function () {
36731           function Lexer(options) {
36732             _classCallCheck(this, Lexer);
36733
36734             this.tokens = [];
36735             this.tokens.links = Object.create(null);
36736             this.options = options || defaults$2;
36737             this.options.tokenizer = this.options.tokenizer || new Tokenizer_1();
36738             this.tokenizer = this.options.tokenizer;
36739             this.tokenizer.options = this.options;
36740             var rules = {
36741               block: block$1.normal,
36742               inline: inline$1.normal
36743             };
36744
36745             if (this.options.pedantic) {
36746               rules.block = block$1.pedantic;
36747               rules.inline = inline$1.pedantic;
36748             } else if (this.options.gfm) {
36749               rules.block = block$1.gfm;
36750
36751               if (this.options.breaks) {
36752                 rules.inline = inline$1.breaks;
36753               } else {
36754                 rules.inline = inline$1.gfm;
36755               }
36756             }
36757
36758             this.tokenizer.rules = rules;
36759           }
36760           /**
36761            * Expose Rules
36762            */
36763
36764
36765           _createClass(Lexer, [{
36766             key: "lex",
36767             value:
36768             /**
36769              * Preprocessing
36770              */
36771             function lex(src) {
36772               src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, '    ');
36773               this.blockTokens(src, this.tokens, true);
36774               this.inline(this.tokens);
36775               return this.tokens;
36776             }
36777             /**
36778              * Lexing
36779              */
36780
36781           }, {
36782             key: "blockTokens",
36783             value: function blockTokens(src) {
36784               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
36785               var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
36786
36787               if (this.options.pedantic) {
36788                 src = src.replace(/^ +$/gm, '');
36789               }
36790
36791               var token, i, l, lastToken;
36792
36793               while (src) {
36794                 // newline
36795                 if (token = this.tokenizer.space(src)) {
36796                   src = src.substring(token.raw.length);
36797
36798                   if (token.type) {
36799                     tokens.push(token);
36800                   }
36801
36802                   continue;
36803                 } // code
36804
36805
36806                 if (token = this.tokenizer.code(src, tokens)) {
36807                   src = src.substring(token.raw.length);
36808
36809                   if (token.type) {
36810                     tokens.push(token);
36811                   } else {
36812                     lastToken = tokens[tokens.length - 1];
36813                     lastToken.raw += '\n' + token.raw;
36814                     lastToken.text += '\n' + token.text;
36815                   }
36816
36817                   continue;
36818                 } // fences
36819
36820
36821                 if (token = this.tokenizer.fences(src)) {
36822                   src = src.substring(token.raw.length);
36823                   tokens.push(token);
36824                   continue;
36825                 } // heading
36826
36827
36828                 if (token = this.tokenizer.heading(src)) {
36829                   src = src.substring(token.raw.length);
36830                   tokens.push(token);
36831                   continue;
36832                 } // table no leading pipe (gfm)
36833
36834
36835                 if (token = this.tokenizer.nptable(src)) {
36836                   src = src.substring(token.raw.length);
36837                   tokens.push(token);
36838                   continue;
36839                 } // hr
36840
36841
36842                 if (token = this.tokenizer.hr(src)) {
36843                   src = src.substring(token.raw.length);
36844                   tokens.push(token);
36845                   continue;
36846                 } // blockquote
36847
36848
36849                 if (token = this.tokenizer.blockquote(src)) {
36850                   src = src.substring(token.raw.length);
36851                   token.tokens = this.blockTokens(token.text, [], top);
36852                   tokens.push(token);
36853                   continue;
36854                 } // list
36855
36856
36857                 if (token = this.tokenizer.list(src)) {
36858                   src = src.substring(token.raw.length);
36859                   l = token.items.length;
36860
36861                   for (i = 0; i < l; i++) {
36862                     token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
36863                   }
36864
36865                   tokens.push(token);
36866                   continue;
36867                 } // html
36868
36869
36870                 if (token = this.tokenizer.html(src)) {
36871                   src = src.substring(token.raw.length);
36872                   tokens.push(token);
36873                   continue;
36874                 } // def
36875
36876
36877                 if (top && (token = this.tokenizer.def(src))) {
36878                   src = src.substring(token.raw.length);
36879
36880                   if (!this.tokens.links[token.tag]) {
36881                     this.tokens.links[token.tag] = {
36882                       href: token.href,
36883                       title: token.title
36884                     };
36885                   }
36886
36887                   continue;
36888                 } // table (gfm)
36889
36890
36891                 if (token = this.tokenizer.table(src)) {
36892                   src = src.substring(token.raw.length);
36893                   tokens.push(token);
36894                   continue;
36895                 } // lheading
36896
36897
36898                 if (token = this.tokenizer.lheading(src)) {
36899                   src = src.substring(token.raw.length);
36900                   tokens.push(token);
36901                   continue;
36902                 } // top-level paragraph
36903
36904
36905                 if (top && (token = this.tokenizer.paragraph(src))) {
36906                   src = src.substring(token.raw.length);
36907                   tokens.push(token);
36908                   continue;
36909                 } // text
36910
36911
36912                 if (token = this.tokenizer.text(src, tokens)) {
36913                   src = src.substring(token.raw.length);
36914
36915                   if (token.type) {
36916                     tokens.push(token);
36917                   } else {
36918                     lastToken = tokens[tokens.length - 1];
36919                     lastToken.raw += '\n' + token.raw;
36920                     lastToken.text += '\n' + token.text;
36921                   }
36922
36923                   continue;
36924                 }
36925
36926                 if (src) {
36927                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
36928
36929                   if (this.options.silent) {
36930                     console.error(errMsg);
36931                     break;
36932                   } else {
36933                     throw new Error(errMsg);
36934                   }
36935                 }
36936               }
36937
36938               return tokens;
36939             }
36940           }, {
36941             key: "inline",
36942             value: function inline(tokens) {
36943               var i, j, k, l2, row, token;
36944               var l = tokens.length;
36945
36946               for (i = 0; i < l; i++) {
36947                 token = tokens[i];
36948
36949                 switch (token.type) {
36950                   case 'paragraph':
36951                   case 'text':
36952                   case 'heading':
36953                     {
36954                       token.tokens = [];
36955                       this.inlineTokens(token.text, token.tokens);
36956                       break;
36957                     }
36958
36959                   case 'table':
36960                     {
36961                       token.tokens = {
36962                         header: [],
36963                         cells: []
36964                       }; // header
36965
36966                       l2 = token.header.length;
36967
36968                       for (j = 0; j < l2; j++) {
36969                         token.tokens.header[j] = [];
36970                         this.inlineTokens(token.header[j], token.tokens.header[j]);
36971                       } // cells
36972
36973
36974                       l2 = token.cells.length;
36975
36976                       for (j = 0; j < l2; j++) {
36977                         row = token.cells[j];
36978                         token.tokens.cells[j] = [];
36979
36980                         for (k = 0; k < row.length; k++) {
36981                           token.tokens.cells[j][k] = [];
36982                           this.inlineTokens(row[k], token.tokens.cells[j][k]);
36983                         }
36984                       }
36985
36986                       break;
36987                     }
36988
36989                   case 'blockquote':
36990                     {
36991                       this.inline(token.tokens);
36992                       break;
36993                     }
36994
36995                   case 'list':
36996                     {
36997                       l2 = token.items.length;
36998
36999                       for (j = 0; j < l2; j++) {
37000                         this.inline(token.items[j].tokens);
37001                       }
37002
37003                       break;
37004                     }
37005                 }
37006               }
37007
37008               return tokens;
37009             }
37010             /**
37011              * Lexing/Compiling
37012              */
37013
37014           }, {
37015             key: "inlineTokens",
37016             value: function inlineTokens(src) {
37017               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
37018               var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
37019               var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
37020               var token; // String with links masked to avoid interference with em and strong
37021
37022               var maskedSrc = src;
37023               var match;
37024               var keepPrevChar, prevChar; // Mask out reflinks
37025
37026               if (this.tokens.links) {
37027                 var links = Object.keys(this.tokens.links);
37028
37029                 if (links.length > 0) {
37030                   while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
37031                     if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
37032                       maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
37033                     }
37034                   }
37035                 }
37036               } // Mask out other blocks
37037
37038
37039               while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
37040                 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
37041               }
37042
37043               while (src) {
37044                 if (!keepPrevChar) {
37045                   prevChar = '';
37046                 }
37047
37048                 keepPrevChar = false; // escape
37049
37050                 if (token = this.tokenizer.escape(src)) {
37051                   src = src.substring(token.raw.length);
37052                   tokens.push(token);
37053                   continue;
37054                 } // tag
37055
37056
37057                 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
37058                   src = src.substring(token.raw.length);
37059                   inLink = token.inLink;
37060                   inRawBlock = token.inRawBlock;
37061                   tokens.push(token);
37062                   continue;
37063                 } // link
37064
37065
37066                 if (token = this.tokenizer.link(src)) {
37067                   src = src.substring(token.raw.length);
37068
37069                   if (token.type === 'link') {
37070                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
37071                   }
37072
37073                   tokens.push(token);
37074                   continue;
37075                 } // reflink, nolink
37076
37077
37078                 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
37079                   src = src.substring(token.raw.length);
37080
37081                   if (token.type === 'link') {
37082                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
37083                   }
37084
37085                   tokens.push(token);
37086                   continue;
37087                 } // strong
37088
37089
37090                 if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {
37091                   src = src.substring(token.raw.length);
37092                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37093                   tokens.push(token);
37094                   continue;
37095                 } // em
37096
37097
37098                 if (token = this.tokenizer.em(src, maskedSrc, prevChar)) {
37099                   src = src.substring(token.raw.length);
37100                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37101                   tokens.push(token);
37102                   continue;
37103                 } // code
37104
37105
37106                 if (token = this.tokenizer.codespan(src)) {
37107                   src = src.substring(token.raw.length);
37108                   tokens.push(token);
37109                   continue;
37110                 } // br
37111
37112
37113                 if (token = this.tokenizer.br(src)) {
37114                   src = src.substring(token.raw.length);
37115                   tokens.push(token);
37116                   continue;
37117                 } // del (gfm)
37118
37119
37120                 if (token = this.tokenizer.del(src)) {
37121                   src = src.substring(token.raw.length);
37122                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37123                   tokens.push(token);
37124                   continue;
37125                 } // autolink
37126
37127
37128                 if (token = this.tokenizer.autolink(src, mangle)) {
37129                   src = src.substring(token.raw.length);
37130                   tokens.push(token);
37131                   continue;
37132                 } // url (gfm)
37133
37134
37135                 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
37136                   src = src.substring(token.raw.length);
37137                   tokens.push(token);
37138                   continue;
37139                 } // text
37140
37141
37142                 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
37143                   src = src.substring(token.raw.length);
37144                   prevChar = token.raw.slice(-1);
37145                   keepPrevChar = true;
37146                   tokens.push(token);
37147                   continue;
37148                 }
37149
37150                 if (src) {
37151                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
37152
37153                   if (this.options.silent) {
37154                     console.error(errMsg);
37155                     break;
37156                   } else {
37157                     throw new Error(errMsg);
37158                   }
37159                 }
37160               }
37161
37162               return tokens;
37163             }
37164           }], [{
37165             key: "rules",
37166             get: function get() {
37167               return {
37168                 block: block$1,
37169                 inline: inline$1
37170               };
37171             }
37172             /**
37173              * Static Lex Method
37174              */
37175
37176           }, {
37177             key: "lex",
37178             value: function lex(src, options) {
37179               var lexer = new Lexer(options);
37180               return lexer.lex(src);
37181             }
37182             /**
37183              * Static Lex Inline Method
37184              */
37185
37186           }, {
37187             key: "lexInline",
37188             value: function lexInline(src, options) {
37189               var lexer = new Lexer(options);
37190               return lexer.inlineTokens(src);
37191             }
37192           }]);
37193
37194           return Lexer;
37195         }();
37196
37197         var defaults$3 = defaults.defaults;
37198         var cleanUrl$1 = helpers.cleanUrl,
37199             escape$2 = helpers.escape;
37200         /**
37201          * Renderer
37202          */
37203
37204         var Renderer_1 = /*#__PURE__*/function () {
37205           function Renderer(options) {
37206             _classCallCheck(this, Renderer);
37207
37208             this.options = options || defaults$3;
37209           }
37210
37211           _createClass(Renderer, [{
37212             key: "code",
37213             value: function code(_code, infostring, escaped) {
37214               var lang = (infostring || '').match(/\S*/)[0];
37215
37216               if (this.options.highlight) {
37217                 var out = this.options.highlight(_code, lang);
37218
37219                 if (out != null && out !== _code) {
37220                   escaped = true;
37221                   _code = out;
37222                 }
37223               }
37224
37225               _code = _code.replace(/\n$/, '') + '\n';
37226
37227               if (!lang) {
37228                 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37229               }
37230
37231               return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37232             }
37233           }, {
37234             key: "blockquote",
37235             value: function blockquote(quote) {
37236               return '<blockquote>\n' + quote + '</blockquote>\n';
37237             }
37238           }, {
37239             key: "html",
37240             value: function html(_html) {
37241               return _html;
37242             }
37243           }, {
37244             key: "heading",
37245             value: function heading(text, level, raw, slugger) {
37246               if (this.options.headerIds) {
37247                 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
37248               } // ignore IDs
37249
37250
37251               return '<h' + level + '>' + text + '</h' + level + '>\n';
37252             }
37253           }, {
37254             key: "hr",
37255             value: function hr() {
37256               return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
37257             }
37258           }, {
37259             key: "list",
37260             value: function list(body, ordered, start) {
37261               var type = ordered ? 'ol' : 'ul',
37262                   startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
37263               return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
37264             }
37265           }, {
37266             key: "listitem",
37267             value: function listitem(text) {
37268               return '<li>' + text + '</li>\n';
37269             }
37270           }, {
37271             key: "checkbox",
37272             value: function checkbox(checked) {
37273               return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
37274             }
37275           }, {
37276             key: "paragraph",
37277             value: function paragraph(text) {
37278               return '<p>' + text + '</p>\n';
37279             }
37280           }, {
37281             key: "table",
37282             value: function table(header, body) {
37283               if (body) body = '<tbody>' + body + '</tbody>';
37284               return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
37285             }
37286           }, {
37287             key: "tablerow",
37288             value: function tablerow(content) {
37289               return '<tr>\n' + content + '</tr>\n';
37290             }
37291           }, {
37292             key: "tablecell",
37293             value: function tablecell(content, flags) {
37294               var type = flags.header ? 'th' : 'td';
37295               var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
37296               return tag + content + '</' + type + '>\n';
37297             } // span level renderer
37298
37299           }, {
37300             key: "strong",
37301             value: function strong(text) {
37302               return '<strong>' + text + '</strong>';
37303             }
37304           }, {
37305             key: "em",
37306             value: function em(text) {
37307               return '<em>' + text + '</em>';
37308             }
37309           }, {
37310             key: "codespan",
37311             value: function codespan(text) {
37312               return '<code>' + text + '</code>';
37313             }
37314           }, {
37315             key: "br",
37316             value: function br() {
37317               return this.options.xhtml ? '<br/>' : '<br>';
37318             }
37319           }, {
37320             key: "del",
37321             value: function del(text) {
37322               return '<del>' + text + '</del>';
37323             }
37324           }, {
37325             key: "link",
37326             value: function link(href, title, text) {
37327               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37328
37329               if (href === null) {
37330                 return text;
37331               }
37332
37333               var out = '<a href="' + escape$2(href) + '"';
37334
37335               if (title) {
37336                 out += ' title="' + title + '"';
37337               }
37338
37339               out += '>' + text + '</a>';
37340               return out;
37341             }
37342           }, {
37343             key: "image",
37344             value: function image(href, title, text) {
37345               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37346
37347               if (href === null) {
37348                 return text;
37349               }
37350
37351               var out = '<img src="' + href + '" alt="' + text + '"';
37352
37353               if (title) {
37354                 out += ' title="' + title + '"';
37355               }
37356
37357               out += this.options.xhtml ? '/>' : '>';
37358               return out;
37359             }
37360           }, {
37361             key: "text",
37362             value: function text(_text) {
37363               return _text;
37364             }
37365           }]);
37366
37367           return Renderer;
37368         }();
37369
37370         /**
37371          * TextRenderer
37372          * returns only the textual part of the token
37373          */
37374         var TextRenderer_1 = /*#__PURE__*/function () {
37375           function TextRenderer() {
37376             _classCallCheck(this, TextRenderer);
37377           }
37378
37379           _createClass(TextRenderer, [{
37380             key: "strong",
37381             value: // no need for block level renderers
37382             function strong(text) {
37383               return text;
37384             }
37385           }, {
37386             key: "em",
37387             value: function em(text) {
37388               return text;
37389             }
37390           }, {
37391             key: "codespan",
37392             value: function codespan(text) {
37393               return text;
37394             }
37395           }, {
37396             key: "del",
37397             value: function del(text) {
37398               return text;
37399             }
37400           }, {
37401             key: "html",
37402             value: function html(text) {
37403               return text;
37404             }
37405           }, {
37406             key: "text",
37407             value: function text(_text) {
37408               return _text;
37409             }
37410           }, {
37411             key: "link",
37412             value: function link(href, title, text) {
37413               return '' + text;
37414             }
37415           }, {
37416             key: "image",
37417             value: function image(href, title, text) {
37418               return '' + text;
37419             }
37420           }, {
37421             key: "br",
37422             value: function br() {
37423               return '';
37424             }
37425           }]);
37426
37427           return TextRenderer;
37428         }();
37429
37430         /**
37431          * Slugger generates header id
37432          */
37433         var Slugger_1 = /*#__PURE__*/function () {
37434           function Slugger() {
37435             _classCallCheck(this, Slugger);
37436
37437             this.seen = {};
37438           }
37439
37440           _createClass(Slugger, [{
37441             key: "serialize",
37442             value: function serialize(value) {
37443               return value.toLowerCase().trim() // remove html tags
37444               .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
37445               .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
37446             }
37447             /**
37448              * Finds the next safe (unique) slug to use
37449              */
37450
37451           }, {
37452             key: "getNextSafeSlug",
37453             value: function getNextSafeSlug(originalSlug, isDryRun) {
37454               var slug = originalSlug;
37455               var occurenceAccumulator = 0;
37456
37457               if (this.seen.hasOwnProperty(slug)) {
37458                 occurenceAccumulator = this.seen[originalSlug];
37459
37460                 do {
37461                   occurenceAccumulator++;
37462                   slug = originalSlug + '-' + occurenceAccumulator;
37463                 } while (this.seen.hasOwnProperty(slug));
37464               }
37465
37466               if (!isDryRun) {
37467                 this.seen[originalSlug] = occurenceAccumulator;
37468                 this.seen[slug] = 0;
37469               }
37470
37471               return slug;
37472             }
37473             /**
37474              * Convert string to unique id
37475              * @param {object} options
37476              * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
37477              */
37478
37479           }, {
37480             key: "slug",
37481             value: function slug(value) {
37482               var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
37483               var slug = this.serialize(value);
37484               return this.getNextSafeSlug(slug, options.dryrun);
37485             }
37486           }]);
37487
37488           return Slugger;
37489         }();
37490
37491         var defaults$4 = defaults.defaults;
37492         var unescape$2 = helpers.unescape;
37493         /**
37494          * Parsing & Compiling
37495          */
37496
37497         var Parser_1 = /*#__PURE__*/function () {
37498           function Parser(options) {
37499             _classCallCheck(this, Parser);
37500
37501             this.options = options || defaults$4;
37502             this.options.renderer = this.options.renderer || new Renderer_1();
37503             this.renderer = this.options.renderer;
37504             this.renderer.options = this.options;
37505             this.textRenderer = new TextRenderer_1();
37506             this.slugger = new Slugger_1();
37507           }
37508           /**
37509            * Static Parse Method
37510            */
37511
37512
37513           _createClass(Parser, [{
37514             key: "parse",
37515             value:
37516             /**
37517              * Parse Loop
37518              */
37519             function parse(tokens) {
37520               var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37521               var out = '',
37522                   i,
37523                   j,
37524                   k,
37525                   l2,
37526                   l3,
37527                   row,
37528                   cell,
37529                   header,
37530                   body,
37531                   token,
37532                   ordered,
37533                   start,
37534                   loose,
37535                   itemBody,
37536                   item,
37537                   checked,
37538                   task,
37539                   checkbox;
37540               var l = tokens.length;
37541
37542               for (i = 0; i < l; i++) {
37543                 token = tokens[i];
37544
37545                 switch (token.type) {
37546                   case 'space':
37547                     {
37548                       continue;
37549                     }
37550
37551                   case 'hr':
37552                     {
37553                       out += this.renderer.hr();
37554                       continue;
37555                     }
37556
37557                   case 'heading':
37558                     {
37559                       out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$2(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
37560                       continue;
37561                     }
37562
37563                   case 'code':
37564                     {
37565                       out += this.renderer.code(token.text, token.lang, token.escaped);
37566                       continue;
37567                     }
37568
37569                   case 'table':
37570                     {
37571                       header = ''; // header
37572
37573                       cell = '';
37574                       l2 = token.header.length;
37575
37576                       for (j = 0; j < l2; j++) {
37577                         cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
37578                           header: true,
37579                           align: token.align[j]
37580                         });
37581                       }
37582
37583                       header += this.renderer.tablerow(cell);
37584                       body = '';
37585                       l2 = token.cells.length;
37586
37587                       for (j = 0; j < l2; j++) {
37588                         row = token.tokens.cells[j];
37589                         cell = '';
37590                         l3 = row.length;
37591
37592                         for (k = 0; k < l3; k++) {
37593                           cell += this.renderer.tablecell(this.parseInline(row[k]), {
37594                             header: false,
37595                             align: token.align[k]
37596                           });
37597                         }
37598
37599                         body += this.renderer.tablerow(cell);
37600                       }
37601
37602                       out += this.renderer.table(header, body);
37603                       continue;
37604                     }
37605
37606                   case 'blockquote':
37607                     {
37608                       body = this.parse(token.tokens);
37609                       out += this.renderer.blockquote(body);
37610                       continue;
37611                     }
37612
37613                   case 'list':
37614                     {
37615                       ordered = token.ordered;
37616                       start = token.start;
37617                       loose = token.loose;
37618                       l2 = token.items.length;
37619                       body = '';
37620
37621                       for (j = 0; j < l2; j++) {
37622                         item = token.items[j];
37623                         checked = item.checked;
37624                         task = item.task;
37625                         itemBody = '';
37626
37627                         if (item.task) {
37628                           checkbox = this.renderer.checkbox(checked);
37629
37630                           if (loose) {
37631                             if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
37632                               item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
37633
37634                               if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
37635                                 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
37636                               }
37637                             } else {
37638                               item.tokens.unshift({
37639                                 type: 'text',
37640                                 text: checkbox
37641                               });
37642                             }
37643                           } else {
37644                             itemBody += checkbox;
37645                           }
37646                         }
37647
37648                         itemBody += this.parse(item.tokens, loose);
37649                         body += this.renderer.listitem(itemBody, task, checked);
37650                       }
37651
37652                       out += this.renderer.list(body, ordered, start);
37653                       continue;
37654                     }
37655
37656                   case 'html':
37657                     {
37658                       // TODO parse inline content if parameter markdown=1
37659                       out += this.renderer.html(token.text);
37660                       continue;
37661                     }
37662
37663                   case 'paragraph':
37664                     {
37665                       out += this.renderer.paragraph(this.parseInline(token.tokens));
37666                       continue;
37667                     }
37668
37669                   case 'text':
37670                     {
37671                       body = token.tokens ? this.parseInline(token.tokens) : token.text;
37672
37673                       while (i + 1 < l && tokens[i + 1].type === 'text') {
37674                         token = tokens[++i];
37675                         body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
37676                       }
37677
37678                       out += top ? this.renderer.paragraph(body) : body;
37679                       continue;
37680                     }
37681
37682                   default:
37683                     {
37684                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37685
37686                       if (this.options.silent) {
37687                         console.error(errMsg);
37688                         return;
37689                       } else {
37690                         throw new Error(errMsg);
37691                       }
37692                     }
37693                 }
37694               }
37695
37696               return out;
37697             }
37698             /**
37699              * Parse Inline Tokens
37700              */
37701
37702           }, {
37703             key: "parseInline",
37704             value: function parseInline(tokens, renderer) {
37705               renderer = renderer || this.renderer;
37706               var out = '',
37707                   i,
37708                   token;
37709               var l = tokens.length;
37710
37711               for (i = 0; i < l; i++) {
37712                 token = tokens[i];
37713
37714                 switch (token.type) {
37715                   case 'escape':
37716                     {
37717                       out += renderer.text(token.text);
37718                       break;
37719                     }
37720
37721                   case 'html':
37722                     {
37723                       out += renderer.html(token.text);
37724                       break;
37725                     }
37726
37727                   case 'link':
37728                     {
37729                       out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
37730                       break;
37731                     }
37732
37733                   case 'image':
37734                     {
37735                       out += renderer.image(token.href, token.title, token.text);
37736                       break;
37737                     }
37738
37739                   case 'strong':
37740                     {
37741                       out += renderer.strong(this.parseInline(token.tokens, renderer));
37742                       break;
37743                     }
37744
37745                   case 'em':
37746                     {
37747                       out += renderer.em(this.parseInline(token.tokens, renderer));
37748                       break;
37749                     }
37750
37751                   case 'codespan':
37752                     {
37753                       out += renderer.codespan(token.text);
37754                       break;
37755                     }
37756
37757                   case 'br':
37758                     {
37759                       out += renderer.br();
37760                       break;
37761                     }
37762
37763                   case 'del':
37764                     {
37765                       out += renderer.del(this.parseInline(token.tokens, renderer));
37766                       break;
37767                     }
37768
37769                   case 'text':
37770                     {
37771                       out += renderer.text(token.text);
37772                       break;
37773                     }
37774
37775                   default:
37776                     {
37777                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37778
37779                       if (this.options.silent) {
37780                         console.error(errMsg);
37781                         return;
37782                       } else {
37783                         throw new Error(errMsg);
37784                       }
37785                     }
37786                 }
37787               }
37788
37789               return out;
37790             }
37791           }], [{
37792             key: "parse",
37793             value: function parse(tokens, options) {
37794               var parser = new Parser(options);
37795               return parser.parse(tokens);
37796             }
37797             /**
37798              * Static Parse Inline Method
37799              */
37800
37801           }, {
37802             key: "parseInline",
37803             value: function parseInline(tokens, options) {
37804               var parser = new Parser(options);
37805               return parser.parseInline(tokens);
37806             }
37807           }]);
37808
37809           return Parser;
37810         }();
37811
37812         var merge$3 = helpers.merge,
37813             checkSanitizeDeprecation$1 = helpers.checkSanitizeDeprecation,
37814             escape$3 = helpers.escape;
37815         var getDefaults = defaults.getDefaults,
37816             changeDefaults = defaults.changeDefaults,
37817             defaults$5 = defaults.defaults;
37818         /**
37819          * Marked
37820          */
37821
37822         function marked(src, opt, callback) {
37823           // throw error in case of non string input
37824           if (typeof src === 'undefined' || src === null) {
37825             throw new Error('marked(): input parameter is undefined or null');
37826           }
37827
37828           if (typeof src !== 'string') {
37829             throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
37830           }
37831
37832           if (typeof opt === 'function') {
37833             callback = opt;
37834             opt = null;
37835           }
37836
37837           opt = merge$3({}, marked.defaults, opt || {});
37838           checkSanitizeDeprecation$1(opt);
37839
37840           if (callback) {
37841             var highlight = opt.highlight;
37842             var tokens;
37843
37844             try {
37845               tokens = Lexer_1.lex(src, opt);
37846             } catch (e) {
37847               return callback(e);
37848             }
37849
37850             var done = function done(err) {
37851               var out;
37852
37853               if (!err) {
37854                 try {
37855                   out = Parser_1.parse(tokens, opt);
37856                 } catch (e) {
37857                   err = e;
37858                 }
37859               }
37860
37861               opt.highlight = highlight;
37862               return err ? callback(err) : callback(null, out);
37863             };
37864
37865             if (!highlight || highlight.length < 3) {
37866               return done();
37867             }
37868
37869             delete opt.highlight;
37870             if (!tokens.length) return done();
37871             var pending = 0;
37872             marked.walkTokens(tokens, function (token) {
37873               if (token.type === 'code') {
37874                 pending++;
37875                 setTimeout(function () {
37876                   highlight(token.text, token.lang, function (err, code) {
37877                     if (err) {
37878                       return done(err);
37879                     }
37880
37881                     if (code != null && code !== token.text) {
37882                       token.text = code;
37883                       token.escaped = true;
37884                     }
37885
37886                     pending--;
37887
37888                     if (pending === 0) {
37889                       done();
37890                     }
37891                   });
37892                 }, 0);
37893               }
37894             });
37895
37896             if (pending === 0) {
37897               done();
37898             }
37899
37900             return;
37901           }
37902
37903           try {
37904             var _tokens = Lexer_1.lex(src, opt);
37905
37906             if (opt.walkTokens) {
37907               marked.walkTokens(_tokens, opt.walkTokens);
37908             }
37909
37910             return Parser_1.parse(_tokens, opt);
37911           } catch (e) {
37912             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
37913
37914             if (opt.silent) {
37915               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
37916             }
37917
37918             throw e;
37919           }
37920         }
37921         /**
37922          * Options
37923          */
37924
37925
37926         marked.options = marked.setOptions = function (opt) {
37927           merge$3(marked.defaults, opt);
37928           changeDefaults(marked.defaults);
37929           return marked;
37930         };
37931
37932         marked.getDefaults = getDefaults;
37933         marked.defaults = defaults$5;
37934         /**
37935          * Use Extension
37936          */
37937
37938         marked.use = function (extension) {
37939           var opts = merge$3({}, extension);
37940
37941           if (extension.renderer) {
37942             (function () {
37943               var renderer = marked.defaults.renderer || new Renderer_1();
37944
37945               var _loop = function _loop(prop) {
37946                 var prevRenderer = renderer[prop];
37947
37948                 renderer[prop] = function () {
37949                   for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
37950                     args[_key] = arguments[_key];
37951                   }
37952
37953                   var ret = extension.renderer[prop].apply(renderer, args);
37954
37955                   if (ret === false) {
37956                     ret = prevRenderer.apply(renderer, args);
37957                   }
37958
37959                   return ret;
37960                 };
37961               };
37962
37963               for (var prop in extension.renderer) {
37964                 _loop(prop);
37965               }
37966
37967               opts.renderer = renderer;
37968             })();
37969           }
37970
37971           if (extension.tokenizer) {
37972             (function () {
37973               var tokenizer = marked.defaults.tokenizer || new Tokenizer_1();
37974
37975               var _loop2 = function _loop2(prop) {
37976                 var prevTokenizer = tokenizer[prop];
37977
37978                 tokenizer[prop] = function () {
37979                   for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
37980                     args[_key2] = arguments[_key2];
37981                   }
37982
37983                   var ret = extension.tokenizer[prop].apply(tokenizer, args);
37984
37985                   if (ret === false) {
37986                     ret = prevTokenizer.apply(tokenizer, args);
37987                   }
37988
37989                   return ret;
37990                 };
37991               };
37992
37993               for (var prop in extension.tokenizer) {
37994                 _loop2(prop);
37995               }
37996
37997               opts.tokenizer = tokenizer;
37998             })();
37999           }
38000
38001           if (extension.walkTokens) {
38002             var walkTokens = marked.defaults.walkTokens;
38003
38004             opts.walkTokens = function (token) {
38005               extension.walkTokens(token);
38006
38007               if (walkTokens) {
38008                 walkTokens(token);
38009               }
38010             };
38011           }
38012
38013           marked.setOptions(opts);
38014         };
38015         /**
38016          * Run callback for every token
38017          */
38018
38019
38020         marked.walkTokens = function (tokens, callback) {
38021           var _iterator = _createForOfIteratorHelper(tokens),
38022               _step;
38023
38024           try {
38025             for (_iterator.s(); !(_step = _iterator.n()).done;) {
38026               var token = _step.value;
38027               callback(token);
38028
38029               switch (token.type) {
38030                 case 'table':
38031                   {
38032                     var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
38033                         _step2;
38034
38035                     try {
38036                       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
38037                         var cell = _step2.value;
38038                         marked.walkTokens(cell, callback);
38039                       }
38040                     } catch (err) {
38041                       _iterator2.e(err);
38042                     } finally {
38043                       _iterator2.f();
38044                     }
38045
38046                     var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
38047                         _step3;
38048
38049                     try {
38050                       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
38051                         var row = _step3.value;
38052
38053                         var _iterator4 = _createForOfIteratorHelper(row),
38054                             _step4;
38055
38056                         try {
38057                           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
38058                             var _cell = _step4.value;
38059                             marked.walkTokens(_cell, callback);
38060                           }
38061                         } catch (err) {
38062                           _iterator4.e(err);
38063                         } finally {
38064                           _iterator4.f();
38065                         }
38066                       }
38067                     } catch (err) {
38068                       _iterator3.e(err);
38069                     } finally {
38070                       _iterator3.f();
38071                     }
38072
38073                     break;
38074                   }
38075
38076                 case 'list':
38077                   {
38078                     marked.walkTokens(token.items, callback);
38079                     break;
38080                   }
38081
38082                 default:
38083                   {
38084                     if (token.tokens) {
38085                       marked.walkTokens(token.tokens, callback);
38086                     }
38087                   }
38088               }
38089             }
38090           } catch (err) {
38091             _iterator.e(err);
38092           } finally {
38093             _iterator.f();
38094           }
38095         };
38096         /**
38097          * Parse Inline
38098          */
38099
38100
38101         marked.parseInline = function (src, opt) {
38102           // throw error in case of non string input
38103           if (typeof src === 'undefined' || src === null) {
38104             throw new Error('marked.parseInline(): input parameter is undefined or null');
38105           }
38106
38107           if (typeof src !== 'string') {
38108             throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
38109           }
38110
38111           opt = merge$3({}, marked.defaults, opt || {});
38112           checkSanitizeDeprecation$1(opt);
38113
38114           try {
38115             var tokens = Lexer_1.lexInline(src, opt);
38116
38117             if (opt.walkTokens) {
38118               marked.walkTokens(tokens, opt.walkTokens);
38119             }
38120
38121             return Parser_1.parseInline(tokens, opt);
38122           } catch (e) {
38123             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
38124
38125             if (opt.silent) {
38126               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
38127             }
38128
38129             throw e;
38130           }
38131         };
38132         /**
38133          * Expose
38134          */
38135
38136
38137         marked.Parser = Parser_1;
38138         marked.parser = Parser_1.parse;
38139         marked.Renderer = Renderer_1;
38140         marked.TextRenderer = TextRenderer_1;
38141         marked.Lexer = Lexer_1;
38142         marked.lexer = Lexer_1.lex;
38143         marked.Tokenizer = Tokenizer_1;
38144         marked.Slugger = Slugger_1;
38145         marked.parse = marked;
38146         var marked_1 = marked;
38147
38148         var tiler$2 = utilTiler();
38149         var dispatch$3 = dispatch('loaded');
38150         var _tileZoom$2 = 14;
38151         var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
38152         var _osmoseData = {
38153           icons: {},
38154           items: []
38155         }; // This gets reassigned if reset
38156
38157         var _cache$2;
38158
38159         function abortRequest$2(controller) {
38160           if (controller) {
38161             controller.abort();
38162           }
38163         }
38164
38165         function abortUnwantedRequests$2(cache, tiles) {
38166           Object.keys(cache.inflightTile).forEach(function (k) {
38167             var wanted = tiles.find(function (tile) {
38168               return k === tile.id;
38169             });
38170
38171             if (!wanted) {
38172               abortRequest$2(cache.inflightTile[k]);
38173               delete cache.inflightTile[k];
38174             }
38175           });
38176         }
38177
38178         function encodeIssueRtree$2(d) {
38179           return {
38180             minX: d.loc[0],
38181             minY: d.loc[1],
38182             maxX: d.loc[0],
38183             maxY: d.loc[1],
38184             data: d
38185           };
38186         } // Replace or remove QAItem from rtree
38187
38188
38189         function updateRtree$2(item, replace) {
38190           _cache$2.rtree.remove(item, function (a, b) {
38191             return a.data.id === b.data.id;
38192           });
38193
38194           if (replace) {
38195             _cache$2.rtree.insert(item);
38196           }
38197         } // Issues shouldn't obscure each other
38198
38199
38200         function preventCoincident$1(loc) {
38201           var coincident = false;
38202
38203           do {
38204             // first time, move marker up. after that, move marker right.
38205             var delta = coincident ? [0.00001, 0] : [0, 0.00001];
38206             loc = geoVecAdd(loc, delta);
38207             var bbox = geoExtent(loc).bbox();
38208             coincident = _cache$2.rtree.search(bbox).length;
38209           } while (coincident);
38210
38211           return loc;
38212         }
38213
38214         var serviceOsmose = {
38215           title: 'osmose',
38216           init: function init() {
38217             _mainFileFetcher.get('qa_data').then(function (d) {
38218               _osmoseData = d.osmose;
38219               _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
38220                 return s.split('-')[0];
38221               }).reduce(function (unique, item) {
38222                 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
38223               }, []);
38224             });
38225
38226             if (!_cache$2) {
38227               this.reset();
38228             }
38229
38230             this.event = utilRebind(this, dispatch$3, 'on');
38231           },
38232           reset: function reset() {
38233             var _strings = {};
38234             var _colors = {};
38235
38236             if (_cache$2) {
38237               Object.values(_cache$2.inflightTile).forEach(abortRequest$2); // Strings and colors are static and should not be re-populated
38238
38239               _strings = _cache$2.strings;
38240               _colors = _cache$2.colors;
38241             }
38242
38243             _cache$2 = {
38244               data: {},
38245               loadedTile: {},
38246               inflightTile: {},
38247               inflightPost: {},
38248               closed: {},
38249               rtree: new RBush(),
38250               strings: _strings,
38251               colors: _colors
38252             };
38253           },
38254           loadIssues: function loadIssues(projection) {
38255             var _this = this;
38256
38257             var params = {
38258               // Tiles return a maximum # of issues
38259               // So we want to filter our request for only types iD supports
38260               item: _osmoseData.items
38261             }; // determine the needed tiles to cover the view
38262
38263             var tiles = tiler$2.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
38264
38265             abortUnwantedRequests$2(_cache$2, tiles); // issue new requests..
38266
38267             tiles.forEach(function (tile) {
38268               if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
38269
38270               var _tile$xyz = _slicedToArray(tile.xyz, 3),
38271                   x = _tile$xyz[0],
38272                   y = _tile$xyz[1],
38273                   z = _tile$xyz[2];
38274
38275               var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
38276               var controller = new AbortController();
38277               _cache$2.inflightTile[tile.id] = controller;
38278               d3_json(url, {
38279                 signal: controller.signal
38280               }).then(function (data) {
38281                 delete _cache$2.inflightTile[tile.id];
38282                 _cache$2.loadedTile[tile.id] = true;
38283
38284                 if (data.features) {
38285                   data.features.forEach(function (issue) {
38286                     var _issue$properties = issue.properties,
38287                         item = _issue$properties.item,
38288                         cl = _issue$properties["class"],
38289                         id = _issue$properties.uuid;
38290                     /* Osmose issues are uniquely identified by a unique
38291                       `item` and `class` combination (both integer values) */
38292
38293                     var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
38294
38295                     if (itemType in _osmoseData.icons) {
38296                       var loc = issue.geometry.coordinates; // lon, lat
38297
38298                       loc = preventCoincident$1(loc);
38299                       var d = new QAItem(loc, _this, itemType, id, {
38300                         item: item
38301                       }); // Setting elems here prevents UI detail requests
38302
38303                       if (item === 8300 || item === 8360) {
38304                         d.elems = [];
38305                       }
38306
38307                       _cache$2.data[d.id] = d;
38308
38309                       _cache$2.rtree.insert(encodeIssueRtree$2(d));
38310                     }
38311                   });
38312                 }
38313
38314                 dispatch$3.call('loaded');
38315               })["catch"](function () {
38316                 delete _cache$2.inflightTile[tile.id];
38317                 _cache$2.loadedTile[tile.id] = true;
38318               });
38319             });
38320           },
38321           loadIssueDetail: function loadIssueDetail(issue) {
38322             var _this2 = this;
38323
38324             // Issue details only need to be fetched once
38325             if (issue.elems !== undefined) {
38326               return Promise.resolve(issue);
38327             }
38328
38329             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
38330
38331             var cacheDetails = function cacheDetails(data) {
38332               // Associated elements used for highlighting
38333               // Assign directly for immediate use in the callback
38334               issue.elems = data.elems.map(function (e) {
38335                 return e.type.substring(0, 1) + e.id;
38336               }); // Some issues have instance specific detail in a subtitle
38337
38338               issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
38339
38340               _this2.replaceItem(issue);
38341             };
38342
38343             return d3_json(url).then(cacheDetails).then(function () {
38344               return issue;
38345             });
38346           },
38347           loadStrings: function loadStrings() {
38348             var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
38349             var items = Object.keys(_osmoseData.icons);
38350
38351             if (locale in _cache$2.strings && Object.keys(_cache$2.strings[locale]).length === items.length) {
38352               return Promise.resolve(_cache$2.strings[locale]);
38353             } // May be partially populated already if some requests were successful
38354
38355
38356             if (!(locale in _cache$2.strings)) {
38357               _cache$2.strings[locale] = {};
38358             } // Only need to cache strings for supported issue types
38359             // Using multiple individual item + class requests to reduce fetched data size
38360
38361
38362             var allRequests = items.map(function (itemType) {
38363               // No need to request data we already have
38364               if (itemType in _cache$2.strings[locale]) return null;
38365
38366               var cacheData = function cacheData(data) {
38367                 // Bunch of nested single value arrays of objects
38368                 var _data$categories = _slicedToArray(data.categories, 1),
38369                     _data$categories$ = _data$categories[0],
38370                     cat = _data$categories$ === void 0 ? {
38371                   items: []
38372                 } : _data$categories$;
38373
38374                 var _cat$items = _slicedToArray(cat.items, 1),
38375                     _cat$items$ = _cat$items[0],
38376                     item = _cat$items$ === void 0 ? {
38377                   "class": []
38378                 } : _cat$items$;
38379
38380                 var _item$class = _slicedToArray(item["class"], 1),
38381                     _item$class$ = _item$class[0],
38382                     cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
38383
38384
38385                 if (!cl) {
38386                   /* eslint-disable no-console */
38387                   console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
38388                   /* eslint-enable no-console */
38389
38390                   return;
38391                 } // Cache served item colors to automatically style issue markers later
38392
38393
38394                 var itemInt = item.item,
38395                     color = item.color;
38396
38397                 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
38398                   _cache$2.colors[itemInt] = color;
38399                 } // Value of root key will be null if no string exists
38400                 // If string exists, value is an object with key 'auto' for string
38401
38402
38403                 var title = cl.title,
38404                     detail = cl.detail,
38405                     fix = cl.fix,
38406                     trap = cl.trap; // Osmose titles shouldn't contain markdown
38407
38408                 var issueStrings = {};
38409                 if (title) issueStrings.title = title.auto;
38410                 if (detail) issueStrings.detail = marked_1(detail.auto);
38411                 if (trap) issueStrings.trap = marked_1(trap.auto);
38412                 if (fix) issueStrings.fix = marked_1(fix.auto);
38413                 _cache$2.strings[locale][itemType] = issueStrings;
38414               };
38415
38416               var _itemType$split = itemType.split('-'),
38417                   _itemType$split2 = _slicedToArray(_itemType$split, 2),
38418                   item = _itemType$split2[0],
38419                   cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
38420
38421
38422               var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
38423               return d3_json(url).then(cacheData);
38424             }).filter(Boolean);
38425             return Promise.all(allRequests).then(function () {
38426               return _cache$2.strings[locale];
38427             });
38428           },
38429           getStrings: function getStrings(itemType) {
38430             var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
38431             // No need to fallback to English, Osmose API handles this for us
38432             return locale in _cache$2.strings ? _cache$2.strings[locale][itemType] : {};
38433           },
38434           getColor: function getColor(itemType) {
38435             return itemType in _cache$2.colors ? _cache$2.colors[itemType] : '#FFFFFF';
38436           },
38437           postUpdate: function postUpdate(issue, callback) {
38438             var _this3 = this;
38439
38440             if (_cache$2.inflightPost[issue.id]) {
38441               return callback({
38442                 message: 'Issue update already inflight',
38443                 status: -2
38444               }, issue);
38445             } // UI sets the status to either 'done' or 'false'
38446
38447
38448             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
38449             var controller = new AbortController();
38450
38451             var after = function after() {
38452               delete _cache$2.inflightPost[issue.id];
38453
38454               _this3.removeItem(issue);
38455
38456               if (issue.newStatus === 'done') {
38457                 // Keep track of the number of issues closed per `item` to tag the changeset
38458                 if (!(issue.item in _cache$2.closed)) {
38459                   _cache$2.closed[issue.item] = 0;
38460                 }
38461
38462                 _cache$2.closed[issue.item] += 1;
38463               }
38464
38465               if (callback) callback(null, issue);
38466             };
38467
38468             _cache$2.inflightPost[issue.id] = controller;
38469             fetch(url, {
38470               signal: controller.signal
38471             }).then(after)["catch"](function (err) {
38472               delete _cache$2.inflightPost[issue.id];
38473               if (callback) callback(err.message);
38474             });
38475           },
38476           // Get all cached QAItems covering the viewport
38477           getItems: function getItems(projection) {
38478             var viewport = projection.clipExtent();
38479             var min = [viewport[0][0], viewport[1][1]];
38480             var max = [viewport[1][0], viewport[0][1]];
38481             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38482             return _cache$2.rtree.search(bbox).map(function (d) {
38483               return d.data;
38484             });
38485           },
38486           // Get a QAItem from cache
38487           // NOTE: Don't change method name until UI v3 is merged
38488           getError: function getError(id) {
38489             return _cache$2.data[id];
38490           },
38491           // get the name of the icon to display for this item
38492           getIcon: function getIcon(itemType) {
38493             return _osmoseData.icons[itemType];
38494           },
38495           // Replace a single QAItem in the cache
38496           replaceItem: function replaceItem(item) {
38497             if (!(item instanceof QAItem) || !item.id) return;
38498             _cache$2.data[item.id] = item;
38499             updateRtree$2(encodeIssueRtree$2(item), true); // true = replace
38500
38501             return item;
38502           },
38503           // Remove a single QAItem from the cache
38504           removeItem: function removeItem(item) {
38505             if (!(item instanceof QAItem) || !item.id) return;
38506             delete _cache$2.data[item.id];
38507             updateRtree$2(encodeIssueRtree$2(item), false); // false = remove
38508           },
38509           // Used to populate `closed:osmose:*` changeset tags
38510           getClosedCounts: function getClosedCounts() {
38511             return _cache$2.closed;
38512           },
38513           itemURL: function itemURL(item) {
38514             return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
38515           }
38516         };
38517
38518         var apibase = 'https://a.mapillary.com/v3/';
38519         var viewercss = 'mapillary-js/mapillary.min.css';
38520         var viewerjs = 'mapillary-js/mapillary.min.js';
38521         var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
38522         var mapFeatureConfig = {
38523           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(',')
38524         };
38525         var maxResults = 1000;
38526         var tileZoom = 14;
38527         var tiler$3 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
38528         var dispatch$4 = dispatch('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'nodeChanged');
38529         var _mlyFallback = false;
38530
38531         var _mlyCache;
38532
38533         var _mlyClicks;
38534
38535         var _mlyActiveImage;
38536
38537         var _mlySelectedImageKey;
38538
38539         var _mlyViewer;
38540
38541         var _mlyViewerFilter = ['all'];
38542
38543         var _loadViewerPromise;
38544
38545         var _mlyHighlightedDetection;
38546
38547         var _mlyShowFeatureDetections = false;
38548         var _mlyShowSignDetections = false;
38549
38550         function abortRequest$3(controller) {
38551           controller.abort();
38552         }
38553
38554         function loadTiles(which, url, projection) {
38555           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
38556           var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
38557
38558           var cache = _mlyCache[which];
38559           Object.keys(cache.inflight).forEach(function (k) {
38560             var wanted = tiles.find(function (tile) {
38561               return k.indexOf(tile.id + ',') === 0;
38562             });
38563
38564             if (!wanted) {
38565               abortRequest$3(cache.inflight[k]);
38566               delete cache.inflight[k];
38567             }
38568           });
38569           tiles.forEach(function (tile) {
38570             loadNextTilePage(which, currZoom, url, tile);
38571           });
38572         }
38573
38574         function loadNextTilePage(which, currZoom, url, tile) {
38575           var cache = _mlyCache[which];
38576           var rect = tile.extent.rectangle();
38577           var maxPages = maxPageAtZoom(currZoom);
38578           var nextPage = cache.nextPage[tile.id] || 0;
38579           var nextURL = cache.nextURL[tile.id] || url + utilQsString({
38580             per_page: maxResults,
38581             page: nextPage,
38582             client_id: clientId,
38583             bbox: [rect[0], rect[1], rect[2], rect[3]].join(',')
38584           });
38585           if (nextPage > maxPages) return;
38586           var id = tile.id + ',' + String(nextPage);
38587           if (cache.loaded[id] || cache.inflight[id]) return;
38588           var controller = new AbortController();
38589           cache.inflight[id] = controller;
38590           var options = {
38591             method: 'GET',
38592             signal: controller.signal,
38593             headers: {
38594               'Content-Type': 'application/json'
38595             }
38596           };
38597           fetch(nextURL, options).then(function (response) {
38598             if (!response.ok) {
38599               throw new Error(response.status + ' ' + response.statusText);
38600             }
38601
38602             var linkHeader = response.headers.get('Link');
38603
38604             if (linkHeader) {
38605               var pagination = parsePagination(linkHeader);
38606
38607               if (pagination.next) {
38608                 cache.nextURL[tile.id] = pagination.next;
38609               }
38610             }
38611
38612             return response.json();
38613           }).then(function (data) {
38614             cache.loaded[id] = true;
38615             delete cache.inflight[id];
38616
38617             if (!data || !data.features || !data.features.length) {
38618               throw new Error('No Data');
38619             }
38620
38621             var features = data.features.map(function (feature) {
38622               var loc = feature.geometry.coordinates;
38623               var d; // An image (shown as a green dot on the map) is a single street photo with extra
38624               // information such as location, camera angle (CA), camera model, and so on.
38625               // Each image feature is a GeoJSON Point
38626
38627               if (which === 'images') {
38628                 d = {
38629                   loc: loc,
38630                   key: feature.properties.key,
38631                   ca: feature.properties.ca,
38632                   captured_at: feature.properties.captured_at,
38633                   captured_by: feature.properties.username,
38634                   pano: feature.properties.pano
38635                 };
38636                 cache.forImageKey[d.key] = d; // cache imageKey -> image
38637                 // Mapillary organizes images as sequences. A sequence of images are continuously captured
38638                 // by a user at a give time. Sequences are shown on the map as green lines.
38639                 // Each sequence feature is a GeoJSON LineString
38640               } else if (which === 'sequences') {
38641                 var sequenceKey = feature.properties.key;
38642                 cache.lineString[sequenceKey] = feature; // cache sequenceKey -> lineString
38643
38644                 feature.properties.coordinateProperties.image_keys.forEach(function (imageKey) {
38645                   cache.forImageKey[imageKey] = sequenceKey; // cache imageKey -> sequenceKey
38646                 });
38647                 return false; // because no `d` data worth loading into an rbush
38648                 // A map feature is a real world object that can be shown on a map. It could be any object
38649                 // recognized from images, manually added in images, or added on the map.
38650                 // Each map feature is a GeoJSON Point (located where the feature is)
38651               } else if (which === 'map_features' || which === 'points') {
38652                 d = {
38653                   loc: loc,
38654                   key: feature.properties.key,
38655                   value: feature.properties.value,
38656                   detections: feature.properties.detections,
38657                   direction: feature.properties.direction,
38658                   accuracy: feature.properties.accuracy,
38659                   first_seen_at: feature.properties.first_seen_at,
38660                   last_seen_at: feature.properties.last_seen_at
38661                 };
38662               }
38663
38664               return {
38665                 minX: loc[0],
38666                 minY: loc[1],
38667                 maxX: loc[0],
38668                 maxY: loc[1],
38669                 data: d
38670               };
38671             }).filter(Boolean);
38672
38673             if (cache.rtree && features) {
38674               cache.rtree.load(features);
38675             }
38676
38677             if (data.features.length === maxResults) {
38678               // more pages to load
38679               cache.nextPage[tile.id] = nextPage + 1;
38680               loadNextTilePage(which, currZoom, url, tile);
38681             } else {
38682               cache.nextPage[tile.id] = Infinity; // no more pages to load
38683             }
38684
38685             if (which === 'images' || which === 'sequences') {
38686               dispatch$4.call('loadedImages');
38687             } else if (which === 'map_features') {
38688               dispatch$4.call('loadedSigns');
38689             } else if (which === 'points') {
38690               dispatch$4.call('loadedMapFeatures');
38691             }
38692           })["catch"](function () {
38693             cache.loaded[id] = true;
38694             delete cache.inflight[id];
38695           });
38696         }
38697
38698         function loadData(which, url) {
38699           var cache = _mlyCache[which];
38700           var options = {
38701             method: 'GET',
38702             headers: {
38703               'Content-Type': 'application/json'
38704             }
38705           };
38706           var nextUrl = url + '&client_id=' + clientId;
38707           return fetch(nextUrl, options).then(function (response) {
38708             if (!response.ok) {
38709               throw new Error(response.status + ' ' + response.statusText);
38710             }
38711
38712             return response.json();
38713           }).then(function (data) {
38714             if (!data || !data.features || !data.features.length) {
38715               throw new Error('No Data');
38716             }
38717
38718             data.features.forEach(function (feature) {
38719               var d;
38720
38721               if (which === 'image_detections') {
38722                 d = {
38723                   key: feature.properties.key,
38724                   image_key: feature.properties.image_key,
38725                   value: feature.properties.value,
38726                   shape: feature.properties.shape
38727                 };
38728
38729                 if (!cache.forImageKey[d.image_key]) {
38730                   cache.forImageKey[d.image_key] = [];
38731                 }
38732
38733                 cache.forImageKey[d.image_key].push(d);
38734               }
38735             });
38736           });
38737         }
38738
38739         function maxPageAtZoom(z) {
38740           if (z < 15) return 2;
38741           if (z === 15) return 5;
38742           if (z === 16) return 10;
38743           if (z === 17) return 20;
38744           if (z === 18) return 40;
38745           if (z > 18) return 80;
38746         } // extract links to pages of API results
38747
38748
38749         function parsePagination(links) {
38750           return links.split(',').map(function (rel) {
38751             var elements = rel.split(';');
38752
38753             if (elements.length === 2) {
38754               return [/<(.+)>/.exec(elements[0])[1], /rel="(.+)"/.exec(elements[1])[1]];
38755             } else {
38756               return ['', ''];
38757             }
38758           }).reduce(function (pagination, val) {
38759             pagination[val[1]] = val[0];
38760             return pagination;
38761           }, {});
38762         } // partition viewport into higher zoom tiles
38763
38764
38765         function partitionViewport(projection) {
38766           var z = geoScaleToZoom(projection.scale());
38767           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
38768
38769           var tiler = utilTiler().zoomExtent([z2, z2]);
38770           return tiler.getTiles(projection).map(function (tile) {
38771             return tile.extent;
38772           });
38773         } // no more than `limit` results per partition.
38774
38775
38776         function searchLimited(limit, projection, rtree) {
38777           limit = limit || 5;
38778           return partitionViewport(projection).reduce(function (result, extent) {
38779             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
38780               return d.data;
38781             });
38782             return found.length ? result.concat(found) : result;
38783           }, []);
38784         }
38785
38786         var serviceMapillary = {
38787           init: function init() {
38788             if (!_mlyCache) {
38789               this.reset();
38790             }
38791
38792             this.event = utilRebind(this, dispatch$4, 'on');
38793           },
38794           reset: function reset() {
38795             if (_mlyCache) {
38796               Object.values(_mlyCache.images.inflight).forEach(abortRequest$3);
38797               Object.values(_mlyCache.image_detections.inflight).forEach(abortRequest$3);
38798               Object.values(_mlyCache.map_features.inflight).forEach(abortRequest$3);
38799               Object.values(_mlyCache.points.inflight).forEach(abortRequest$3);
38800               Object.values(_mlyCache.sequences.inflight).forEach(abortRequest$3);
38801             }
38802
38803             _mlyCache = {
38804               images: {
38805                 inflight: {},
38806                 loaded: {},
38807                 nextPage: {},
38808                 nextURL: {},
38809                 rtree: new RBush(),
38810                 forImageKey: {}
38811               },
38812               image_detections: {
38813                 inflight: {},
38814                 loaded: {},
38815                 nextPage: {},
38816                 nextURL: {},
38817                 forImageKey: {}
38818               },
38819               map_features: {
38820                 inflight: {},
38821                 loaded: {},
38822                 nextPage: {},
38823                 nextURL: {},
38824                 rtree: new RBush()
38825               },
38826               points: {
38827                 inflight: {},
38828                 loaded: {},
38829                 nextPage: {},
38830                 nextURL: {},
38831                 rtree: new RBush()
38832               },
38833               sequences: {
38834                 inflight: {},
38835                 loaded: {},
38836                 nextPage: {},
38837                 nextURL: {},
38838                 rtree: new RBush(),
38839                 forImageKey: {},
38840                 lineString: {}
38841               }
38842             };
38843             _mlySelectedImageKey = null;
38844             _mlyActiveImage = null;
38845             _mlyClicks = [];
38846           },
38847           images: function images(projection) {
38848             var limit = 5;
38849             return searchLimited(limit, projection, _mlyCache.images.rtree);
38850           },
38851           signs: function signs(projection) {
38852             var limit = 5;
38853             return searchLimited(limit, projection, _mlyCache.map_features.rtree);
38854           },
38855           mapFeatures: function mapFeatures(projection) {
38856             var limit = 5;
38857             return searchLimited(limit, projection, _mlyCache.points.rtree);
38858           },
38859           cachedImage: function cachedImage(imageKey) {
38860             return _mlyCache.images.forImageKey[imageKey];
38861           },
38862           sequences: function sequences(projection) {
38863             var viewport = projection.clipExtent();
38864             var min = [viewport[0][0], viewport[1][1]];
38865             var max = [viewport[1][0], viewport[0][1]];
38866             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38867             var sequenceKeys = {}; // all sequences for images in viewport
38868
38869             _mlyCache.images.rtree.search(bbox).forEach(function (d) {
38870               var sequenceKey = _mlyCache.sequences.forImageKey[d.data.key];
38871
38872               if (sequenceKey) {
38873                 sequenceKeys[sequenceKey] = true;
38874               }
38875             }); // Return lineStrings for the sequences
38876
38877
38878             return Object.keys(sequenceKeys).map(function (sequenceKey) {
38879               return _mlyCache.sequences.lineString[sequenceKey];
38880             });
38881           },
38882           signsSupported: function signsSupported() {
38883             return true;
38884           },
38885           loadImages: function loadImages(projection) {
38886             loadTiles('images', apibase + 'images?sort_by=key&', projection);
38887             loadTiles('sequences', apibase + 'sequences?sort_by=key&', projection);
38888           },
38889           loadSigns: function loadSigns(projection) {
38890             loadTiles('map_features', apibase + 'map_features?layers=trafficsigns&min_nbr_image_detections=2&sort_by=key&', projection);
38891           },
38892           loadMapFeatures: function loadMapFeatures(projection) {
38893             loadTiles('points', apibase + 'map_features?layers=points&min_nbr_image_detections=2&sort_by=key&values=' + mapFeatureConfig.values + '&', projection);
38894           },
38895           ensureViewerLoaded: function ensureViewerLoaded(context) {
38896             if (_loadViewerPromise) return _loadViewerPromise; // add mly-wrapper
38897
38898             var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
38899             wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
38900             var that = this;
38901             _loadViewerPromise = new Promise(function (resolve, reject) {
38902               var loadedCount = 0;
38903
38904               function loaded() {
38905                 loadedCount += 1; // wait until both files are loaded
38906
38907                 if (loadedCount === 2) resolve();
38908               }
38909
38910               var head = select('head'); // load mapillary-viewercss
38911
38912               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 () {
38913                 reject();
38914               }); // load mapillary-viewerjs
38915
38916               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 () {
38917                 reject();
38918               });
38919             })["catch"](function () {
38920               _loadViewerPromise = null;
38921             }).then(function () {
38922               that.initViewer(context);
38923             });
38924             return _loadViewerPromise;
38925           },
38926           loadSignResources: function loadSignResources(context) {
38927             context.ui().svgDefs.addSprites(['mapillary-sprite'], false
38928             /* don't override colors */
38929             );
38930             return this;
38931           },
38932           loadObjectResources: function loadObjectResources(context) {
38933             context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
38934             /* don't override colors */
38935             );
38936             return this;
38937           },
38938           resetTags: function resetTags() {
38939             if (_mlyViewer && !_mlyFallback) {
38940               _mlyViewer.getComponent('tag').removeAll(); // remove previous detections
38941
38942             }
38943           },
38944           showFeatureDetections: function showFeatureDetections(value) {
38945             _mlyShowFeatureDetections = value;
38946
38947             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38948               this.resetTags();
38949             }
38950           },
38951           showSignDetections: function showSignDetections(value) {
38952             _mlyShowSignDetections = value;
38953
38954             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38955               this.resetTags();
38956             }
38957           },
38958           filterViewer: function filterViewer(context) {
38959             var showsPano = context.photos().showsPanoramic();
38960             var showsFlat = context.photos().showsFlat();
38961             var fromDate = context.photos().fromDate();
38962             var toDate = context.photos().toDate();
38963             var usernames = context.photos().usernames();
38964             var filter = ['all'];
38965             if (!showsPano) filter.push(['==', 'pano', false]);
38966             if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
38967             if (usernames && usernames.length) filter.push(['==', 'username', usernames[0]]);
38968
38969             if (fromDate) {
38970               var fromTimestamp = new Date(fromDate).getTime();
38971               filter.push(['>=', 'capturedAt', fromTimestamp]);
38972             }
38973
38974             if (toDate) {
38975               var toTimestamp = new Date(toDate).getTime();
38976               filter.push(['>=', 'capturedAt', toTimestamp]);
38977             }
38978
38979             if (_mlyViewer) {
38980               _mlyViewer.setFilter(filter);
38981             }
38982
38983             _mlyViewerFilter = filter;
38984             return filter;
38985           },
38986           showViewer: function showViewer(context) {
38987             var wrap = context.container().select('.photoviewer').classed('hide', false);
38988             var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
38989
38990             if (isHidden && _mlyViewer) {
38991               wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
38992               wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
38993
38994               _mlyViewer.resize();
38995             }
38996
38997             return this;
38998           },
38999           hideViewer: function hideViewer(context) {
39000             _mlyActiveImage = null;
39001             _mlySelectedImageKey = null;
39002
39003             if (!_mlyFallback && _mlyViewer) {
39004               _mlyViewer.getComponent('sequence').stop();
39005             }
39006
39007             var viewer = context.container().select('.photoviewer');
39008             if (!viewer.empty()) viewer.datum(null);
39009             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
39010             this.updateUrlImage(null);
39011             dispatch$4.call('nodeChanged');
39012             return this.setStyles(context, null, true);
39013           },
39014           parsePagination: parsePagination,
39015           updateUrlImage: function updateUrlImage(imageKey) {
39016             if (!window.mocha) {
39017               var hash = utilStringQs(window.location.hash);
39018
39019               if (imageKey) {
39020                 hash.photo = 'mapillary/' + imageKey;
39021               } else {
39022                 delete hash.photo;
39023               }
39024
39025               window.location.replace('#' + utilQsString(hash, true));
39026             }
39027           },
39028           highlightDetection: function highlightDetection(detection) {
39029             if (detection) {
39030               _mlyHighlightedDetection = detection.detection_key;
39031             }
39032
39033             return this;
39034           },
39035           initViewer: function initViewer(context) {
39036             var that = this;
39037             if (!window.Mapillary) return;
39038             var opts = {
39039               baseImageSize: 320,
39040               component: {
39041                 cover: false,
39042                 keyboard: false,
39043                 tag: true
39044               }
39045             }; // Disable components requiring WebGL support
39046
39047             if (!Mapillary.isSupported() && Mapillary.isFallbackSupported()) {
39048               _mlyFallback = true;
39049               opts.component = {
39050                 cover: false,
39051                 direction: false,
39052                 imagePlane: false,
39053                 keyboard: false,
39054                 mouse: false,
39055                 sequence: false,
39056                 tag: false,
39057                 image: true,
39058                 // fallback
39059                 navigation: true // fallback
39060
39061               };
39062             }
39063
39064             _mlyViewer = new Mapillary.Viewer('ideditor-mly', clientId, null, opts);
39065
39066             _mlyViewer.on('nodechanged', nodeChanged);
39067
39068             _mlyViewer.on('bearingchanged', bearingChanged);
39069
39070             if (_mlyViewerFilter) {
39071               _mlyViewer.setFilter(_mlyViewerFilter);
39072             } // Register viewer resize handler
39073
39074
39075             context.ui().photoviewer.on('resize.mapillary', function () {
39076               if (_mlyViewer) _mlyViewer.resize();
39077             }); // nodeChanged: called after the viewer has changed images and is ready.
39078             //
39079             // There is some logic here to batch up clicks into a _mlyClicks array
39080             // because the user might click on a lot of markers quickly and nodechanged
39081             // may be called out of order asynchronously.
39082             //
39083             // Clicks are added to the array in `selectedImage` and removed here.
39084             //
39085
39086             function nodeChanged(node) {
39087               that.resetTags();
39088               var clicks = _mlyClicks;
39089               var index = clicks.indexOf(node.key);
39090               var selectedKey = _mlySelectedImageKey;
39091               that.setActiveImage(node);
39092
39093               if (index > -1) {
39094                 // `nodechanged` initiated from clicking on a marker..
39095                 clicks.splice(index, 1); // remove the click
39096                 // If `node.key` matches the current _mlySelectedImageKey, call `selectImage()`
39097                 // one more time to update the detections and attribution..
39098
39099                 if (node.key === selectedKey) {
39100                   that.selectImage(context, _mlySelectedImageKey, true);
39101                 }
39102               } else {
39103                 // `nodechanged` initiated from the Mapillary viewer controls..
39104                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
39105                 context.map().centerEase(loc);
39106                 that.selectImage(context, node.key, true);
39107               }
39108
39109               dispatch$4.call('nodeChanged');
39110             }
39111
39112             function bearingChanged(e) {
39113               dispatch$4.call('bearingChanged', undefined, e);
39114             }
39115           },
39116           // Pass in the image key string as `imageKey`.
39117           // This allows images to be selected from places that dont have access
39118           // to the full image datum (like the street signs layer or the js viewer)
39119           selectImage: function selectImage(context, imageKey, fromViewer) {
39120             _mlySelectedImageKey = imageKey;
39121             this.updateUrlImage(imageKey);
39122             var d = _mlyCache.images.forImageKey[imageKey];
39123             var viewer = context.container().select('.photoviewer');
39124             if (!viewer.empty()) viewer.datum(d);
39125             imageKey = d && d.key || imageKey;
39126
39127             if (!fromViewer && imageKey) {
39128               _mlyClicks.push(imageKey);
39129             }
39130
39131             this.setStyles(context, null, true);
39132
39133             if (_mlyShowFeatureDetections) {
39134               this.updateDetections(imageKey, apibase + 'image_detections?layers=points&values=' + mapFeatureConfig.values + '&image_keys=' + imageKey);
39135             }
39136
39137             if (_mlyShowSignDetections) {
39138               this.updateDetections(imageKey, apibase + 'image_detections?layers=trafficsigns&image_keys=' + imageKey);
39139             }
39140
39141             if (_mlyViewer && imageKey) {
39142               _mlyViewer.moveToKey(imageKey)["catch"](function (e) {
39143                 console.error('mly3', e);
39144               }); // eslint-disable-line no-console
39145
39146             }
39147
39148             return this;
39149           },
39150           getActiveImage: function getActiveImage() {
39151             return _mlyActiveImage;
39152           },
39153           getSelectedImageKey: function getSelectedImageKey() {
39154             return _mlySelectedImageKey;
39155           },
39156           getSequenceKeyForImageKey: function getSequenceKeyForImageKey(imageKey) {
39157             return _mlyCache.sequences.forImageKey[imageKey];
39158           },
39159           setActiveImage: function setActiveImage(node) {
39160             if (node) {
39161               _mlyActiveImage = {
39162                 ca: node.originalCA,
39163                 key: node.key,
39164                 loc: [node.originalLatLon.lon, node.originalLatLon.lat],
39165                 pano: node.pano
39166               };
39167             } else {
39168               _mlyActiveImage = null;
39169             }
39170           },
39171           // Updates the currently highlighted sequence and selected bubble.
39172           // Reset is only necessary when interacting with the viewport because
39173           // this implicitly changes the currently selected bubble/sequence
39174           setStyles: function setStyles(context, hovered, reset) {
39175             if (reset) {
39176               // reset all layers
39177               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false);
39178               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
39179             }
39180
39181             var hoveredImageKey = hovered && hovered.key;
39182             var hoveredSequenceKey = hoveredImageKey && this.getSequenceKeyForImageKey(hoveredImageKey);
39183             var hoveredLineString = hoveredSequenceKey && _mlyCache.sequences.lineString[hoveredSequenceKey];
39184             var hoveredImageKeys = hoveredLineString && hoveredLineString.properties.coordinateProperties.image_keys || [];
39185             var selectedImageKey = _mlySelectedImageKey;
39186             var selectedSequenceKey = selectedImageKey && this.getSequenceKeyForImageKey(selectedImageKey);
39187             var selectedLineString = selectedSequenceKey && _mlyCache.sequences.lineString[selectedSequenceKey];
39188             var selectedImageKeys = selectedLineString && selectedLineString.properties.coordinateProperties.image_keys || []; // highlight sibling viewfields on either the selected or the hovered sequences
39189
39190             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
39191             context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
39192               return highlightedImageKeys.indexOf(d.key) !== -1;
39193             }).classed('hovered', function (d) {
39194               return d.key === hoveredImageKey;
39195             });
39196             context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
39197               return d.properties.key === hoveredSequenceKey;
39198             }).classed('currentView', function (d) {
39199               return d.properties.key === selectedSequenceKey;
39200             }); // update viewfields if needed
39201
39202             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
39203
39204             function viewfieldPath() {
39205               var d = this.parentNode.__data__;
39206
39207               if (d.pano && d.key !== selectedImageKey) {
39208                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
39209               } else {
39210                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
39211               }
39212             }
39213
39214             return this;
39215           },
39216           updateDetections: function updateDetections(imageKey, url) {
39217             if (!_mlyViewer || _mlyFallback) return;
39218             if (!imageKey) return;
39219
39220             if (!_mlyCache.image_detections.forImageKey[imageKey]) {
39221               loadData('image_detections', url).then(function () {
39222                 showDetections(_mlyCache.image_detections.forImageKey[imageKey] || []);
39223               });
39224             } else {
39225               showDetections(_mlyCache.image_detections.forImageKey[imageKey]);
39226             }
39227
39228             function showDetections(detections) {
39229               detections.forEach(function (data) {
39230                 var tag = makeTag(data);
39231
39232                 if (tag) {
39233                   var tagComponent = _mlyViewer.getComponent('tag');
39234
39235                   tagComponent.add([tag]);
39236                 }
39237               });
39238             }
39239
39240             function makeTag(data) {
39241               var valueParts = data.value.split('--');
39242               if (!valueParts.length) return;
39243               var tag;
39244               var text;
39245               var color = 0xffffff;
39246
39247               if (_mlyHighlightedDetection === data.key) {
39248                 color = 0xffff00;
39249                 text = valueParts[1];
39250
39251                 if (text === 'flat' || text === 'discrete' || text === 'sign') {
39252                   text = valueParts[2];
39253                 }
39254
39255                 text = text.replace(/-/g, ' ');
39256                 text = text.charAt(0).toUpperCase() + text.slice(1);
39257                 _mlyHighlightedDetection = null;
39258               }
39259
39260               if (data.shape.type === 'Polygon') {
39261                 var polygonGeometry = new Mapillary.TagComponent.PolygonGeometry(data.shape.coordinates[0]);
39262                 tag = new Mapillary.TagComponent.OutlineTag(data.key, polygonGeometry, {
39263                   text: text,
39264                   textColor: color,
39265                   lineColor: color,
39266                   lineWidth: 2,
39267                   fillColor: color,
39268                   fillOpacity: 0.3
39269                 });
39270               } else if (data.shape.type === 'Point') {
39271                 var pointGeometry = new Mapillary.TagComponent.PointGeometry(data.shape.coordinates[0]);
39272                 tag = new Mapillary.TagComponent.SpotTag(data.key, pointGeometry, {
39273                   text: text,
39274                   color: color,
39275                   textColor: color
39276                 });
39277               }
39278
39279               return tag;
39280             }
39281           },
39282           cache: function cache() {
39283             return _mlyCache;
39284           }
39285         };
39286
39287         function validationIssue(attrs) {
39288           this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
39289
39290           this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
39291
39292           this.severity = attrs.severity; // required - 'warning' or 'error'
39293
39294           this.message = attrs.message; // required - function returning localized string
39295
39296           this.reference = attrs.reference; // optional - function(selection) to render reference information
39297
39298           this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
39299
39300           this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
39301
39302           this.data = attrs.data; // optional - object containing extra data for the fixes
39303
39304           this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
39305
39306           this.hash = attrs.hash; // optional - string to further differentiate the issue
39307
39308           this.id = generateID.apply(this); // generated - see below
39309
39310           this.autoFix = null; // generated - if autofix exists, will be set below
39311           // A unique, deterministic string hash.
39312           // Issues with identical id values are considered identical.
39313
39314           function generateID() {
39315             var parts = [this.type];
39316
39317             if (this.hash) {
39318               // subclasses can pass in their own differentiator
39319               parts.push(this.hash);
39320             }
39321
39322             if (this.subtype) {
39323               parts.push(this.subtype);
39324             } // include the entities this issue is for
39325             // (sort them so the id is deterministic)
39326
39327
39328             if (this.entityIds) {
39329               var entityKeys = this.entityIds.slice().sort();
39330               parts.push.apply(parts, entityKeys);
39331             }
39332
39333             return parts.join(':');
39334           }
39335
39336           this.extent = function (resolver) {
39337             if (this.loc) {
39338               return geoExtent(this.loc);
39339             }
39340
39341             if (this.entityIds && this.entityIds.length) {
39342               return this.entityIds.reduce(function (extent, entityId) {
39343                 return extent.extend(resolver.entity(entityId).extent(resolver));
39344               }, geoExtent());
39345             }
39346
39347             return null;
39348           };
39349
39350           this.fixes = function (context) {
39351             var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
39352             var issue = this;
39353
39354             if (issue.severity === 'warning') {
39355               // allow ignoring any issue that's not an error
39356               fixes.push(new validationIssueFix({
39357                 title: _t.html('issues.fix.ignore_issue.title'),
39358                 icon: 'iD-icon-close',
39359                 onClick: function onClick() {
39360                   context.validator().ignoreIssue(this.issue.id);
39361                 }
39362               }));
39363             }
39364
39365             fixes.forEach(function (fix) {
39366               // the id doesn't matter as long as it's unique to this issue/fix
39367               fix.id = fix.title; // add a reference to the issue for use in actions
39368
39369               fix.issue = issue;
39370
39371               if (fix.autoArgs) {
39372                 issue.autoFix = fix;
39373               }
39374             });
39375             return fixes;
39376           };
39377         }
39378         function validationIssueFix(attrs) {
39379           this.title = attrs.title; // Required
39380
39381           this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
39382
39383           this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
39384
39385           this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
39386
39387           this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
39388
39389           this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
39390
39391           this.issue = null; // Generated link - added by validationIssue
39392         }
39393
39394         var buildRuleChecks = function buildRuleChecks() {
39395           return {
39396             equals: function equals(_equals) {
39397               return function (tags) {
39398                 return Object.keys(_equals).every(function (k) {
39399                   return _equals[k] === tags[k];
39400                 });
39401               };
39402             },
39403             notEquals: function notEquals(_notEquals) {
39404               return function (tags) {
39405                 return Object.keys(_notEquals).some(function (k) {
39406                   return _notEquals[k] !== tags[k];
39407                 });
39408               };
39409             },
39410             absence: function absence(_absence) {
39411               return function (tags) {
39412                 return Object.keys(tags).indexOf(_absence) === -1;
39413               };
39414             },
39415             presence: function presence(_presence) {
39416               return function (tags) {
39417                 return Object.keys(tags).indexOf(_presence) > -1;
39418               };
39419             },
39420             greaterThan: function greaterThan(_greaterThan) {
39421               var key = Object.keys(_greaterThan)[0];
39422               var value = _greaterThan[key];
39423               return function (tags) {
39424                 return tags[key] > value;
39425               };
39426             },
39427             greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
39428               var key = Object.keys(_greaterThanEqual)[0];
39429               var value = _greaterThanEqual[key];
39430               return function (tags) {
39431                 return tags[key] >= value;
39432               };
39433             },
39434             lessThan: function lessThan(_lessThan) {
39435               var key = Object.keys(_lessThan)[0];
39436               var value = _lessThan[key];
39437               return function (tags) {
39438                 return tags[key] < value;
39439               };
39440             },
39441             lessThanEqual: function lessThanEqual(_lessThanEqual) {
39442               var key = Object.keys(_lessThanEqual)[0];
39443               var value = _lessThanEqual[key];
39444               return function (tags) {
39445                 return tags[key] <= value;
39446               };
39447             },
39448             positiveRegex: function positiveRegex(_positiveRegex) {
39449               var tagKey = Object.keys(_positiveRegex)[0];
39450
39451               var expression = _positiveRegex[tagKey].join('|');
39452
39453               var regex = new RegExp(expression);
39454               return function (tags) {
39455                 return regex.test(tags[tagKey]);
39456               };
39457             },
39458             negativeRegex: function negativeRegex(_negativeRegex) {
39459               var tagKey = Object.keys(_negativeRegex)[0];
39460
39461               var expression = _negativeRegex[tagKey].join('|');
39462
39463               var regex = new RegExp(expression);
39464               return function (tags) {
39465                 return !regex.test(tags[tagKey]);
39466               };
39467             }
39468           };
39469         };
39470
39471         var buildLineKeys = function buildLineKeys() {
39472           return {
39473             highway: {
39474               rest_area: true,
39475               services: true
39476             },
39477             railway: {
39478               roundhouse: true,
39479               station: true,
39480               traverser: true,
39481               turntable: true,
39482               wash: true
39483             }
39484           };
39485         };
39486
39487         var serviceMapRules = {
39488           init: function init() {
39489             this._ruleChecks = buildRuleChecks();
39490             this._validationRules = [];
39491             this._areaKeys = osmAreaKeys;
39492             this._lineKeys = buildLineKeys();
39493           },
39494           // list of rules only relevant to tag checks...
39495           filterRuleChecks: function filterRuleChecks(selector) {
39496             var _ruleChecks = this._ruleChecks;
39497             return Object.keys(selector).reduce(function (rules, key) {
39498               if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
39499                 rules.push(_ruleChecks[key](selector[key]));
39500               }
39501
39502               return rules;
39503             }, []);
39504           },
39505           // builds tagMap from mapcss-parse selector object...
39506           buildTagMap: function buildTagMap(selector) {
39507             var getRegexValues = function getRegexValues(regexes) {
39508               return regexes.map(function (regex) {
39509                 return regex.replace(/\$|\^/g, '');
39510               });
39511             };
39512
39513             var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
39514               var values;
39515               var isRegex = /regex/gi.test(key);
39516               var isEqual = /equals/gi.test(key);
39517
39518               if (isRegex || isEqual) {
39519                 Object.keys(selector[key]).forEach(function (selectorKey) {
39520                   values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
39521
39522                   if (expectedTags.hasOwnProperty(selectorKey)) {
39523                     values = values.concat(expectedTags[selectorKey]);
39524                   }
39525
39526                   expectedTags[selectorKey] = values;
39527                 });
39528               } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
39529                 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
39530                 values = [selector[key][tagKey]];
39531
39532                 if (expectedTags.hasOwnProperty(tagKey)) {
39533                   values = values.concat(expectedTags[tagKey]);
39534                 }
39535
39536                 expectedTags[tagKey] = values;
39537               }
39538
39539               return expectedTags;
39540             }, {});
39541             return tagMap;
39542           },
39543           // inspired by osmWay#isArea()
39544           inferGeometry: function inferGeometry(tagMap) {
39545             var _lineKeys = this._lineKeys;
39546             var _areaKeys = this._areaKeys;
39547
39548             var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
39549               return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
39550             };
39551
39552             var keyValueImpliesLine = function keyValueImpliesLine(key) {
39553               return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
39554             };
39555
39556             if (tagMap.hasOwnProperty('area')) {
39557               if (tagMap.area.indexOf('yes') > -1) {
39558                 return 'area';
39559               }
39560
39561               if (tagMap.area.indexOf('no') > -1) {
39562                 return 'line';
39563               }
39564             }
39565
39566             for (var key in tagMap) {
39567               if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
39568                 return 'area';
39569               }
39570
39571               if (key in _lineKeys && keyValueImpliesLine(key)) {
39572                 return 'area';
39573               }
39574             }
39575
39576             return 'line';
39577           },
39578           // adds from mapcss-parse selector check...
39579           addRule: function addRule(selector) {
39580             var rule = {
39581               // checks relevant to mapcss-selector
39582               checks: this.filterRuleChecks(selector),
39583               // true if all conditions for a tag error are true..
39584               matches: function matches(entity) {
39585                 return this.checks.every(function (check) {
39586                   return check(entity.tags);
39587                 });
39588               },
39589               // borrowed from Way#isArea()
39590               inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
39591               geometryMatches: function geometryMatches(entity, graph) {
39592                 if (entity.type === 'node' || entity.type === 'relation') {
39593                   return selector.geometry === entity.type;
39594                 } else if (entity.type === 'way') {
39595                   return this.inferredGeometry === entity.geometry(graph);
39596                 }
39597               },
39598               // when geometries match and tag matches are present, return a warning...
39599               findIssues: function findIssues(entity, graph, issues) {
39600                 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
39601                   var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
39602                   var _message = selector[severity];
39603                   issues.push(new validationIssue({
39604                     type: 'maprules',
39605                     severity: severity,
39606                     message: function message() {
39607                       return _message;
39608                     },
39609                     entityIds: [entity.id]
39610                   }));
39611                 }
39612               }
39613             };
39614
39615             this._validationRules.push(rule);
39616           },
39617           clearRules: function clearRules() {
39618             this._validationRules = [];
39619           },
39620           // returns validationRules...
39621           validationRules: function validationRules() {
39622             return this._validationRules;
39623           },
39624           // returns ruleChecks
39625           ruleChecks: function ruleChecks() {
39626             return this._ruleChecks;
39627           }
39628         };
39629
39630         var apibase$1 = 'https://nominatim.openstreetmap.org/';
39631         var _inflight = {};
39632
39633         var _nominatimCache;
39634
39635         var serviceNominatim = {
39636           init: function init() {
39637             _inflight = {};
39638             _nominatimCache = new RBush();
39639           },
39640           reset: function reset() {
39641             Object.values(_inflight).forEach(function (controller) {
39642               controller.abort();
39643             });
39644             _inflight = {};
39645             _nominatimCache = new RBush();
39646           },
39647           countryCode: function countryCode(location, callback) {
39648             this.reverse(location, function (err, result) {
39649               if (err) {
39650                 return callback(err);
39651               } else if (result.address) {
39652                 return callback(null, result.address.country_code);
39653               } else {
39654                 return callback('Unable to geocode', null);
39655               }
39656             });
39657           },
39658           reverse: function reverse(loc, callback) {
39659             var cached = _nominatimCache.search({
39660               minX: loc[0],
39661               minY: loc[1],
39662               maxX: loc[0],
39663               maxY: loc[1]
39664             });
39665
39666             if (cached.length > 0) {
39667               if (callback) callback(null, cached[0].data);
39668               return;
39669             }
39670
39671             var params = {
39672               zoom: 13,
39673               format: 'json',
39674               addressdetails: 1,
39675               lat: loc[1],
39676               lon: loc[0]
39677             };
39678             var url = apibase$1 + 'reverse?' + utilQsString(params);
39679             if (_inflight[url]) return;
39680             var controller = new AbortController();
39681             _inflight[url] = controller;
39682             d3_json(url, {
39683               signal: controller.signal
39684             }).then(function (result) {
39685               delete _inflight[url];
39686
39687               if (result && result.error) {
39688                 throw new Error(result.error);
39689               }
39690
39691               var extent = geoExtent(loc).padByMeters(200);
39692
39693               _nominatimCache.insert(Object.assign(extent.bbox(), {
39694                 data: result
39695               }));
39696
39697               if (callback) callback(null, result);
39698             })["catch"](function (err) {
39699               delete _inflight[url];
39700               if (err.name === 'AbortError') return;
39701               if (callback) callback(err.message);
39702             });
39703           },
39704           search: function search(val, callback) {
39705             var searchVal = encodeURIComponent(val);
39706             var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
39707             if (_inflight[url]) return;
39708             var controller = new AbortController();
39709             _inflight[url] = controller;
39710             d3_json(url, {
39711               signal: controller.signal
39712             }).then(function (result) {
39713               delete _inflight[url];
39714
39715               if (result && result.error) {
39716                 throw new Error(result.error);
39717               }
39718
39719               if (callback) callback(null, result);
39720             })["catch"](function (err) {
39721               delete _inflight[url];
39722               if (err.name === 'AbortError') return;
39723               if (callback) callback(err.message);
39724             });
39725           }
39726         };
39727
39728         var apibase$2 = 'https://openstreetcam.org';
39729         var maxResults$1 = 1000;
39730         var tileZoom$1 = 14;
39731         var tiler$4 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
39732         var dispatch$5 = dispatch('loadedImages');
39733         var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
39734
39735         var _oscCache;
39736
39737         var _oscSelectedImage;
39738
39739         var _loadViewerPromise$1;
39740
39741         function abortRequest$4(controller) {
39742           controller.abort();
39743         }
39744
39745         function maxPageAtZoom$1(z) {
39746           if (z < 15) return 2;
39747           if (z === 15) return 5;
39748           if (z === 16) return 10;
39749           if (z === 17) return 20;
39750           if (z === 18) return 40;
39751           if (z > 18) return 80;
39752         }
39753
39754         function loadTiles$1(which, url, projection) {
39755           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
39756           var tiles = tiler$4.getTiles(projection); // abort inflight requests that are no longer needed
39757
39758           var cache = _oscCache[which];
39759           Object.keys(cache.inflight).forEach(function (k) {
39760             var wanted = tiles.find(function (tile) {
39761               return k.indexOf(tile.id + ',') === 0;
39762             });
39763
39764             if (!wanted) {
39765               abortRequest$4(cache.inflight[k]);
39766               delete cache.inflight[k];
39767             }
39768           });
39769           tiles.forEach(function (tile) {
39770             loadNextTilePage$1(which, currZoom, url, tile);
39771           });
39772         }
39773
39774         function loadNextTilePage$1(which, currZoom, url, tile) {
39775           var cache = _oscCache[which];
39776           var bbox = tile.extent.bbox();
39777           var maxPages = maxPageAtZoom$1(currZoom);
39778           var nextPage = cache.nextPage[tile.id] || 1;
39779           var params = utilQsString({
39780             ipp: maxResults$1,
39781             page: nextPage,
39782             // client_id: clientId,
39783             bbTopLeft: [bbox.maxY, bbox.minX].join(','),
39784             bbBottomRight: [bbox.minY, bbox.maxX].join(',')
39785           }, true);
39786           if (nextPage > maxPages) return;
39787           var id = tile.id + ',' + String(nextPage);
39788           if (cache.loaded[id] || cache.inflight[id]) return;
39789           var controller = new AbortController();
39790           cache.inflight[id] = controller;
39791           var options = {
39792             method: 'POST',
39793             signal: controller.signal,
39794             body: params,
39795             headers: {
39796               'Content-Type': 'application/x-www-form-urlencoded'
39797             }
39798           };
39799           d3_json(url, options).then(function (data) {
39800             cache.loaded[id] = true;
39801             delete cache.inflight[id];
39802
39803             if (!data || !data.currentPageItems || !data.currentPageItems.length) {
39804               throw new Error('No Data');
39805             }
39806
39807             var features = data.currentPageItems.map(function (item) {
39808               var loc = [+item.lng, +item.lat];
39809               var d;
39810
39811               if (which === 'images') {
39812                 d = {
39813                   loc: loc,
39814                   key: item.id,
39815                   ca: +item.heading,
39816                   captured_at: item.shot_date || item.date_added,
39817                   captured_by: item.username,
39818                   imagePath: item.lth_name,
39819                   sequence_id: item.sequence_id,
39820                   sequence_index: +item.sequence_index
39821                 }; // cache sequence info
39822
39823                 var seq = _oscCache.sequences[d.sequence_id];
39824
39825                 if (!seq) {
39826                   seq = {
39827                     rotation: 0,
39828                     images: []
39829                   };
39830                   _oscCache.sequences[d.sequence_id] = seq;
39831                 }
39832
39833                 seq.images[d.sequence_index] = d;
39834                 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
39835               }
39836
39837               return {
39838                 minX: loc[0],
39839                 minY: loc[1],
39840                 maxX: loc[0],
39841                 maxY: loc[1],
39842                 data: d
39843               };
39844             });
39845             cache.rtree.load(features);
39846
39847             if (data.currentPageItems.length === maxResults$1) {
39848               // more pages to load
39849               cache.nextPage[tile.id] = nextPage + 1;
39850               loadNextTilePage$1(which, currZoom, url, tile);
39851             } else {
39852               cache.nextPage[tile.id] = Infinity; // no more pages to load
39853             }
39854
39855             if (which === 'images') {
39856               dispatch$5.call('loadedImages');
39857             }
39858           })["catch"](function () {
39859             cache.loaded[id] = true;
39860             delete cache.inflight[id];
39861           });
39862         } // partition viewport into higher zoom tiles
39863
39864
39865         function partitionViewport$1(projection) {
39866           var z = geoScaleToZoom(projection.scale());
39867           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
39868
39869           var tiler = utilTiler().zoomExtent([z2, z2]);
39870           return tiler.getTiles(projection).map(function (tile) {
39871             return tile.extent;
39872           });
39873         } // no more than `limit` results per partition.
39874
39875
39876         function searchLimited$1(limit, projection, rtree) {
39877           limit = limit || 5;
39878           return partitionViewport$1(projection).reduce(function (result, extent) {
39879             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
39880               return d.data;
39881             });
39882             return found.length ? result.concat(found) : result;
39883           }, []);
39884         }
39885
39886         var serviceOpenstreetcam = {
39887           init: function init() {
39888             if (!_oscCache) {
39889               this.reset();
39890             }
39891
39892             this.event = utilRebind(this, dispatch$5, 'on');
39893           },
39894           reset: function reset() {
39895             if (_oscCache) {
39896               Object.values(_oscCache.images.inflight).forEach(abortRequest$4);
39897             }
39898
39899             _oscCache = {
39900               images: {
39901                 inflight: {},
39902                 loaded: {},
39903                 nextPage: {},
39904                 rtree: new RBush(),
39905                 forImageKey: {}
39906               },
39907               sequences: {}
39908             };
39909             _oscSelectedImage = null;
39910           },
39911           images: function images(projection) {
39912             var limit = 5;
39913             return searchLimited$1(limit, projection, _oscCache.images.rtree);
39914           },
39915           sequences: function sequences(projection) {
39916             var viewport = projection.clipExtent();
39917             var min = [viewport[0][0], viewport[1][1]];
39918             var max = [viewport[1][0], viewport[0][1]];
39919             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
39920             var sequenceKeys = {}; // all sequences for images in viewport
39921
39922             _oscCache.images.rtree.search(bbox).forEach(function (d) {
39923               sequenceKeys[d.data.sequence_id] = true;
39924             }); // make linestrings from those sequences
39925
39926
39927             var lineStrings = [];
39928             Object.keys(sequenceKeys).forEach(function (sequenceKey) {
39929               var seq = _oscCache.sequences[sequenceKey];
39930               var images = seq && seq.images;
39931
39932               if (images) {
39933                 lineStrings.push({
39934                   type: 'LineString',
39935                   coordinates: images.map(function (d) {
39936                     return d.loc;
39937                   }).filter(Boolean),
39938                   properties: {
39939                     captured_at: images[0] ? images[0].captured_at : null,
39940                     captured_by: images[0] ? images[0].captured_by : null,
39941                     key: sequenceKey
39942                   }
39943                 });
39944               }
39945             });
39946             return lineStrings;
39947           },
39948           cachedImage: function cachedImage(imageKey) {
39949             return _oscCache.images.forImageKey[imageKey];
39950           },
39951           loadImages: function loadImages(projection) {
39952             var url = apibase$2 + '/1.0/list/nearby-photos/';
39953             loadTiles$1('images', url, projection);
39954           },
39955           ensureViewerLoaded: function ensureViewerLoaded(context) {
39956             if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
39957
39958             var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
39959             var that = this;
39960             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
39961             wrapEnter.append('div').attr('class', 'photo-attribution fillD');
39962             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
39963             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
39964             controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
39965             controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
39966             controlsEnter.append('button').on('click.forward', step(1)).html('►');
39967             wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
39968
39969             context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
39970               imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
39971             });
39972
39973             function zoomPan(d3_event) {
39974               var t = d3_event.transform;
39975               context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
39976             }
39977
39978             function rotate(deg) {
39979               return function () {
39980                 if (!_oscSelectedImage) return;
39981                 var sequenceKey = _oscSelectedImage.sequence_id;
39982                 var sequence = _oscCache.sequences[sequenceKey];
39983                 if (!sequence) return;
39984                 var r = sequence.rotation || 0;
39985                 r += deg;
39986                 if (r > 180) r -= 360;
39987                 if (r < -180) r += 360;
39988                 sequence.rotation = r;
39989                 var wrap = context.container().select('.photoviewer .osc-wrapper');
39990                 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
39991                 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
39992               };
39993             }
39994
39995             function step(stepBy) {
39996               return function () {
39997                 if (!_oscSelectedImage) return;
39998                 var sequenceKey = _oscSelectedImage.sequence_id;
39999                 var sequence = _oscCache.sequences[sequenceKey];
40000                 if (!sequence) return;
40001                 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
40002                 var nextImage = sequence.images[nextIndex];
40003                 if (!nextImage) return;
40004                 context.map().centerEase(nextImage.loc);
40005                 that.selectImage(context, nextImage.key);
40006               };
40007             } // don't need any async loading so resolve immediately
40008
40009
40010             _loadViewerPromise$1 = Promise.resolve();
40011             return _loadViewerPromise$1;
40012           },
40013           showViewer: function showViewer(context) {
40014             var viewer = context.container().select('.photoviewer').classed('hide', false);
40015             var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
40016
40017             if (isHidden) {
40018               viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
40019               viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
40020             }
40021
40022             return this;
40023           },
40024           hideViewer: function hideViewer(context) {
40025             _oscSelectedImage = null;
40026             this.updateUrlImage(null);
40027             var viewer = context.container().select('.photoviewer');
40028             if (!viewer.empty()) viewer.datum(null);
40029             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
40030             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
40031             return this.setStyles(context, null, true);
40032           },
40033           selectImage: function selectImage(context, imageKey) {
40034             var d = this.cachedImage(imageKey);
40035             _oscSelectedImage = d;
40036             this.updateUrlImage(imageKey);
40037             var viewer = context.container().select('.photoviewer');
40038             if (!viewer.empty()) viewer.datum(d);
40039             this.setStyles(context, null, true);
40040             context.container().selectAll('.icon-sign').classed('currentView', false);
40041             if (!d) return this;
40042             var wrap = context.container().select('.photoviewer .osc-wrapper');
40043             var imageWrap = wrap.selectAll('.osc-image-wrap');
40044             var attribution = wrap.selectAll('.photo-attribution').html('');
40045             wrap.transition().duration(100).call(imgZoom.transform, identity$2);
40046             imageWrap.selectAll('.osc-image').remove();
40047
40048             if (d) {
40049               var sequence = _oscCache.sequences[d.sequence_id];
40050               var r = sequence && sequence.rotation || 0;
40051               imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$2 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
40052
40053               if (d.captured_by) {
40054                 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
40055                 attribution.append('span').html('|');
40056               }
40057
40058               if (d.captured_at) {
40059                 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
40060                 attribution.append('span').html('|');
40061               }
40062
40063               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');
40064             }
40065
40066             return this;
40067
40068             function localeDateString(s) {
40069               if (!s) return null;
40070               var options = {
40071                 day: 'numeric',
40072                 month: 'short',
40073                 year: 'numeric'
40074               };
40075               var d = new Date(s);
40076               if (isNaN(d.getTime())) return null;
40077               return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
40078             }
40079           },
40080           getSelectedImage: function getSelectedImage() {
40081             return _oscSelectedImage;
40082           },
40083           getSequenceKeyForImage: function getSequenceKeyForImage(d) {
40084             return d && d.sequence_id;
40085           },
40086           // Updates the currently highlighted sequence and selected bubble.
40087           // Reset is only necessary when interacting with the viewport because
40088           // this implicitly changes the currently selected bubble/sequence
40089           setStyles: function setStyles(context, hovered, reset) {
40090             if (reset) {
40091               // reset all layers
40092               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
40093               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
40094             }
40095
40096             var hoveredImageKey = hovered && hovered.key;
40097             var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
40098             var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
40099             var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
40100               return d.key;
40101             }) || [];
40102             var viewer = context.container().select('.photoviewer');
40103             var selected = viewer.empty() ? undefined : viewer.datum();
40104             var selectedImageKey = selected && selected.key;
40105             var selectedSequenceKey = this.getSequenceKeyForImage(selected);
40106             var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
40107             var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
40108               return d.key;
40109             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
40110
40111             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
40112             context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
40113               return highlightedImageKeys.indexOf(d.key) !== -1;
40114             }).classed('hovered', function (d) {
40115               return d.key === hoveredImageKey;
40116             }).classed('currentView', function (d) {
40117               return d.key === selectedImageKey;
40118             });
40119             context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
40120               return d.properties.key === hoveredSequenceKey;
40121             }).classed('currentView', function (d) {
40122               return d.properties.key === selectedSequenceKey;
40123             }); // update viewfields if needed
40124
40125             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
40126
40127             function viewfieldPath() {
40128               var d = this.parentNode.__data__;
40129
40130               if (d.pano && d.key !== selectedImageKey) {
40131                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
40132               } else {
40133                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
40134               }
40135             }
40136
40137             return this;
40138           },
40139           updateUrlImage: function updateUrlImage(imageKey) {
40140             if (!window.mocha) {
40141               var hash = utilStringQs(window.location.hash);
40142
40143               if (imageKey) {
40144                 hash.photo = 'openstreetcam/' + imageKey;
40145               } else {
40146                 delete hash.photo;
40147               }
40148
40149               window.location.replace('#' + utilQsString(hash, true));
40150             }
40151           },
40152           cache: function cache() {
40153             return _oscCache;
40154           }
40155         };
40156
40157         var FORCED$f = fails(function () {
40158           return new Date(NaN).toJSON() !== null
40159             || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
40160         });
40161
40162         // `Date.prototype.toJSON` method
40163         // https://tc39.es/ecma262/#sec-date.prototype.tojson
40164         _export({ target: 'Date', proto: true, forced: FORCED$f }, {
40165           // eslint-disable-next-line no-unused-vars -- required for `.length`
40166           toJSON: function toJSON(key) {
40167             var O = toObject(this);
40168             var pv = toPrimitive(O);
40169             return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
40170           }
40171         });
40172
40173         // `URL.prototype.toJSON` method
40174         // https://url.spec.whatwg.org/#dom-url-tojson
40175         _export({ target: 'URL', proto: true, enumerable: true }, {
40176           toJSON: function toJSON() {
40177             return URL.prototype.toString.call(this);
40178           }
40179         });
40180
40181         /**
40182          * Checks if `value` is the
40183          * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
40184          * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
40185          *
40186          * @static
40187          * @memberOf _
40188          * @since 0.1.0
40189          * @category Lang
40190          * @param {*} value The value to check.
40191          * @returns {boolean} Returns `true` if `value` is an object, else `false`.
40192          * @example
40193          *
40194          * _.isObject({});
40195          * // => true
40196          *
40197          * _.isObject([1, 2, 3]);
40198          * // => true
40199          *
40200          * _.isObject(_.noop);
40201          * // => true
40202          *
40203          * _.isObject(null);
40204          * // => false
40205          */
40206         function isObject$1(value) {
40207           var type = _typeof(value);
40208
40209           return value != null && (type == 'object' || type == 'function');
40210         }
40211
40212         /** Detect free variable `global` from Node.js. */
40213         var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
40214
40215         /** Detect free variable `self`. */
40216
40217         var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
40218         /** Used as a reference to the global object. */
40219
40220         var root$1 = freeGlobal || freeSelf || Function('return this')();
40221
40222         /**
40223          * Gets the timestamp of the number of milliseconds that have elapsed since
40224          * the Unix epoch (1 January 1970 00:00:00 UTC).
40225          *
40226          * @static
40227          * @memberOf _
40228          * @since 2.4.0
40229          * @category Date
40230          * @returns {number} Returns the timestamp.
40231          * @example
40232          *
40233          * _.defer(function(stamp) {
40234          *   console.log(_.now() - stamp);
40235          * }, _.now());
40236          * // => Logs the number of milliseconds it took for the deferred invocation.
40237          */
40238
40239         var now$1 = function now() {
40240           return root$1.Date.now();
40241         };
40242
40243         /** Used to match a single whitespace character. */
40244         var reWhitespace = /\s/;
40245         /**
40246          * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
40247          * character of `string`.
40248          *
40249          * @private
40250          * @param {string} string The string to inspect.
40251          * @returns {number} Returns the index of the last non-whitespace character.
40252          */
40253
40254         function trimmedEndIndex(string) {
40255           var index = string.length;
40256
40257           while (index-- && reWhitespace.test(string.charAt(index))) {}
40258
40259           return index;
40260         }
40261
40262         /** Used to match leading whitespace. */
40263
40264         var reTrimStart = /^\s+/;
40265         /**
40266          * The base implementation of `_.trim`.
40267          *
40268          * @private
40269          * @param {string} string The string to trim.
40270          * @returns {string} Returns the trimmed string.
40271          */
40272
40273         function baseTrim(string) {
40274           return string ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') : string;
40275         }
40276
40277         /** Built-in value references. */
40278
40279         var _Symbol = root$1.Symbol;
40280
40281         /** Used for built-in method references. */
40282
40283         var objectProto = Object.prototype;
40284         /** Used to check objects for own properties. */
40285
40286         var hasOwnProperty$1 = objectProto.hasOwnProperty;
40287         /**
40288          * Used to resolve the
40289          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40290          * of values.
40291          */
40292
40293         var nativeObjectToString = objectProto.toString;
40294         /** Built-in value references. */
40295
40296         var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
40297         /**
40298          * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
40299          *
40300          * @private
40301          * @param {*} value The value to query.
40302          * @returns {string} Returns the raw `toStringTag`.
40303          */
40304
40305         function getRawTag(value) {
40306           var isOwn = hasOwnProperty$1.call(value, symToStringTag),
40307               tag = value[symToStringTag];
40308
40309           try {
40310             value[symToStringTag] = undefined;
40311             var unmasked = true;
40312           } catch (e) {}
40313
40314           var result = nativeObjectToString.call(value);
40315
40316           if (unmasked) {
40317             if (isOwn) {
40318               value[symToStringTag] = tag;
40319             } else {
40320               delete value[symToStringTag];
40321             }
40322           }
40323
40324           return result;
40325         }
40326
40327         /** Used for built-in method references. */
40328         var objectProto$1 = Object.prototype;
40329         /**
40330          * Used to resolve the
40331          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40332          * of values.
40333          */
40334
40335         var nativeObjectToString$1 = objectProto$1.toString;
40336         /**
40337          * Converts `value` to a string using `Object.prototype.toString`.
40338          *
40339          * @private
40340          * @param {*} value The value to convert.
40341          * @returns {string} Returns the converted string.
40342          */
40343
40344         function objectToString$1(value) {
40345           return nativeObjectToString$1.call(value);
40346         }
40347
40348         /** `Object#toString` result references. */
40349
40350         var nullTag = '[object Null]',
40351             undefinedTag = '[object Undefined]';
40352         /** Built-in value references. */
40353
40354         var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
40355         /**
40356          * The base implementation of `getTag` without fallbacks for buggy environments.
40357          *
40358          * @private
40359          * @param {*} value The value to query.
40360          * @returns {string} Returns the `toStringTag`.
40361          */
40362
40363         function baseGetTag(value) {
40364           if (value == null) {
40365             return value === undefined ? undefinedTag : nullTag;
40366           }
40367
40368           return symToStringTag$1 && symToStringTag$1 in Object(value) ? getRawTag(value) : objectToString$1(value);
40369         }
40370
40371         /**
40372          * Checks if `value` is object-like. A value is object-like if it's not `null`
40373          * and has a `typeof` result of "object".
40374          *
40375          * @static
40376          * @memberOf _
40377          * @since 4.0.0
40378          * @category Lang
40379          * @param {*} value The value to check.
40380          * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
40381          * @example
40382          *
40383          * _.isObjectLike({});
40384          * // => true
40385          *
40386          * _.isObjectLike([1, 2, 3]);
40387          * // => true
40388          *
40389          * _.isObjectLike(_.noop);
40390          * // => false
40391          *
40392          * _.isObjectLike(null);
40393          * // => false
40394          */
40395         function isObjectLike(value) {
40396           return value != null && _typeof(value) == 'object';
40397         }
40398
40399         /** `Object#toString` result references. */
40400
40401         var symbolTag = '[object Symbol]';
40402         /**
40403          * Checks if `value` is classified as a `Symbol` primitive or object.
40404          *
40405          * @static
40406          * @memberOf _
40407          * @since 4.0.0
40408          * @category Lang
40409          * @param {*} value The value to check.
40410          * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
40411          * @example
40412          *
40413          * _.isSymbol(Symbol.iterator);
40414          * // => true
40415          *
40416          * _.isSymbol('abc');
40417          * // => false
40418          */
40419
40420         function isSymbol$1(value) {
40421           return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
40422         }
40423
40424         /** Used as references for various `Number` constants. */
40425
40426         var NAN = 0 / 0;
40427         /** Used to detect bad signed hexadecimal string values. */
40428
40429         var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
40430         /** Used to detect binary string values. */
40431
40432         var reIsBinary = /^0b[01]+$/i;
40433         /** Used to detect octal string values. */
40434
40435         var reIsOctal = /^0o[0-7]+$/i;
40436         /** Built-in method references without a dependency on `root`. */
40437
40438         var freeParseInt = parseInt;
40439         /**
40440          * Converts `value` to a number.
40441          *
40442          * @static
40443          * @memberOf _
40444          * @since 4.0.0
40445          * @category Lang
40446          * @param {*} value The value to process.
40447          * @returns {number} Returns the number.
40448          * @example
40449          *
40450          * _.toNumber(3.2);
40451          * // => 3.2
40452          *
40453          * _.toNumber(Number.MIN_VALUE);
40454          * // => 5e-324
40455          *
40456          * _.toNumber(Infinity);
40457          * // => Infinity
40458          *
40459          * _.toNumber('3.2');
40460          * // => 3.2
40461          */
40462
40463         function toNumber$1(value) {
40464           if (typeof value == 'number') {
40465             return value;
40466           }
40467
40468           if (isSymbol$1(value)) {
40469             return NAN;
40470           }
40471
40472           if (isObject$1(value)) {
40473             var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
40474             value = isObject$1(other) ? other + '' : other;
40475           }
40476
40477           if (typeof value != 'string') {
40478             return value === 0 ? value : +value;
40479           }
40480
40481           value = baseTrim(value);
40482           var isBinary = reIsBinary.test(value);
40483           return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
40484         }
40485
40486         /** Error message constants. */
40487
40488         var FUNC_ERROR_TEXT = 'Expected a function';
40489         /* Built-in method references for those with the same name as other `lodash` methods. */
40490
40491         var nativeMax = Math.max,
40492             nativeMin = Math.min;
40493         /**
40494          * Creates a debounced function that delays invoking `func` until after `wait`
40495          * milliseconds have elapsed since the last time the debounced function was
40496          * invoked. The debounced function comes with a `cancel` method to cancel
40497          * delayed `func` invocations and a `flush` method to immediately invoke them.
40498          * Provide `options` to indicate whether `func` should be invoked on the
40499          * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
40500          * with the last arguments provided to the debounced function. Subsequent
40501          * calls to the debounced function return the result of the last `func`
40502          * invocation.
40503          *
40504          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40505          * invoked on the trailing edge of the timeout only if the debounced function
40506          * is invoked more than once during the `wait` timeout.
40507          *
40508          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40509          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40510          *
40511          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40512          * for details over the differences between `_.debounce` and `_.throttle`.
40513          *
40514          * @static
40515          * @memberOf _
40516          * @since 0.1.0
40517          * @category Function
40518          * @param {Function} func The function to debounce.
40519          * @param {number} [wait=0] The number of milliseconds to delay.
40520          * @param {Object} [options={}] The options object.
40521          * @param {boolean} [options.leading=false]
40522          *  Specify invoking on the leading edge of the timeout.
40523          * @param {number} [options.maxWait]
40524          *  The maximum time `func` is allowed to be delayed before it's invoked.
40525          * @param {boolean} [options.trailing=true]
40526          *  Specify invoking on the trailing edge of the timeout.
40527          * @returns {Function} Returns the new debounced function.
40528          * @example
40529          *
40530          * // Avoid costly calculations while the window size is in flux.
40531          * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
40532          *
40533          * // Invoke `sendMail` when clicked, debouncing subsequent calls.
40534          * jQuery(element).on('click', _.debounce(sendMail, 300, {
40535          *   'leading': true,
40536          *   'trailing': false
40537          * }));
40538          *
40539          * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
40540          * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
40541          * var source = new EventSource('/stream');
40542          * jQuery(source).on('message', debounced);
40543          *
40544          * // Cancel the trailing debounced invocation.
40545          * jQuery(window).on('popstate', debounced.cancel);
40546          */
40547
40548         function debounce(func, wait, options) {
40549           var lastArgs,
40550               lastThis,
40551               maxWait,
40552               result,
40553               timerId,
40554               lastCallTime,
40555               lastInvokeTime = 0,
40556               leading = false,
40557               maxing = false,
40558               trailing = true;
40559
40560           if (typeof func != 'function') {
40561             throw new TypeError(FUNC_ERROR_TEXT);
40562           }
40563
40564           wait = toNumber$1(wait) || 0;
40565
40566           if (isObject$1(options)) {
40567             leading = !!options.leading;
40568             maxing = 'maxWait' in options;
40569             maxWait = maxing ? nativeMax(toNumber$1(options.maxWait) || 0, wait) : maxWait;
40570             trailing = 'trailing' in options ? !!options.trailing : trailing;
40571           }
40572
40573           function invokeFunc(time) {
40574             var args = lastArgs,
40575                 thisArg = lastThis;
40576             lastArgs = lastThis = undefined;
40577             lastInvokeTime = time;
40578             result = func.apply(thisArg, args);
40579             return result;
40580           }
40581
40582           function leadingEdge(time) {
40583             // Reset any `maxWait` timer.
40584             lastInvokeTime = time; // Start the timer for the trailing edge.
40585
40586             timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
40587
40588             return leading ? invokeFunc(time) : result;
40589           }
40590
40591           function remainingWait(time) {
40592             var timeSinceLastCall = time - lastCallTime,
40593                 timeSinceLastInvoke = time - lastInvokeTime,
40594                 timeWaiting = wait - timeSinceLastCall;
40595             return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
40596           }
40597
40598           function shouldInvoke(time) {
40599             var timeSinceLastCall = time - lastCallTime,
40600                 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
40601             // trailing edge, the system time has gone backwards and we're treating
40602             // it as the trailing edge, or we've hit the `maxWait` limit.
40603
40604             return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
40605           }
40606
40607           function timerExpired() {
40608             var time = now$1();
40609
40610             if (shouldInvoke(time)) {
40611               return trailingEdge(time);
40612             } // Restart the timer.
40613
40614
40615             timerId = setTimeout(timerExpired, remainingWait(time));
40616           }
40617
40618           function trailingEdge(time) {
40619             timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
40620             // debounced at least once.
40621
40622             if (trailing && lastArgs) {
40623               return invokeFunc(time);
40624             }
40625
40626             lastArgs = lastThis = undefined;
40627             return result;
40628           }
40629
40630           function cancel() {
40631             if (timerId !== undefined) {
40632               clearTimeout(timerId);
40633             }
40634
40635             lastInvokeTime = 0;
40636             lastArgs = lastCallTime = lastThis = timerId = undefined;
40637           }
40638
40639           function flush() {
40640             return timerId === undefined ? result : trailingEdge(now$1());
40641           }
40642
40643           function debounced() {
40644             var time = now$1(),
40645                 isInvoking = shouldInvoke(time);
40646             lastArgs = arguments;
40647             lastThis = this;
40648             lastCallTime = time;
40649
40650             if (isInvoking) {
40651               if (timerId === undefined) {
40652                 return leadingEdge(lastCallTime);
40653               }
40654
40655               if (maxing) {
40656                 // Handle invocations in a tight loop.
40657                 clearTimeout(timerId);
40658                 timerId = setTimeout(timerExpired, wait);
40659                 return invokeFunc(lastCallTime);
40660               }
40661             }
40662
40663             if (timerId === undefined) {
40664               timerId = setTimeout(timerExpired, wait);
40665             }
40666
40667             return result;
40668           }
40669
40670           debounced.cancel = cancel;
40671           debounced.flush = flush;
40672           return debounced;
40673         }
40674
40675         /** Error message constants. */
40676
40677         var FUNC_ERROR_TEXT$1 = 'Expected a function';
40678         /**
40679          * Creates a throttled function that only invokes `func` at most once per
40680          * every `wait` milliseconds. The throttled function comes with a `cancel`
40681          * method to cancel delayed `func` invocations and a `flush` method to
40682          * immediately invoke them. Provide `options` to indicate whether `func`
40683          * should be invoked on the leading and/or trailing edge of the `wait`
40684          * timeout. The `func` is invoked with the last arguments provided to the
40685          * throttled function. Subsequent calls to the throttled function return the
40686          * result of the last `func` invocation.
40687          *
40688          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40689          * invoked on the trailing edge of the timeout only if the throttled function
40690          * is invoked more than once during the `wait` timeout.
40691          *
40692          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40693          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40694          *
40695          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40696          * for details over the differences between `_.throttle` and `_.debounce`.
40697          *
40698          * @static
40699          * @memberOf _
40700          * @since 0.1.0
40701          * @category Function
40702          * @param {Function} func The function to throttle.
40703          * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
40704          * @param {Object} [options={}] The options object.
40705          * @param {boolean} [options.leading=true]
40706          *  Specify invoking on the leading edge of the timeout.
40707          * @param {boolean} [options.trailing=true]
40708          *  Specify invoking on the trailing edge of the timeout.
40709          * @returns {Function} Returns the new throttled function.
40710          * @example
40711          *
40712          * // Avoid excessively updating the position while scrolling.
40713          * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
40714          *
40715          * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
40716          * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
40717          * jQuery(element).on('click', throttled);
40718          *
40719          * // Cancel the trailing throttled invocation.
40720          * jQuery(window).on('popstate', throttled.cancel);
40721          */
40722
40723         function throttle(func, wait, options) {
40724           var leading = true,
40725               trailing = true;
40726
40727           if (typeof func != 'function') {
40728             throw new TypeError(FUNC_ERROR_TEXT$1);
40729           }
40730
40731           if (isObject$1(options)) {
40732             leading = 'leading' in options ? !!options.leading : leading;
40733             trailing = 'trailing' in options ? !!options.trailing : trailing;
40734           }
40735
40736           return debounce(func, wait, {
40737             'leading': leading,
40738             'maxWait': wait,
40739             'trailing': trailing
40740           });
40741         }
40742
40743         var hashes = createCommonjsModule(function (module, exports) {
40744           /**
40745            * jshashes - https://github.com/h2non/jshashes
40746            * Released under the "New BSD" license
40747            *
40748            * Algorithms specification:
40749            *
40750            * MD5 - http://www.ietf.org/rfc/rfc1321.txt
40751            * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
40752            * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40753            * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40754            * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40755            * HMAC - http://www.ietf.org/rfc/rfc2104.txt
40756            */
40757           (function () {
40758             var Hashes;
40759
40760             function utf8Encode(str) {
40761               var x,
40762                   y,
40763                   output = '',
40764                   i = -1,
40765                   l;
40766
40767               if (str && str.length) {
40768                 l = str.length;
40769
40770                 while ((i += 1) < l) {
40771                   /* Decode utf-16 surrogate pairs */
40772                   x = str.charCodeAt(i);
40773                   y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
40774
40775                   if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
40776                     x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
40777                     i += 1;
40778                   }
40779                   /* Encode output as utf-8 */
40780
40781
40782                   if (x <= 0x7F) {
40783                     output += String.fromCharCode(x);
40784                   } else if (x <= 0x7FF) {
40785                     output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
40786                   } else if (x <= 0xFFFF) {
40787                     output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40788                   } else if (x <= 0x1FFFFF) {
40789                     output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40790                   }
40791                 }
40792               }
40793
40794               return output;
40795             }
40796
40797             function utf8Decode(str) {
40798               var i,
40799                   ac,
40800                   c1,
40801                   c2,
40802                   c3,
40803                   arr = [],
40804                   l;
40805               i = ac = c1 = c2 = c3 = 0;
40806
40807               if (str && str.length) {
40808                 l = str.length;
40809                 str += '';
40810
40811                 while (i < l) {
40812                   c1 = str.charCodeAt(i);
40813                   ac += 1;
40814
40815                   if (c1 < 128) {
40816                     arr[ac] = String.fromCharCode(c1);
40817                     i += 1;
40818                   } else if (c1 > 191 && c1 < 224) {
40819                     c2 = str.charCodeAt(i + 1);
40820                     arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
40821                     i += 2;
40822                   } else {
40823                     c2 = str.charCodeAt(i + 1);
40824                     c3 = str.charCodeAt(i + 2);
40825                     arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
40826                     i += 3;
40827                   }
40828                 }
40829               }
40830
40831               return arr.join('');
40832             }
40833             /**
40834              * Add integers, wrapping at 2^32. This uses 16-bit operations internally
40835              * to work around bugs in some JS interpreters.
40836              */
40837
40838
40839             function safe_add(x, y) {
40840               var lsw = (x & 0xFFFF) + (y & 0xFFFF),
40841                   msw = (x >> 16) + (y >> 16) + (lsw >> 16);
40842               return msw << 16 | lsw & 0xFFFF;
40843             }
40844             /**
40845              * Bitwise rotate a 32-bit number to the left.
40846              */
40847
40848
40849             function bit_rol(num, cnt) {
40850               return num << cnt | num >>> 32 - cnt;
40851             }
40852             /**
40853              * Convert a raw string to a hex string
40854              */
40855
40856
40857             function rstr2hex(input, hexcase) {
40858               var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
40859                   output = '',
40860                   x,
40861                   i = 0,
40862                   l = input.length;
40863
40864               for (; i < l; i += 1) {
40865                 x = input.charCodeAt(i);
40866                 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
40867               }
40868
40869               return output;
40870             }
40871             /**
40872              * Convert an array of big-endian words to a string
40873              */
40874
40875
40876             function binb2rstr(input) {
40877               var i,
40878                   l = input.length * 32,
40879                   output = '';
40880
40881               for (i = 0; i < l; i += 8) {
40882                 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
40883               }
40884
40885               return output;
40886             }
40887             /**
40888              * Convert an array of little-endian words to a string
40889              */
40890
40891
40892             function binl2rstr(input) {
40893               var i,
40894                   l = input.length * 32,
40895                   output = '';
40896
40897               for (i = 0; i < l; i += 8) {
40898                 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
40899               }
40900
40901               return output;
40902             }
40903             /**
40904              * Convert a raw string to an array of little-endian words
40905              * Characters >255 have their high-byte silently ignored.
40906              */
40907
40908
40909             function rstr2binl(input) {
40910               var i,
40911                   l = input.length * 8,
40912                   output = Array(input.length >> 2),
40913                   lo = output.length;
40914
40915               for (i = 0; i < lo; i += 1) {
40916                 output[i] = 0;
40917               }
40918
40919               for (i = 0; i < l; i += 8) {
40920                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
40921               }
40922
40923               return output;
40924             }
40925             /**
40926              * Convert a raw string to an array of big-endian words
40927              * Characters >255 have their high-byte silently ignored.
40928              */
40929
40930
40931             function rstr2binb(input) {
40932               var i,
40933                   l = input.length * 8,
40934                   output = Array(input.length >> 2),
40935                   lo = output.length;
40936
40937               for (i = 0; i < lo; i += 1) {
40938                 output[i] = 0;
40939               }
40940
40941               for (i = 0; i < l; i += 8) {
40942                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
40943               }
40944
40945               return output;
40946             }
40947             /**
40948              * Convert a raw string to an arbitrary string encoding
40949              */
40950
40951
40952             function rstr2any(input, encoding) {
40953               var divisor = encoding.length,
40954                   remainders = Array(),
40955                   i,
40956                   q,
40957                   x,
40958                   ld,
40959                   quotient,
40960                   dividend,
40961                   output,
40962                   full_length;
40963               /* Convert to an array of 16-bit big-endian values, forming the dividend */
40964
40965               dividend = Array(Math.ceil(input.length / 2));
40966               ld = dividend.length;
40967
40968               for (i = 0; i < ld; i += 1) {
40969                 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
40970               }
40971               /**
40972                * Repeatedly perform a long division. The binary array forms the dividend,
40973                * the length of the encoding is the divisor. Once computed, the quotient
40974                * forms the dividend for the next step. We stop when the dividend is zerHashes.
40975                * All remainders are stored for later use.
40976                */
40977
40978
40979               while (dividend.length > 0) {
40980                 quotient = Array();
40981                 x = 0;
40982
40983                 for (i = 0; i < dividend.length; i += 1) {
40984                   x = (x << 16) + dividend[i];
40985                   q = Math.floor(x / divisor);
40986                   x -= q * divisor;
40987
40988                   if (quotient.length > 0 || q > 0) {
40989                     quotient[quotient.length] = q;
40990                   }
40991                 }
40992
40993                 remainders[remainders.length] = x;
40994                 dividend = quotient;
40995               }
40996               /* Convert the remainders to the output string */
40997
40998
40999               output = '';
41000
41001               for (i = remainders.length - 1; i >= 0; i--) {
41002                 output += encoding.charAt(remainders[i]);
41003               }
41004               /* Append leading zero equivalents */
41005
41006
41007               full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
41008
41009               for (i = output.length; i < full_length; i += 1) {
41010                 output = encoding[0] + output;
41011               }
41012
41013               return output;
41014             }
41015             /**
41016              * Convert a raw string to a base-64 string
41017              */
41018
41019
41020             function rstr2b64(input, b64pad) {
41021               var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
41022                   output = '',
41023                   len = input.length,
41024                   i,
41025                   j,
41026                   triplet;
41027               b64pad = b64pad || '=';
41028
41029               for (i = 0; i < len; i += 3) {
41030                 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
41031
41032                 for (j = 0; j < 4; j += 1) {
41033                   if (i * 8 + j * 6 > input.length * 8) {
41034                     output += b64pad;
41035                   } else {
41036                     output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
41037                   }
41038                 }
41039               }
41040
41041               return output;
41042             }
41043
41044             Hashes = {
41045               /**
41046                * @property {String} version
41047                * @readonly
41048                */
41049               VERSION: '1.0.6',
41050
41051               /**
41052                * @member Hashes
41053                * @class Base64
41054                * @constructor
41055                */
41056               Base64: function Base64() {
41057                 // private properties
41058                 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
41059                     pad = '=',
41060                     // URL encoding support @todo
41061                 utf8 = true; // by default enable UTF-8 support encoding
41062                 // public method for encoding
41063
41064                 this.encode = function (input) {
41065                   var i,
41066                       j,
41067                       triplet,
41068                       output = '',
41069                       len = input.length;
41070                   pad = pad || '=';
41071                   input = utf8 ? utf8Encode(input) : input;
41072
41073                   for (i = 0; i < len; i += 3) {
41074                     triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
41075
41076                     for (j = 0; j < 4; j += 1) {
41077                       if (i * 8 + j * 6 > len * 8) {
41078                         output += pad;
41079                       } else {
41080                         output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
41081                       }
41082                     }
41083                   }
41084
41085                   return output;
41086                 }; // public method for decoding
41087
41088
41089                 this.decode = function (input) {
41090                   // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
41091                   var i,
41092                       o1,
41093                       o2,
41094                       o3,
41095                       h1,
41096                       h2,
41097                       h3,
41098                       h4,
41099                       bits,
41100                       ac,
41101                       dec = '',
41102                       arr = [];
41103
41104                   if (!input) {
41105                     return input;
41106                   }
41107
41108                   i = ac = 0;
41109                   input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
41110                   //input += '';
41111
41112                   do {
41113                     // unpack four hexets into three octets using index points in b64
41114                     h1 = tab.indexOf(input.charAt(i += 1));
41115                     h2 = tab.indexOf(input.charAt(i += 1));
41116                     h3 = tab.indexOf(input.charAt(i += 1));
41117                     h4 = tab.indexOf(input.charAt(i += 1));
41118                     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
41119                     o1 = bits >> 16 & 0xff;
41120                     o2 = bits >> 8 & 0xff;
41121                     o3 = bits & 0xff;
41122                     ac += 1;
41123
41124                     if (h3 === 64) {
41125                       arr[ac] = String.fromCharCode(o1);
41126                     } else if (h4 === 64) {
41127                       arr[ac] = String.fromCharCode(o1, o2);
41128                     } else {
41129                       arr[ac] = String.fromCharCode(o1, o2, o3);
41130                     }
41131                   } while (i < input.length);
41132
41133                   dec = arr.join('');
41134                   dec = utf8 ? utf8Decode(dec) : dec;
41135                   return dec;
41136                 }; // set custom pad string
41137
41138
41139                 this.setPad = function (str) {
41140                   pad = str || pad;
41141                   return this;
41142                 }; // set custom tab string characters
41143
41144
41145                 this.setTab = function (str) {
41146                   tab = str || tab;
41147                   return this;
41148                 };
41149
41150                 this.setUTF8 = function (bool) {
41151                   if (typeof bool === 'boolean') {
41152                     utf8 = bool;
41153                   }
41154
41155                   return this;
41156                 };
41157               },
41158
41159               /**
41160                * CRC-32 calculation
41161                * @member Hashes
41162                * @method CRC32
41163                * @static
41164                * @param {String} str Input String
41165                * @return {String}
41166                */
41167               CRC32: function CRC32(str) {
41168                 var crc = 0,
41169                     x = 0,
41170                     y = 0,
41171                     table,
41172                     i,
41173                     iTop;
41174                 str = utf8Encode(str);
41175                 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('');
41176                 crc = crc ^ -1;
41177
41178                 for (i = 0, iTop = str.length; i < iTop; i += 1) {
41179                   y = (crc ^ str.charCodeAt(i)) & 0xFF;
41180                   x = '0x' + table.substr(y * 9, 8);
41181                   crc = crc >>> 8 ^ x;
41182                 } // always return a positive number (that's what >>> 0 does)
41183
41184
41185                 return (crc ^ -1) >>> 0;
41186               },
41187
41188               /**
41189                * @member Hashes
41190                * @class MD5
41191                * @constructor
41192                * @param {Object} [config]
41193                *
41194                * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
41195                * Digest Algorithm, as defined in RFC 1321.
41196                * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
41197                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41198                * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
41199                */
41200               MD5: function MD5(options) {
41201                 /**
41202                  * Private config properties. You may need to tweak these to be compatible with
41203                  * the server-side, but the defaults work in most cases.
41204                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41205                  */
41206                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41207                     // hexadecimal output case format. false - lowercase; true - uppercase
41208                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41209                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41210                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41211                 // privileged (public) methods
41212
41213                 this.hex = function (s) {
41214                   return rstr2hex(rstr(s), hexcase);
41215                 };
41216
41217                 this.b64 = function (s) {
41218                   return rstr2b64(rstr(s), b64pad);
41219                 };
41220
41221                 this.any = function (s, e) {
41222                   return rstr2any(rstr(s), e);
41223                 };
41224
41225                 this.raw = function (s) {
41226                   return rstr(s);
41227                 };
41228
41229                 this.hex_hmac = function (k, d) {
41230                   return rstr2hex(rstr_hmac(k, d), hexcase);
41231                 };
41232
41233                 this.b64_hmac = function (k, d) {
41234                   return rstr2b64(rstr_hmac(k, d), b64pad);
41235                 };
41236
41237                 this.any_hmac = function (k, d, e) {
41238                   return rstr2any(rstr_hmac(k, d), e);
41239                 };
41240                 /**
41241                  * Perform a simple self-test to see if the VM is working
41242                  * @return {String} Hexadecimal hash sample
41243                  */
41244
41245
41246                 this.vm_test = function () {
41247                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41248                 };
41249                 /**
41250                  * Enable/disable uppercase hexadecimal returned string
41251                  * @param {Boolean}
41252                  * @return {Object} this
41253                  */
41254
41255
41256                 this.setUpperCase = function (a) {
41257                   if (typeof a === 'boolean') {
41258                     hexcase = a;
41259                   }
41260
41261                   return this;
41262                 };
41263                 /**
41264                  * Defines a base64 pad string
41265                  * @param {String} Pad
41266                  * @return {Object} this
41267                  */
41268
41269
41270                 this.setPad = function (a) {
41271                   b64pad = a || b64pad;
41272                   return this;
41273                 };
41274                 /**
41275                  * Defines a base64 pad string
41276                  * @param {Boolean}
41277                  * @return {Object} [this]
41278                  */
41279
41280
41281                 this.setUTF8 = function (a) {
41282                   if (typeof a === 'boolean') {
41283                     utf8 = a;
41284                   }
41285
41286                   return this;
41287                 }; // private methods
41288
41289                 /**
41290                  * Calculate the MD5 of a raw string
41291                  */
41292
41293
41294                 function rstr(s) {
41295                   s = utf8 ? utf8Encode(s) : s;
41296                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
41297                 }
41298                 /**
41299                  * Calculate the HMAC-MD5, of a key and some data (raw strings)
41300                  */
41301
41302
41303                 function rstr_hmac(key, data) {
41304                   var bkey, ipad, opad, hash, i;
41305                   key = utf8 ? utf8Encode(key) : key;
41306                   data = utf8 ? utf8Encode(data) : data;
41307                   bkey = rstr2binl(key);
41308
41309                   if (bkey.length > 16) {
41310                     bkey = binl(bkey, key.length * 8);
41311                   }
41312
41313                   ipad = Array(16), opad = Array(16);
41314
41315                   for (i = 0; i < 16; i += 1) {
41316                     ipad[i] = bkey[i] ^ 0x36363636;
41317                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41318                   }
41319
41320                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
41321                   return binl2rstr(binl(opad.concat(hash), 512 + 128));
41322                 }
41323                 /**
41324                  * Calculate the MD5 of an array of little-endian words, and a bit length.
41325                  */
41326
41327
41328                 function binl(x, len) {
41329                   var i,
41330                       olda,
41331                       oldb,
41332                       oldc,
41333                       oldd,
41334                       a = 1732584193,
41335                       b = -271733879,
41336                       c = -1732584194,
41337                       d = 271733878;
41338                   /* append padding */
41339
41340                   x[len >> 5] |= 0x80 << len % 32;
41341                   x[(len + 64 >>> 9 << 4) + 14] = len;
41342
41343                   for (i = 0; i < x.length; i += 16) {
41344                     olda = a;
41345                     oldb = b;
41346                     oldc = c;
41347                     oldd = d;
41348                     a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
41349                     d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
41350                     c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
41351                     b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
41352                     a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
41353                     d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
41354                     c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
41355                     b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
41356                     a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
41357                     d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
41358                     c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
41359                     b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
41360                     a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
41361                     d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
41362                     c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
41363                     b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
41364                     a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
41365                     d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
41366                     c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
41367                     b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
41368                     a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
41369                     d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
41370                     c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
41371                     b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
41372                     a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
41373                     d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
41374                     c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
41375                     b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
41376                     a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
41377                     d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
41378                     c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
41379                     b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
41380                     a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
41381                     d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
41382                     c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
41383                     b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
41384                     a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
41385                     d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
41386                     c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
41387                     b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
41388                     a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
41389                     d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
41390                     c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
41391                     b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
41392                     a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
41393                     d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
41394                     c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
41395                     b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
41396                     a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
41397                     d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
41398                     c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
41399                     b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
41400                     a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
41401                     d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
41402                     c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
41403                     b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
41404                     a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
41405                     d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
41406                     c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
41407                     b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
41408                     a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
41409                     d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
41410                     c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
41411                     b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
41412                     a = safe_add(a, olda);
41413                     b = safe_add(b, oldb);
41414                     c = safe_add(c, oldc);
41415                     d = safe_add(d, oldd);
41416                   }
41417
41418                   return Array(a, b, c, d);
41419                 }
41420                 /**
41421                  * These functions implement the four basic operations the algorithm uses.
41422                  */
41423
41424
41425                 function md5_cmn(q, a, b, x, s, t) {
41426                   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
41427                 }
41428
41429                 function md5_ff(a, b, c, d, x, s, t) {
41430                   return md5_cmn(b & c | ~b & d, a, b, x, s, t);
41431                 }
41432
41433                 function md5_gg(a, b, c, d, x, s, t) {
41434                   return md5_cmn(b & d | c & ~d, a, b, x, s, t);
41435                 }
41436
41437                 function md5_hh(a, b, c, d, x, s, t) {
41438                   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
41439                 }
41440
41441                 function md5_ii(a, b, c, d, x, s, t) {
41442                   return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
41443                 }
41444               },
41445
41446               /**
41447                * @member Hashes
41448                * @class Hashes.SHA1
41449                * @param {Object} [config]
41450                * @constructor
41451                *
41452                * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
41453                * Version 2.2 Copyright Paul Johnston 2000 - 2009.
41454                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41455                * See http://pajhome.org.uk/crypt/md5 for details.
41456                */
41457               SHA1: function SHA1(options) {
41458                 /**
41459                  * Private config properties. You may need to tweak these to be compatible with
41460                  * the server-side, but the defaults work in most cases.
41461                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41462                  */
41463                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41464                     // hexadecimal output case format. false - lowercase; true - uppercase
41465                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41466                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41467                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41468                 // public methods
41469
41470                 this.hex = function (s) {
41471                   return rstr2hex(rstr(s), hexcase);
41472                 };
41473
41474                 this.b64 = function (s) {
41475                   return rstr2b64(rstr(s), b64pad);
41476                 };
41477
41478                 this.any = function (s, e) {
41479                   return rstr2any(rstr(s), e);
41480                 };
41481
41482                 this.raw = function (s) {
41483                   return rstr(s);
41484                 };
41485
41486                 this.hex_hmac = function (k, d) {
41487                   return rstr2hex(rstr_hmac(k, d));
41488                 };
41489
41490                 this.b64_hmac = function (k, d) {
41491                   return rstr2b64(rstr_hmac(k, d), b64pad);
41492                 };
41493
41494                 this.any_hmac = function (k, d, e) {
41495                   return rstr2any(rstr_hmac(k, d), e);
41496                 };
41497                 /**
41498                  * Perform a simple self-test to see if the VM is working
41499                  * @return {String} Hexadecimal hash sample
41500                  * @public
41501                  */
41502
41503
41504                 this.vm_test = function () {
41505                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41506                 };
41507                 /**
41508                  * @description Enable/disable uppercase hexadecimal returned string
41509                  * @param {boolean}
41510                  * @return {Object} this
41511                  * @public
41512                  */
41513
41514
41515                 this.setUpperCase = function (a) {
41516                   if (typeof a === 'boolean') {
41517                     hexcase = a;
41518                   }
41519
41520                   return this;
41521                 };
41522                 /**
41523                  * @description Defines a base64 pad string
41524                  * @param {string} Pad
41525                  * @return {Object} this
41526                  * @public
41527                  */
41528
41529
41530                 this.setPad = function (a) {
41531                   b64pad = a || b64pad;
41532                   return this;
41533                 };
41534                 /**
41535                  * @description Defines a base64 pad string
41536                  * @param {boolean}
41537                  * @return {Object} this
41538                  * @public
41539                  */
41540
41541
41542                 this.setUTF8 = function (a) {
41543                   if (typeof a === 'boolean') {
41544                     utf8 = a;
41545                   }
41546
41547                   return this;
41548                 }; // private methods
41549
41550                 /**
41551                  * Calculate the SHA-512 of a raw string
41552                  */
41553
41554
41555                 function rstr(s) {
41556                   s = utf8 ? utf8Encode(s) : s;
41557                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41558                 }
41559                 /**
41560                  * Calculate the HMAC-SHA1 of a key and some data (raw strings)
41561                  */
41562
41563
41564                 function rstr_hmac(key, data) {
41565                   var bkey, ipad, opad, i, hash;
41566                   key = utf8 ? utf8Encode(key) : key;
41567                   data = utf8 ? utf8Encode(data) : data;
41568                   bkey = rstr2binb(key);
41569
41570                   if (bkey.length > 16) {
41571                     bkey = binb(bkey, key.length * 8);
41572                   }
41573
41574                   ipad = Array(16), opad = Array(16);
41575
41576                   for (i = 0; i < 16; i += 1) {
41577                     ipad[i] = bkey[i] ^ 0x36363636;
41578                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41579                   }
41580
41581                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41582                   return binb2rstr(binb(opad.concat(hash), 512 + 160));
41583                 }
41584                 /**
41585                  * Calculate the SHA-1 of an array of big-endian words, and a bit length
41586                  */
41587
41588
41589                 function binb(x, len) {
41590                   var i,
41591                       j,
41592                       t,
41593                       olda,
41594                       oldb,
41595                       oldc,
41596                       oldd,
41597                       olde,
41598                       w = Array(80),
41599                       a = 1732584193,
41600                       b = -271733879,
41601                       c = -1732584194,
41602                       d = 271733878,
41603                       e = -1009589776;
41604                   /* append padding */
41605
41606                   x[len >> 5] |= 0x80 << 24 - len % 32;
41607                   x[(len + 64 >> 9 << 4) + 15] = len;
41608
41609                   for (i = 0; i < x.length; i += 16) {
41610                     olda = a;
41611                     oldb = b;
41612                     oldc = c;
41613                     oldd = d;
41614                     olde = e;
41615
41616                     for (j = 0; j < 80; j += 1) {
41617                       if (j < 16) {
41618                         w[j] = x[i + j];
41619                       } else {
41620                         w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
41621                       }
41622
41623                       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)));
41624                       e = d;
41625                       d = c;
41626                       c = bit_rol(b, 30);
41627                       b = a;
41628                       a = t;
41629                     }
41630
41631                     a = safe_add(a, olda);
41632                     b = safe_add(b, oldb);
41633                     c = safe_add(c, oldc);
41634                     d = safe_add(d, oldd);
41635                     e = safe_add(e, olde);
41636                   }
41637
41638                   return Array(a, b, c, d, e);
41639                 }
41640                 /**
41641                  * Perform the appropriate triplet combination function for the current
41642                  * iteration
41643                  */
41644
41645
41646                 function sha1_ft(t, b, c, d) {
41647                   if (t < 20) {
41648                     return b & c | ~b & d;
41649                   }
41650
41651                   if (t < 40) {
41652                     return b ^ c ^ d;
41653                   }
41654
41655                   if (t < 60) {
41656                     return b & c | b & d | c & d;
41657                   }
41658
41659                   return b ^ c ^ d;
41660                 }
41661                 /**
41662                  * Determine the appropriate additive constant for the current iteration
41663                  */
41664
41665
41666                 function sha1_kt(t) {
41667                   return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
41668                 }
41669               },
41670
41671               /**
41672                * @class Hashes.SHA256
41673                * @param {config}
41674                *
41675                * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
41676                * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
41677                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41678                * See http://pajhome.org.uk/crypt/md5 for details.
41679                * Also http://anmar.eu.org/projects/jssha2/
41680                */
41681               SHA256: function SHA256(options) {
41682                 /**
41683                  * Private properties configuration variables. You may need to tweak these to be compatible with
41684                  * the server-side, but the defaults work in most cases.
41685                  * @see this.setUpperCase() method
41686                  * @see this.setPad() method
41687                  */
41688                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41689                     // hexadecimal output case format. false - lowercase; true - uppercase  */
41690                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41691
41692                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41693                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41694
41695                 /* enable/disable utf8 encoding */
41696                 sha256_K;
41697                 /* privileged (public) methods */
41698
41699                 this.hex = function (s) {
41700                   return rstr2hex(rstr(s, utf8));
41701                 };
41702
41703                 this.b64 = function (s) {
41704                   return rstr2b64(rstr(s, utf8), b64pad);
41705                 };
41706
41707                 this.any = function (s, e) {
41708                   return rstr2any(rstr(s, utf8), e);
41709                 };
41710
41711                 this.raw = function (s) {
41712                   return rstr(s, utf8);
41713                 };
41714
41715                 this.hex_hmac = function (k, d) {
41716                   return rstr2hex(rstr_hmac(k, d));
41717                 };
41718
41719                 this.b64_hmac = function (k, d) {
41720                   return rstr2b64(rstr_hmac(k, d), b64pad);
41721                 };
41722
41723                 this.any_hmac = function (k, d, e) {
41724                   return rstr2any(rstr_hmac(k, d), e);
41725                 };
41726                 /**
41727                  * Perform a simple self-test to see if the VM is working
41728                  * @return {String} Hexadecimal hash sample
41729                  * @public
41730                  */
41731
41732
41733                 this.vm_test = function () {
41734                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41735                 };
41736                 /**
41737                  * Enable/disable uppercase hexadecimal returned string
41738                  * @param {boolean}
41739                  * @return {Object} this
41740                  * @public
41741                  */
41742
41743
41744                 this.setUpperCase = function (a) {
41745                   if (typeof a === 'boolean') {
41746                     hexcase = a;
41747                   }
41748
41749                   return this;
41750                 };
41751                 /**
41752                  * @description Defines a base64 pad string
41753                  * @param {string} Pad
41754                  * @return {Object} this
41755                  * @public
41756                  */
41757
41758
41759                 this.setPad = function (a) {
41760                   b64pad = a || b64pad;
41761                   return this;
41762                 };
41763                 /**
41764                  * Defines a base64 pad string
41765                  * @param {boolean}
41766                  * @return {Object} this
41767                  * @public
41768                  */
41769
41770
41771                 this.setUTF8 = function (a) {
41772                   if (typeof a === 'boolean') {
41773                     utf8 = a;
41774                   }
41775
41776                   return this;
41777                 }; // private methods
41778
41779                 /**
41780                  * Calculate the SHA-512 of a raw string
41781                  */
41782
41783
41784                 function rstr(s, utf8) {
41785                   s = utf8 ? utf8Encode(s) : s;
41786                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41787                 }
41788                 /**
41789                  * Calculate the HMAC-sha256 of a key and some data (raw strings)
41790                  */
41791
41792
41793                 function rstr_hmac(key, data) {
41794                   key = utf8 ? utf8Encode(key) : key;
41795                   data = utf8 ? utf8Encode(data) : data;
41796                   var hash,
41797                       i = 0,
41798                       bkey = rstr2binb(key),
41799                       ipad = Array(16),
41800                       opad = Array(16);
41801
41802                   if (bkey.length > 16) {
41803                     bkey = binb(bkey, key.length * 8);
41804                   }
41805
41806                   for (; i < 16; i += 1) {
41807                     ipad[i] = bkey[i] ^ 0x36363636;
41808                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41809                   }
41810
41811                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41812                   return binb2rstr(binb(opad.concat(hash), 512 + 256));
41813                 }
41814                 /*
41815                  * Main sha256 function, with its support functions
41816                  */
41817
41818
41819                 function sha256_S(X, n) {
41820                   return X >>> n | X << 32 - n;
41821                 }
41822
41823                 function sha256_R(X, n) {
41824                   return X >>> n;
41825                 }
41826
41827                 function sha256_Ch(x, y, z) {
41828                   return x & y ^ ~x & z;
41829                 }
41830
41831                 function sha256_Maj(x, y, z) {
41832                   return x & y ^ x & z ^ y & z;
41833                 }
41834
41835                 function sha256_Sigma0256(x) {
41836                   return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
41837                 }
41838
41839                 function sha256_Sigma1256(x) {
41840                   return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
41841                 }
41842
41843                 function sha256_Gamma0256(x) {
41844                   return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
41845                 }
41846
41847                 function sha256_Gamma1256(x) {
41848                   return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
41849                 }
41850
41851                 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];
41852
41853                 function binb(m, l) {
41854                   var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
41855                   var W = new Array(64);
41856                   var a, b, c, d, e, f, g, h;
41857                   var i, j, T1, T2;
41858                   /* append padding */
41859
41860                   m[l >> 5] |= 0x80 << 24 - l % 32;
41861                   m[(l + 64 >> 9 << 4) + 15] = l;
41862
41863                   for (i = 0; i < m.length; i += 16) {
41864                     a = HASH[0];
41865                     b = HASH[1];
41866                     c = HASH[2];
41867                     d = HASH[3];
41868                     e = HASH[4];
41869                     f = HASH[5];
41870                     g = HASH[6];
41871                     h = HASH[7];
41872
41873                     for (j = 0; j < 64; j += 1) {
41874                       if (j < 16) {
41875                         W[j] = m[j + i];
41876                       } else {
41877                         W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
41878                       }
41879
41880                       T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
41881                       T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
41882                       h = g;
41883                       g = f;
41884                       f = e;
41885                       e = safe_add(d, T1);
41886                       d = c;
41887                       c = b;
41888                       b = a;
41889                       a = safe_add(T1, T2);
41890                     }
41891
41892                     HASH[0] = safe_add(a, HASH[0]);
41893                     HASH[1] = safe_add(b, HASH[1]);
41894                     HASH[2] = safe_add(c, HASH[2]);
41895                     HASH[3] = safe_add(d, HASH[3]);
41896                     HASH[4] = safe_add(e, HASH[4]);
41897                     HASH[5] = safe_add(f, HASH[5]);
41898                     HASH[6] = safe_add(g, HASH[6]);
41899                     HASH[7] = safe_add(h, HASH[7]);
41900                   }
41901
41902                   return HASH;
41903                 }
41904               },
41905
41906               /**
41907                * @class Hashes.SHA512
41908                * @param {config}
41909                *
41910                * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
41911                * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
41912                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41913                * See http://pajhome.org.uk/crypt/md5 for details.
41914                */
41915               SHA512: function SHA512(options) {
41916                 /**
41917                  * Private properties configuration variables. You may need to tweak these to be compatible with
41918                  * the server-side, but the defaults work in most cases.
41919                  * @see this.setUpperCase() method
41920                  * @see this.setPad() method
41921                  */
41922                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41923
41924                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
41925                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41926
41927                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41928                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41929
41930                 /* enable/disable utf8 encoding */
41931                 sha512_k;
41932                 /* privileged (public) methods */
41933
41934                 this.hex = function (s) {
41935                   return rstr2hex(rstr(s));
41936                 };
41937
41938                 this.b64 = function (s) {
41939                   return rstr2b64(rstr(s), b64pad);
41940                 };
41941
41942                 this.any = function (s, e) {
41943                   return rstr2any(rstr(s), e);
41944                 };
41945
41946                 this.raw = function (s) {
41947                   return rstr(s);
41948                 };
41949
41950                 this.hex_hmac = function (k, d) {
41951                   return rstr2hex(rstr_hmac(k, d));
41952                 };
41953
41954                 this.b64_hmac = function (k, d) {
41955                   return rstr2b64(rstr_hmac(k, d), b64pad);
41956                 };
41957
41958                 this.any_hmac = function (k, d, e) {
41959                   return rstr2any(rstr_hmac(k, d), e);
41960                 };
41961                 /**
41962                  * Perform a simple self-test to see if the VM is working
41963                  * @return {String} Hexadecimal hash sample
41964                  * @public
41965                  */
41966
41967
41968                 this.vm_test = function () {
41969                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41970                 };
41971                 /**
41972                  * @description Enable/disable uppercase hexadecimal returned string
41973                  * @param {boolean}
41974                  * @return {Object} this
41975                  * @public
41976                  */
41977
41978
41979                 this.setUpperCase = function (a) {
41980                   if (typeof a === 'boolean') {
41981                     hexcase = a;
41982                   }
41983
41984                   return this;
41985                 };
41986                 /**
41987                  * @description Defines a base64 pad string
41988                  * @param {string} Pad
41989                  * @return {Object} this
41990                  * @public
41991                  */
41992
41993
41994                 this.setPad = function (a) {
41995                   b64pad = a || b64pad;
41996                   return this;
41997                 };
41998                 /**
41999                  * @description Defines a base64 pad string
42000                  * @param {boolean}
42001                  * @return {Object} this
42002                  * @public
42003                  */
42004
42005
42006                 this.setUTF8 = function (a) {
42007                   if (typeof a === 'boolean') {
42008                     utf8 = a;
42009                   }
42010
42011                   return this;
42012                 };
42013                 /* private methods */
42014
42015                 /**
42016                  * Calculate the SHA-512 of a raw string
42017                  */
42018
42019
42020                 function rstr(s) {
42021                   s = utf8 ? utf8Encode(s) : s;
42022                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
42023                 }
42024                 /*
42025                  * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
42026                  */
42027
42028
42029                 function rstr_hmac(key, data) {
42030                   key = utf8 ? utf8Encode(key) : key;
42031                   data = utf8 ? utf8Encode(data) : data;
42032                   var hash,
42033                       i = 0,
42034                       bkey = rstr2binb(key),
42035                       ipad = Array(32),
42036                       opad = Array(32);
42037
42038                   if (bkey.length > 32) {
42039                     bkey = binb(bkey, key.length * 8);
42040                   }
42041
42042                   for (; i < 32; i += 1) {
42043                     ipad[i] = bkey[i] ^ 0x36363636;
42044                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
42045                   }
42046
42047                   hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
42048                   return binb2rstr(binb(opad.concat(hash), 1024 + 512));
42049                 }
42050                 /**
42051                  * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
42052                  */
42053
42054
42055                 function binb(x, len) {
42056                   var j,
42057                       i,
42058                       l,
42059                       W = new Array(80),
42060                       hash = new Array(16),
42061                       //Initial hash values
42062                   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)],
42063                       T1 = new int64(0, 0),
42064                       T2 = new int64(0, 0),
42065                       a = new int64(0, 0),
42066                       b = new int64(0, 0),
42067                       c = new int64(0, 0),
42068                       d = new int64(0, 0),
42069                       e = new int64(0, 0),
42070                       f = new int64(0, 0),
42071                       g = new int64(0, 0),
42072                       h = new int64(0, 0),
42073                       //Temporary variables not specified by the document
42074                   s0 = new int64(0, 0),
42075                       s1 = new int64(0, 0),
42076                       Ch = new int64(0, 0),
42077                       Maj = new int64(0, 0),
42078                       r1 = new int64(0, 0),
42079                       r2 = new int64(0, 0),
42080                       r3 = new int64(0, 0);
42081
42082                   if (sha512_k === undefined) {
42083                     //SHA512 constants
42084                     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)];
42085                   }
42086
42087                   for (i = 0; i < 80; i += 1) {
42088                     W[i] = new int64(0, 0);
42089                   } // append padding to the source string. The format is described in the FIPS.
42090
42091
42092                   x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
42093                   x[(len + 128 >> 10 << 5) + 31] = len;
42094                   l = x.length;
42095
42096                   for (i = 0; i < l; i += 32) {
42097                     //32 dwords is the block size
42098                     int64copy(a, H[0]);
42099                     int64copy(b, H[1]);
42100                     int64copy(c, H[2]);
42101                     int64copy(d, H[3]);
42102                     int64copy(e, H[4]);
42103                     int64copy(f, H[5]);
42104                     int64copy(g, H[6]);
42105                     int64copy(h, H[7]);
42106
42107                     for (j = 0; j < 16; j += 1) {
42108                       W[j].h = x[i + 2 * j];
42109                       W[j].l = x[i + 2 * j + 1];
42110                     }
42111
42112                     for (j = 16; j < 80; j += 1) {
42113                       //sigma1
42114                       int64rrot(r1, W[j - 2], 19);
42115                       int64revrrot(r2, W[j - 2], 29);
42116                       int64shr(r3, W[j - 2], 6);
42117                       s1.l = r1.l ^ r2.l ^ r3.l;
42118                       s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
42119
42120                       int64rrot(r1, W[j - 15], 1);
42121                       int64rrot(r2, W[j - 15], 8);
42122                       int64shr(r3, W[j - 15], 7);
42123                       s0.l = r1.l ^ r2.l ^ r3.l;
42124                       s0.h = r1.h ^ r2.h ^ r3.h;
42125                       int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
42126                     }
42127
42128                     for (j = 0; j < 80; j += 1) {
42129                       //Ch
42130                       Ch.l = e.l & f.l ^ ~e.l & g.l;
42131                       Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
42132
42133                       int64rrot(r1, e, 14);
42134                       int64rrot(r2, e, 18);
42135                       int64revrrot(r3, e, 9);
42136                       s1.l = r1.l ^ r2.l ^ r3.l;
42137                       s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
42138
42139                       int64rrot(r1, a, 28);
42140                       int64revrrot(r2, a, 2);
42141                       int64revrrot(r3, a, 7);
42142                       s0.l = r1.l ^ r2.l ^ r3.l;
42143                       s0.h = r1.h ^ r2.h ^ r3.h; //Maj
42144
42145                       Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
42146                       Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
42147                       int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
42148                       int64add(T2, s0, Maj);
42149                       int64copy(h, g);
42150                       int64copy(g, f);
42151                       int64copy(f, e);
42152                       int64add(e, d, T1);
42153                       int64copy(d, c);
42154                       int64copy(c, b);
42155                       int64copy(b, a);
42156                       int64add(a, T1, T2);
42157                     }
42158
42159                     int64add(H[0], H[0], a);
42160                     int64add(H[1], H[1], b);
42161                     int64add(H[2], H[2], c);
42162                     int64add(H[3], H[3], d);
42163                     int64add(H[4], H[4], e);
42164                     int64add(H[5], H[5], f);
42165                     int64add(H[6], H[6], g);
42166                     int64add(H[7], H[7], h);
42167                   } //represent the hash as an array of 32-bit dwords
42168
42169
42170                   for (i = 0; i < 8; i += 1) {
42171                     hash[2 * i] = H[i].h;
42172                     hash[2 * i + 1] = H[i].l;
42173                   }
42174
42175                   return hash;
42176                 } //A constructor for 64-bit numbers
42177
42178
42179                 function int64(h, l) {
42180                   this.h = h;
42181                   this.l = l; //this.toString = int64toString;
42182                 } //Copies src into dst, assuming both are 64-bit numbers
42183
42184
42185                 function int64copy(dst, src) {
42186                   dst.h = src.h;
42187                   dst.l = src.l;
42188                 } //Right-rotates a 64-bit number by shift
42189                 //Won't handle cases of shift>=32
42190                 //The function revrrot() is for that
42191
42192
42193                 function int64rrot(dst, x, shift) {
42194                   dst.l = x.l >>> shift | x.h << 32 - shift;
42195                   dst.h = x.h >>> shift | x.l << 32 - shift;
42196                 } //Reverses the dwords of the source and then rotates right by shift.
42197                 //This is equivalent to rotation by 32+shift
42198
42199
42200                 function int64revrrot(dst, x, shift) {
42201                   dst.l = x.h >>> shift | x.l << 32 - shift;
42202                   dst.h = x.l >>> shift | x.h << 32 - shift;
42203                 } //Bitwise-shifts right a 64-bit number by shift
42204                 //Won't handle shift>=32, but it's never needed in SHA512
42205
42206
42207                 function int64shr(dst, x, shift) {
42208                   dst.l = x.l >>> shift | x.h << 32 - shift;
42209                   dst.h = x.h >>> shift;
42210                 } //Adds two 64-bit numbers
42211                 //Like the original implementation, does not rely on 32-bit operations
42212
42213
42214                 function int64add(dst, x, y) {
42215                   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
42216                   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
42217                   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
42218                   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
42219                   dst.l = w0 & 0xffff | w1 << 16;
42220                   dst.h = w2 & 0xffff | w3 << 16;
42221                 } //Same, except with 4 addends. Works faster than adding them one by one.
42222
42223
42224                 function int64add4(dst, a, b, c, d) {
42225                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
42226                   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
42227                   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
42228                   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
42229                   dst.l = w0 & 0xffff | w1 << 16;
42230                   dst.h = w2 & 0xffff | w3 << 16;
42231                 } //Same, except with 5 addends
42232
42233
42234                 function int64add5(dst, a, b, c, d, e) {
42235                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
42236                       w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
42237                       w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
42238                       w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
42239                   dst.l = w0 & 0xffff | w1 << 16;
42240                   dst.h = w2 & 0xffff | w3 << 16;
42241                 }
42242               },
42243
42244               /**
42245                * @class Hashes.RMD160
42246                * @constructor
42247                * @param {Object} [config]
42248                *
42249                * A JavaScript implementation of the RIPEMD-160 Algorithm
42250                * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
42251                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
42252                * See http://pajhome.org.uk/crypt/md5 for details.
42253                * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
42254                */
42255               RMD160: function RMD160(options) {
42256                 /**
42257                  * Private properties configuration variables. You may need to tweak these to be compatible with
42258                  * the server-side, but the defaults work in most cases.
42259                  * @see this.setUpperCase() method
42260                  * @see this.setPad() method
42261                  */
42262                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
42263
42264                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
42265                 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
42266
42267                 /* base-64 pad character. Default '=' for strict RFC compliance   */
42268                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
42269
42270                 /* enable/disable utf8 encoding */
42271                 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],
42272                     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],
42273                     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],
42274                     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];
42275                 /* privileged (public) methods */
42276
42277                 this.hex = function (s) {
42278                   return rstr2hex(rstr(s));
42279                 };
42280
42281                 this.b64 = function (s) {
42282                   return rstr2b64(rstr(s), b64pad);
42283                 };
42284
42285                 this.any = function (s, e) {
42286                   return rstr2any(rstr(s), e);
42287                 };
42288
42289                 this.raw = function (s) {
42290                   return rstr(s);
42291                 };
42292
42293                 this.hex_hmac = function (k, d) {
42294                   return rstr2hex(rstr_hmac(k, d));
42295                 };
42296
42297                 this.b64_hmac = function (k, d) {
42298                   return rstr2b64(rstr_hmac(k, d), b64pad);
42299                 };
42300
42301                 this.any_hmac = function (k, d, e) {
42302                   return rstr2any(rstr_hmac(k, d), e);
42303                 };
42304                 /**
42305                  * Perform a simple self-test to see if the VM is working
42306                  * @return {String} Hexadecimal hash sample
42307                  * @public
42308                  */
42309
42310
42311                 this.vm_test = function () {
42312                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
42313                 };
42314                 /**
42315                  * @description Enable/disable uppercase hexadecimal returned string
42316                  * @param {boolean}
42317                  * @return {Object} this
42318                  * @public
42319                  */
42320
42321
42322                 this.setUpperCase = function (a) {
42323                   if (typeof a === 'boolean') {
42324                     hexcase = a;
42325                   }
42326
42327                   return this;
42328                 };
42329                 /**
42330                  * @description Defines a base64 pad string
42331                  * @param {string} Pad
42332                  * @return {Object} this
42333                  * @public
42334                  */
42335
42336
42337                 this.setPad = function (a) {
42338                   if (typeof a !== 'undefined') {
42339                     b64pad = a;
42340                   }
42341
42342                   return this;
42343                 };
42344                 /**
42345                  * @description Defines a base64 pad string
42346                  * @param {boolean}
42347                  * @return {Object} this
42348                  * @public
42349                  */
42350
42351
42352                 this.setUTF8 = function (a) {
42353                   if (typeof a === 'boolean') {
42354                     utf8 = a;
42355                   }
42356
42357                   return this;
42358                 };
42359                 /* private methods */
42360
42361                 /**
42362                  * Calculate the rmd160 of a raw string
42363                  */
42364
42365
42366                 function rstr(s) {
42367                   s = utf8 ? utf8Encode(s) : s;
42368                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
42369                 }
42370                 /**
42371                  * Calculate the HMAC-rmd160 of a key and some data (raw strings)
42372                  */
42373
42374
42375                 function rstr_hmac(key, data) {
42376                   key = utf8 ? utf8Encode(key) : key;
42377                   data = utf8 ? utf8Encode(data) : data;
42378                   var i,
42379                       hash,
42380                       bkey = rstr2binl(key),
42381                       ipad = Array(16),
42382                       opad = Array(16);
42383
42384                   if (bkey.length > 16) {
42385                     bkey = binl(bkey, key.length * 8);
42386                   }
42387
42388                   for (i = 0; i < 16; i += 1) {
42389                     ipad[i] = bkey[i] ^ 0x36363636;
42390                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
42391                   }
42392
42393                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
42394                   return binl2rstr(binl(opad.concat(hash), 512 + 160));
42395                 }
42396                 /**
42397                  * Convert an array of little-endian words to a string
42398                  */
42399
42400
42401                 function binl2rstr(input) {
42402                   var i,
42403                       output = '',
42404                       l = input.length * 32;
42405
42406                   for (i = 0; i < l; i += 8) {
42407                     output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
42408                   }
42409
42410                   return output;
42411                 }
42412                 /**
42413                  * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
42414                  */
42415
42416
42417                 function binl(x, len) {
42418                   var T,
42419                       j,
42420                       i,
42421                       l,
42422                       h0 = 0x67452301,
42423                       h1 = 0xefcdab89,
42424                       h2 = 0x98badcfe,
42425                       h3 = 0x10325476,
42426                       h4 = 0xc3d2e1f0,
42427                       A1,
42428                       B1,
42429                       C1,
42430                       D1,
42431                       E1,
42432                       A2,
42433                       B2,
42434                       C2,
42435                       D2,
42436                       E2;
42437                   /* append padding */
42438
42439                   x[len >> 5] |= 0x80 << len % 32;
42440                   x[(len + 64 >>> 9 << 4) + 14] = len;
42441                   l = x.length;
42442
42443                   for (i = 0; i < l; i += 16) {
42444                     A1 = A2 = h0;
42445                     B1 = B2 = h1;
42446                     C1 = C2 = h2;
42447                     D1 = D2 = h3;
42448                     E1 = E2 = h4;
42449
42450                     for (j = 0; j <= 79; j += 1) {
42451                       T = safe_add(A1, rmd160_f(j, B1, C1, D1));
42452                       T = safe_add(T, x[i + rmd160_r1[j]]);
42453                       T = safe_add(T, rmd160_K1(j));
42454                       T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
42455                       A1 = E1;
42456                       E1 = D1;
42457                       D1 = bit_rol(C1, 10);
42458                       C1 = B1;
42459                       B1 = T;
42460                       T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
42461                       T = safe_add(T, x[i + rmd160_r2[j]]);
42462                       T = safe_add(T, rmd160_K2(j));
42463                       T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
42464                       A2 = E2;
42465                       E2 = D2;
42466                       D2 = bit_rol(C2, 10);
42467                       C2 = B2;
42468                       B2 = T;
42469                     }
42470
42471                     T = safe_add(h1, safe_add(C1, D2));
42472                     h1 = safe_add(h2, safe_add(D1, E2));
42473                     h2 = safe_add(h3, safe_add(E1, A2));
42474                     h3 = safe_add(h4, safe_add(A1, B2));
42475                     h4 = safe_add(h0, safe_add(B1, C2));
42476                     h0 = T;
42477                   }
42478
42479                   return [h0, h1, h2, h3, h4];
42480                 } // specific algorithm methods
42481
42482
42483                 function rmd160_f(j, x, y, z) {
42484                   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';
42485                 }
42486
42487                 function rmd160_K1(j) {
42488                   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';
42489                 }
42490
42491                 function rmd160_K2(j) {
42492                   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';
42493                 }
42494               }
42495             }; // exposes Hashes
42496
42497             (function (window, undefined$1) {
42498               var freeExports = false;
42499
42500               {
42501                 freeExports = exports;
42502
42503                 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
42504                   window = commonjsGlobal;
42505                 }
42506               }
42507
42508               if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
42509                 // define as an anonymous module, so, through path mapping, it can be aliased
42510                 undefined$1(function () {
42511                   return Hashes;
42512                 });
42513               } else if (freeExports) {
42514                 // in Node.js or RingoJS v0.8.0+
42515                 if ( module && module.exports === freeExports) {
42516                   module.exports = Hashes;
42517                 } // in Narwhal or RingoJS v0.7.0-
42518                 else {
42519                     freeExports.Hashes = Hashes;
42520                   }
42521               } else {
42522                 // in a browser or Rhino
42523                 window.Hashes = Hashes;
42524               }
42525             })(this);
42526           })(); // IIFE
42527
42528         });
42529
42530         var immutable = extend$2;
42531         var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
42532
42533         function extend$2() {
42534           var target = {};
42535
42536           for (var i = 0; i < arguments.length; i++) {
42537             var source = arguments[i];
42538
42539             for (var key in source) {
42540               if (hasOwnProperty$2.call(source, key)) {
42541                 target[key] = source[key];
42542               }
42543             }
42544           }
42545
42546           return target;
42547         }
42548
42549         var sha1 = new hashes.SHA1();
42550         var ohauth = {};
42551
42552         ohauth.qsString = function (obj) {
42553           return Object.keys(obj).sort().map(function (key) {
42554             return ohauth.percentEncode(key) + '=' + ohauth.percentEncode(obj[key]);
42555           }).join('&');
42556         };
42557
42558         ohauth.stringQs = function (str) {
42559           return str.split('&').filter(function (pair) {
42560             return pair !== '';
42561           }).reduce(function (obj, pair) {
42562             var parts = pair.split('=');
42563             obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
42564             return obj;
42565           }, {});
42566         };
42567
42568         ohauth.rawxhr = function (method, url, data, headers, callback) {
42569           var xhr = new XMLHttpRequest(),
42570               twoHundred = /^20\d$/;
42571
42572           xhr.onreadystatechange = function () {
42573             if (4 === xhr.readyState && 0 !== xhr.status) {
42574               if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
42575             }
42576           };
42577
42578           xhr.onerror = function (e) {
42579             return callback(e, null);
42580           };
42581
42582           xhr.open(method, url, true);
42583
42584           for (var h in headers) {
42585             xhr.setRequestHeader(h, headers[h]);
42586           }
42587
42588           xhr.send(data);
42589           return xhr;
42590         };
42591
42592         ohauth.xhr = function (method, url, auth, data, options, callback) {
42593           var headers = options && options.header || {
42594             'Content-Type': 'application/x-www-form-urlencoded'
42595           };
42596           headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
42597           return ohauth.rawxhr(method, url, data, headers, callback);
42598         };
42599
42600         ohauth.nonce = function () {
42601           for (var o = ''; o.length < 6;) {
42602             o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
42603           }
42604
42605           return o;
42606         };
42607
42608         ohauth.authHeader = function (obj) {
42609           return Object.keys(obj).sort().map(function (key) {
42610             return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
42611           }).join(', ');
42612         };
42613
42614         ohauth.timestamp = function () {
42615           return ~~(+new Date() / 1000);
42616         };
42617
42618         ohauth.percentEncode = function (s) {
42619           return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
42620         };
42621
42622         ohauth.baseString = function (method, url, params) {
42623           if (params.oauth_signature) delete params.oauth_signature;
42624           return [method, ohauth.percentEncode(url), ohauth.percentEncode(ohauth.qsString(params))].join('&');
42625         };
42626
42627         ohauth.signature = function (oauth_secret, token_secret, baseString) {
42628           return sha1.b64_hmac(ohauth.percentEncode(oauth_secret) + '&' + ohauth.percentEncode(token_secret), baseString);
42629         };
42630         /**
42631          * Takes an options object for configuration (consumer_key,
42632          * consumer_secret, version, signature_method, token, token_secret)
42633          * and returns a function that generates the Authorization header
42634          * for given data.
42635          *
42636          * The returned function takes these parameters:
42637          * - method: GET/POST/...
42638          * - uri: full URI with protocol, port, path and query string
42639          * - extra_params: any extra parameters (that are passed in the POST data),
42640          *   can be an object or a from-urlencoded string.
42641          *
42642          * Returned function returns full OAuth header with "OAuth" string in it.
42643          */
42644
42645
42646         ohauth.headerGenerator = function (options) {
42647           options = options || {};
42648           var consumer_key = options.consumer_key || '',
42649               consumer_secret = options.consumer_secret || '',
42650               signature_method = options.signature_method || 'HMAC-SHA1',
42651               version = options.version || '1.0',
42652               token = options.token || '',
42653               token_secret = options.token_secret || '';
42654           return function (method, uri, extra_params) {
42655             method = method.toUpperCase();
42656
42657             if (typeof extra_params === 'string' && extra_params.length > 0) {
42658               extra_params = ohauth.stringQs(extra_params);
42659             }
42660
42661             var uri_parts = uri.split('?', 2),
42662                 base_uri = uri_parts[0];
42663             var query_params = uri_parts.length === 2 ? ohauth.stringQs(uri_parts[1]) : {};
42664             var oauth_params = {
42665               oauth_consumer_key: consumer_key,
42666               oauth_signature_method: signature_method,
42667               oauth_version: version,
42668               oauth_timestamp: ohauth.timestamp(),
42669               oauth_nonce: ohauth.nonce()
42670             };
42671             if (token) oauth_params.oauth_token = token;
42672             var all_params = immutable({}, oauth_params, query_params, extra_params),
42673                 base_str = ohauth.baseString(method, base_uri, all_params);
42674             oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
42675             return 'OAuth ' + ohauth.authHeader(oauth_params);
42676           };
42677         };
42678
42679         var ohauth_1 = ohauth;
42680
42681         var resolveUrl$1 = createCommonjsModule(function (module, exports) {
42682           // Copyright 2014 Simon Lydell
42683           // X11 (“MIT”) Licensed. (See LICENSE.)
42684           void function (root, factory) {
42685             {
42686               module.exports = factory();
42687             }
42688           }(commonjsGlobal, function () {
42689             function resolveUrl()
42690             /* ...urls */
42691             {
42692               var numUrls = arguments.length;
42693
42694               if (numUrls === 0) {
42695                 throw new Error("resolveUrl requires at least one argument; got none.");
42696               }
42697
42698               var base = document.createElement("base");
42699               base.href = arguments[0];
42700
42701               if (numUrls === 1) {
42702                 return base.href;
42703               }
42704
42705               var head = document.getElementsByTagName("head")[0];
42706               head.insertBefore(base, head.firstChild);
42707               var a = document.createElement("a");
42708               var resolved;
42709
42710               for (var index = 1; index < numUrls; index++) {
42711                 a.href = arguments[index];
42712                 resolved = a.href;
42713                 base.href = resolved;
42714               }
42715
42716               head.removeChild(base);
42717               return resolved;
42718             }
42719
42720             return resolveUrl;
42721           });
42722         });
42723
42724         var assign = make_assign();
42725         var create$1 = make_create();
42726         var trim$3 = make_trim();
42727         var Global = typeof window !== 'undefined' ? window : commonjsGlobal;
42728         var util = {
42729           assign: assign,
42730           create: create$1,
42731           trim: trim$3,
42732           bind: bind$1,
42733           slice: slice$2,
42734           each: each,
42735           map: map$1,
42736           pluck: pluck,
42737           isList: isList,
42738           isFunction: isFunction,
42739           isObject: isObject$2,
42740           Global: Global
42741         };
42742
42743         function make_assign() {
42744           if (Object.assign) {
42745             return Object.assign;
42746           } else {
42747             return function shimAssign(obj, props1, props2, etc) {
42748               for (var i = 1; i < arguments.length; i++) {
42749                 each(Object(arguments[i]), function (val, key) {
42750                   obj[key] = val;
42751                 });
42752               }
42753
42754               return obj;
42755             };
42756           }
42757         }
42758
42759         function make_create() {
42760           if (Object.create) {
42761             return function create(obj, assignProps1, assignProps2, etc) {
42762               var assignArgsList = slice$2(arguments, 1);
42763               return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
42764             };
42765           } else {
42766             var F = function F() {}; // eslint-disable-line no-inner-declarations
42767
42768
42769             return function create(obj, assignProps1, assignProps2, etc) {
42770               var assignArgsList = slice$2(arguments, 1);
42771               F.prototype = obj;
42772               return assign.apply(this, [new F()].concat(assignArgsList));
42773             };
42774           }
42775         }
42776
42777         function make_trim() {
42778           if (String.prototype.trim) {
42779             return function trim(str) {
42780               return String.prototype.trim.call(str);
42781             };
42782           } else {
42783             return function trim(str) {
42784               return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
42785             };
42786           }
42787         }
42788
42789         function bind$1(obj, fn) {
42790           return function () {
42791             return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
42792           };
42793         }
42794
42795         function slice$2(arr, index) {
42796           return Array.prototype.slice.call(arr, index || 0);
42797         }
42798
42799         function each(obj, fn) {
42800           pluck(obj, function (val, key) {
42801             fn(val, key);
42802             return false;
42803           });
42804         }
42805
42806         function map$1(obj, fn) {
42807           var res = isList(obj) ? [] : {};
42808           pluck(obj, function (v, k) {
42809             res[k] = fn(v, k);
42810             return false;
42811           });
42812           return res;
42813         }
42814
42815         function pluck(obj, fn) {
42816           if (isList(obj)) {
42817             for (var i = 0; i < obj.length; i++) {
42818               if (fn(obj[i], i)) {
42819                 return obj[i];
42820               }
42821             }
42822           } else {
42823             for (var key in obj) {
42824               if (obj.hasOwnProperty(key)) {
42825                 if (fn(obj[key], key)) {
42826                   return obj[key];
42827                 }
42828               }
42829             }
42830           }
42831         }
42832
42833         function isList(val) {
42834           return val != null && typeof val != 'function' && typeof val.length == 'number';
42835         }
42836
42837         function isFunction(val) {
42838           return val && {}.toString.call(val) === '[object Function]';
42839         }
42840
42841         function isObject$2(val) {
42842           return val && {}.toString.call(val) === '[object Object]';
42843         }
42844
42845         var slice$3 = util.slice;
42846         var pluck$1 = util.pluck;
42847         var each$1 = util.each;
42848         var bind$2 = util.bind;
42849         var create$2 = util.create;
42850         var isList$1 = util.isList;
42851         var isFunction$1 = util.isFunction;
42852         var isObject$3 = util.isObject;
42853         var storeEngine = {
42854           createStore: _createStore
42855         };
42856         var storeAPI = {
42857           version: '2.0.12',
42858           enabled: false,
42859           // get returns the value of the given key. If that value
42860           // is undefined, it returns optionalDefaultValue instead.
42861           get: function get(key, optionalDefaultValue) {
42862             var data = this.storage.read(this._namespacePrefix + key);
42863             return this._deserialize(data, optionalDefaultValue);
42864           },
42865           // set will store the given value at key and returns value.
42866           // Calling set with value === undefined is equivalent to calling remove.
42867           set: function set(key, value) {
42868             if (value === undefined) {
42869               return this.remove(key);
42870             }
42871
42872             this.storage.write(this._namespacePrefix + key, this._serialize(value));
42873             return value;
42874           },
42875           // remove deletes the key and value stored at the given key.
42876           remove: function remove(key) {
42877             this.storage.remove(this._namespacePrefix + key);
42878           },
42879           // each will call the given callback once for each key-value pair
42880           // in this store.
42881           each: function each(callback) {
42882             var self = this;
42883             this.storage.each(function (val, namespacedKey) {
42884               callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
42885             });
42886           },
42887           // clearAll will remove all the stored key-value pairs in this store.
42888           clearAll: function clearAll() {
42889             this.storage.clearAll();
42890           },
42891           // additional functionality that can't live in plugins
42892           // ---------------------------------------------------
42893           // hasNamespace returns true if this store instance has the given namespace.
42894           hasNamespace: function hasNamespace(namespace) {
42895             return this._namespacePrefix == '__storejs_' + namespace + '_';
42896           },
42897           // createStore creates a store.js instance with the first
42898           // functioning storage in the list of storage candidates,
42899           // and applies the the given mixins to the instance.
42900           createStore: function createStore() {
42901             return _createStore.apply(this, arguments);
42902           },
42903           addPlugin: function addPlugin(plugin) {
42904             this._addPlugin(plugin);
42905           },
42906           namespace: function namespace(_namespace) {
42907             return _createStore(this.storage, this.plugins, _namespace);
42908           }
42909         };
42910
42911         function _warn() {
42912           var _console = typeof console == 'undefined' ? null : console;
42913
42914           if (!_console) {
42915             return;
42916           }
42917
42918           var fn = _console.warn ? _console.warn : _console.log;
42919           fn.apply(_console, arguments);
42920         }
42921
42922         function _createStore(storages, plugins, namespace) {
42923           if (!namespace) {
42924             namespace = '';
42925           }
42926
42927           if (storages && !isList$1(storages)) {
42928             storages = [storages];
42929           }
42930
42931           if (plugins && !isList$1(plugins)) {
42932             plugins = [plugins];
42933           }
42934
42935           var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
42936           var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
42937           var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
42938
42939           if (!legalNamespaces.test(namespace)) {
42940             throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
42941           }
42942
42943           var _privateStoreProps = {
42944             _namespacePrefix: namespacePrefix,
42945             _namespaceRegexp: namespaceRegexp,
42946             _testStorage: function _testStorage(storage) {
42947               try {
42948                 var testStr = '__storejs__test__';
42949                 storage.write(testStr, testStr);
42950                 var ok = storage.read(testStr) === testStr;
42951                 storage.remove(testStr);
42952                 return ok;
42953               } catch (e) {
42954                 return false;
42955               }
42956             },
42957             _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
42958               var oldFn = this[propName];
42959
42960               this[propName] = function pluginFn() {
42961                 var args = slice$3(arguments, 0);
42962                 var self = this; // super_fn calls the old function which was overwritten by
42963                 // this mixin.
42964
42965                 function super_fn() {
42966                   if (!oldFn) {
42967                     return;
42968                   }
42969
42970                   each$1(arguments, function (arg, i) {
42971                     args[i] = arg;
42972                   });
42973                   return oldFn.apply(self, args);
42974                 } // Give mixing function access to super_fn by prefixing all mixin function
42975                 // arguments with super_fn.
42976
42977
42978                 var newFnArgs = [super_fn].concat(args);
42979                 return pluginFnProp.apply(self, newFnArgs);
42980               };
42981             },
42982             _serialize: function _serialize(obj) {
42983               return JSON.stringify(obj);
42984             },
42985             _deserialize: function _deserialize(strVal, defaultVal) {
42986               if (!strVal) {
42987                 return defaultVal;
42988               } // It is possible that a raw string value has been previously stored
42989               // in a storage without using store.js, meaning it will be a raw
42990               // string value instead of a JSON serialized string. By defaulting
42991               // to the raw string value in case of a JSON parse error, we allow
42992               // for past stored values to be forwards-compatible with store.js
42993
42994
42995               var val = '';
42996
42997               try {
42998                 val = JSON.parse(strVal);
42999               } catch (e) {
43000                 val = strVal;
43001               }
43002
43003               return val !== undefined ? val : defaultVal;
43004             },
43005             _addStorage: function _addStorage(storage) {
43006               if (this.enabled) {
43007                 return;
43008               }
43009
43010               if (this._testStorage(storage)) {
43011                 this.storage = storage;
43012                 this.enabled = true;
43013               }
43014             },
43015             _addPlugin: function _addPlugin(plugin) {
43016               var self = this; // If the plugin is an array, then add all plugins in the array.
43017               // This allows for a plugin to depend on other plugins.
43018
43019               if (isList$1(plugin)) {
43020                 each$1(plugin, function (plugin) {
43021                   self._addPlugin(plugin);
43022                 });
43023                 return;
43024               } // Keep track of all plugins we've seen so far, so that we
43025               // don't add any of them twice.
43026
43027
43028               var seenPlugin = pluck$1(this.plugins, function (seenPlugin) {
43029                 return plugin === seenPlugin;
43030               });
43031
43032               if (seenPlugin) {
43033                 return;
43034               }
43035
43036               this.plugins.push(plugin); // Check that the plugin is properly formed
43037
43038               if (!isFunction$1(plugin)) {
43039                 throw new Error('Plugins must be function values that return objects');
43040               }
43041
43042               var pluginProperties = plugin.call(this);
43043
43044               if (!isObject$3(pluginProperties)) {
43045                 throw new Error('Plugins must return an object of function properties');
43046               } // Add the plugin function properties to this store instance.
43047
43048
43049               each$1(pluginProperties, function (pluginFnProp, propName) {
43050                 if (!isFunction$1(pluginFnProp)) {
43051                   throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
43052                 }
43053
43054                 self._assignPluginFnProp(pluginFnProp, propName);
43055               });
43056             },
43057             // Put deprecated properties in the private API, so as to not expose it to accidential
43058             // discovery through inspection of the store object.
43059             // Deprecated: addStorage
43060             addStorage: function addStorage(storage) {
43061               _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
43062
43063               this._addStorage(storage);
43064             }
43065           };
43066           var store = create$2(_privateStoreProps, storeAPI, {
43067             plugins: []
43068           });
43069           store.raw = {};
43070           each$1(store, function (prop, propName) {
43071             if (isFunction$1(prop)) {
43072               store.raw[propName] = bind$2(store, prop);
43073             }
43074           });
43075           each$1(storages, function (storage) {
43076             store._addStorage(storage);
43077           });
43078           each$1(plugins, function (plugin) {
43079             store._addPlugin(plugin);
43080           });
43081           return store;
43082         }
43083
43084         var Global$1 = util.Global;
43085         var localStorage_1 = {
43086           name: 'localStorage',
43087           read: read,
43088           write: write,
43089           each: each$2,
43090           remove: remove$2,
43091           clearAll: clearAll
43092         };
43093
43094         function localStorage$1() {
43095           return Global$1.localStorage;
43096         }
43097
43098         function read(key) {
43099           return localStorage$1().getItem(key);
43100         }
43101
43102         function write(key, data) {
43103           return localStorage$1().setItem(key, data);
43104         }
43105
43106         function each$2(fn) {
43107           for (var i = localStorage$1().length - 1; i >= 0; i--) {
43108             var key = localStorage$1().key(i);
43109             fn(read(key), key);
43110           }
43111         }
43112
43113         function remove$2(key) {
43114           return localStorage$1().removeItem(key);
43115         }
43116
43117         function clearAll() {
43118           return localStorage$1().clear();
43119         }
43120
43121         // versions 6 and 7, where no localStorage, etc
43122         // is available.
43123
43124         var Global$2 = util.Global;
43125         var oldFFGlobalStorage = {
43126           name: 'oldFF-globalStorage',
43127           read: read$1,
43128           write: write$1,
43129           each: each$3,
43130           remove: remove$3,
43131           clearAll: clearAll$1
43132         };
43133         var globalStorage = Global$2.globalStorage;
43134
43135         function read$1(key) {
43136           return globalStorage[key];
43137         }
43138
43139         function write$1(key, data) {
43140           globalStorage[key] = data;
43141         }
43142
43143         function each$3(fn) {
43144           for (var i = globalStorage.length - 1; i >= 0; i--) {
43145             var key = globalStorage.key(i);
43146             fn(globalStorage[key], key);
43147           }
43148         }
43149
43150         function remove$3(key) {
43151           return globalStorage.removeItem(key);
43152         }
43153
43154         function clearAll$1() {
43155           each$3(function (key, _) {
43156             delete globalStorage[key];
43157           });
43158         }
43159
43160         // versions 6 and 7, where no localStorage, sessionStorage, etc
43161         // is available.
43162
43163         var Global$3 = util.Global;
43164         var oldIEUserDataStorage = {
43165           name: 'oldIE-userDataStorage',
43166           write: write$2,
43167           read: read$2,
43168           each: each$4,
43169           remove: remove$4,
43170           clearAll: clearAll$2
43171         };
43172         var storageName = 'storejs';
43173         var doc = Global$3.document;
43174
43175         var _withStorageEl = _makeIEStorageElFunction();
43176
43177         var disable = (Global$3.navigator ? Global$3.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
43178
43179         function write$2(unfixedKey, data) {
43180           if (disable) {
43181             return;
43182           }
43183
43184           var fixedKey = fixKey(unfixedKey);
43185
43186           _withStorageEl(function (storageEl) {
43187             storageEl.setAttribute(fixedKey, data);
43188             storageEl.save(storageName);
43189           });
43190         }
43191
43192         function read$2(unfixedKey) {
43193           if (disable) {
43194             return;
43195           }
43196
43197           var fixedKey = fixKey(unfixedKey);
43198           var res = null;
43199
43200           _withStorageEl(function (storageEl) {
43201             res = storageEl.getAttribute(fixedKey);
43202           });
43203
43204           return res;
43205         }
43206
43207         function each$4(callback) {
43208           _withStorageEl(function (storageEl) {
43209             var attributes = storageEl.XMLDocument.documentElement.attributes;
43210
43211             for (var i = attributes.length - 1; i >= 0; i--) {
43212               var attr = attributes[i];
43213               callback(storageEl.getAttribute(attr.name), attr.name);
43214             }
43215           });
43216         }
43217
43218         function remove$4(unfixedKey) {
43219           var fixedKey = fixKey(unfixedKey);
43220
43221           _withStorageEl(function (storageEl) {
43222             storageEl.removeAttribute(fixedKey);
43223             storageEl.save(storageName);
43224           });
43225         }
43226
43227         function clearAll$2() {
43228           _withStorageEl(function (storageEl) {
43229             var attributes = storageEl.XMLDocument.documentElement.attributes;
43230             storageEl.load(storageName);
43231
43232             for (var i = attributes.length - 1; i >= 0; i--) {
43233               storageEl.removeAttribute(attributes[i].name);
43234             }
43235
43236             storageEl.save(storageName);
43237           });
43238         } // Helpers
43239         //////////
43240         // In IE7, keys cannot start with a digit or contain certain chars.
43241         // See https://github.com/marcuswestin/store.js/issues/40
43242         // See https://github.com/marcuswestin/store.js/issues/83
43243
43244
43245         var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
43246
43247         function fixKey(key) {
43248           return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
43249         }
43250
43251         function _makeIEStorageElFunction() {
43252           if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
43253             return null;
43254           }
43255
43256           var scriptTag = 'script',
43257               storageOwner,
43258               storageContainer,
43259               storageEl; // Since #userData storage applies only to specific paths, we need to
43260           // somehow link our data to a specific path.  We choose /favicon.ico
43261           // as a pretty safe option, since all browsers already make a request to
43262           // this URL anyway and being a 404 will not hurt us here.  We wrap an
43263           // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
43264           // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
43265           // since the iframe access rules appear to allow direct access and
43266           // manipulation of the document element, even for a 404 page.  This
43267           // document can be used instead of the current document (which would
43268           // have been limited to the current path) to perform #userData storage.
43269
43270           try {
43271             /* global ActiveXObject */
43272             storageContainer = new ActiveXObject('htmlfile');
43273             storageContainer.open();
43274             storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
43275             storageContainer.close();
43276             storageOwner = storageContainer.w.frames[0].document;
43277             storageEl = storageOwner.createElement('div');
43278           } catch (e) {
43279             // somehow ActiveXObject instantiation failed (perhaps some special
43280             // security settings or otherwse), fall back to per-path storage
43281             storageEl = doc.createElement('div');
43282             storageOwner = doc.body;
43283           }
43284
43285           return function (storeFunction) {
43286             var args = [].slice.call(arguments, 0);
43287             args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
43288             // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
43289
43290             storageOwner.appendChild(storageEl);
43291             storageEl.addBehavior('#default#userData');
43292             storageEl.load(storageName);
43293             storeFunction.apply(this, args);
43294             storageOwner.removeChild(storageEl);
43295             return;
43296           };
43297         }
43298
43299         // doesn't work but cookies do. This implementation is adopted from
43300         // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
43301
43302         var Global$4 = util.Global;
43303         var trim$4 = util.trim;
43304         var cookieStorage = {
43305           name: 'cookieStorage',
43306           read: read$3,
43307           write: write$3,
43308           each: each$5,
43309           remove: remove$5,
43310           clearAll: clearAll$3
43311         };
43312         var doc$1 = Global$4.document;
43313
43314         function read$3(key) {
43315           if (!key || !_has(key)) {
43316             return null;
43317           }
43318
43319           var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
43320           return unescape(doc$1.cookie.replace(new RegExp(regexpStr), "$1"));
43321         }
43322
43323         function each$5(callback) {
43324           var cookies = doc$1.cookie.split(/; ?/g);
43325
43326           for (var i = cookies.length - 1; i >= 0; i--) {
43327             if (!trim$4(cookies[i])) {
43328               continue;
43329             }
43330
43331             var kvp = cookies[i].split('=');
43332             var key = unescape(kvp[0]);
43333             var val = unescape(kvp[1]);
43334             callback(val, key);
43335           }
43336         }
43337
43338         function write$3(key, data) {
43339           if (!key) {
43340             return;
43341           }
43342
43343           doc$1.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
43344         }
43345
43346         function remove$5(key) {
43347           if (!key || !_has(key)) {
43348             return;
43349           }
43350
43351           doc$1.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
43352         }
43353
43354         function clearAll$3() {
43355           each$5(function (_, key) {
43356             remove$5(key);
43357           });
43358         }
43359
43360         function _has(key) {
43361           return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc$1.cookie);
43362         }
43363
43364         var Global$5 = util.Global;
43365         var sessionStorage_1 = {
43366           name: 'sessionStorage',
43367           read: read$4,
43368           write: write$4,
43369           each: each$6,
43370           remove: remove$6,
43371           clearAll: clearAll$4
43372         };
43373
43374         function sessionStorage() {
43375           return Global$5.sessionStorage;
43376         }
43377
43378         function read$4(key) {
43379           return sessionStorage().getItem(key);
43380         }
43381
43382         function write$4(key, data) {
43383           return sessionStorage().setItem(key, data);
43384         }
43385
43386         function each$6(fn) {
43387           for (var i = sessionStorage().length - 1; i >= 0; i--) {
43388             var key = sessionStorage().key(i);
43389             fn(read$4(key), key);
43390           }
43391         }
43392
43393         function remove$6(key) {
43394           return sessionStorage().removeItem(key);
43395         }
43396
43397         function clearAll$4() {
43398           return sessionStorage().clear();
43399         }
43400
43401         // memoryStorage is a useful last fallback to ensure that the store
43402         // is functions (meaning store.get(), store.set(), etc will all function).
43403         // However, stored values will not persist when the browser navigates to
43404         // a new page or reloads the current page.
43405         var memoryStorage_1 = {
43406           name: 'memoryStorage',
43407           read: read$5,
43408           write: write$5,
43409           each: each$7,
43410           remove: remove$7,
43411           clearAll: clearAll$5
43412         };
43413         var memoryStorage = {};
43414
43415         function read$5(key) {
43416           return memoryStorage[key];
43417         }
43418
43419         function write$5(key, data) {
43420           memoryStorage[key] = data;
43421         }
43422
43423         function each$7(callback) {
43424           for (var key in memoryStorage) {
43425             if (memoryStorage.hasOwnProperty(key)) {
43426               callback(memoryStorage[key], key);
43427             }
43428           }
43429         }
43430
43431         function remove$7(key) {
43432           delete memoryStorage[key];
43433         }
43434
43435         function clearAll$5(key) {
43436           memoryStorage = {};
43437         }
43438
43439         var all = [// Listed in order of usage preference
43440         localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
43441
43442         /* eslint-disable */
43443         //  json2.js
43444         //  2016-10-28
43445         //  Public Domain.
43446         //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
43447         //  See http://www.JSON.org/js.html
43448         //  This code should be minified before deployment.
43449         //  See http://javascript.crockford.com/jsmin.html
43450         //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
43451         //  NOT CONTROL.
43452         //  This file creates a global JSON object containing two methods: stringify
43453         //  and parse. This file provides the ES5 JSON capability to ES3 systems.
43454         //  If a project might run on IE8 or earlier, then this file should be included.
43455         //  This file does nothing on ES5 systems.
43456         //      JSON.stringify(value, replacer, space)
43457         //          value       any JavaScript value, usually an object or array.
43458         //          replacer    an optional parameter that determines how object
43459         //                      values are stringified for objects. It can be a
43460         //                      function or an array of strings.
43461         //          space       an optional parameter that specifies the indentation
43462         //                      of nested structures. If it is omitted, the text will
43463         //                      be packed without extra whitespace. If it is a number,
43464         //                      it will specify the number of spaces to indent at each
43465         //                      level. If it is a string (such as "\t" or "&nbsp;"),
43466         //                      it contains the characters used to indent at each level.
43467         //          This method produces a JSON text from a JavaScript value.
43468         //          When an object value is found, if the object contains a toJSON
43469         //          method, its toJSON method will be called and the result will be
43470         //          stringified. A toJSON method does not serialize: it returns the
43471         //          value represented by the name/value pair that should be serialized,
43472         //          or undefined if nothing should be serialized. The toJSON method
43473         //          will be passed the key associated with the value, and this will be
43474         //          bound to the value.
43475         //          For example, this would serialize Dates as ISO strings.
43476         //              Date.prototype.toJSON = function (key) {
43477         //                  function f(n) {
43478         //                      // Format integers to have at least two digits.
43479         //                      return (n < 10)
43480         //                          ? "0" + n
43481         //                          : n;
43482         //                  }
43483         //                  return this.getUTCFullYear()   + "-" +
43484         //                       f(this.getUTCMonth() + 1) + "-" +
43485         //                       f(this.getUTCDate())      + "T" +
43486         //                       f(this.getUTCHours())     + ":" +
43487         //                       f(this.getUTCMinutes())   + ":" +
43488         //                       f(this.getUTCSeconds())   + "Z";
43489         //              };
43490         //          You can provide an optional replacer method. It will be passed the
43491         //          key and value of each member, with this bound to the containing
43492         //          object. The value that is returned from your method will be
43493         //          serialized. If your method returns undefined, then the member will
43494         //          be excluded from the serialization.
43495         //          If the replacer parameter is an array of strings, then it will be
43496         //          used to select the members to be serialized. It filters the results
43497         //          such that only members with keys listed in the replacer array are
43498         //          stringified.
43499         //          Values that do not have JSON representations, such as undefined or
43500         //          functions, will not be serialized. Such values in objects will be
43501         //          dropped; in arrays they will be replaced with null. You can use
43502         //          a replacer function to replace those with JSON values.
43503         //          JSON.stringify(undefined) returns undefined.
43504         //          The optional space parameter produces a stringification of the
43505         //          value that is filled with line breaks and indentation to make it
43506         //          easier to read.
43507         //          If the space parameter is a non-empty string, then that string will
43508         //          be used for indentation. If the space parameter is a number, then
43509         //          the indentation will be that many spaces.
43510         //          Example:
43511         //          text = JSON.stringify(["e", {pluribus: "unum"}]);
43512         //          // text is '["e",{"pluribus":"unum"}]'
43513         //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
43514         //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
43515         //          text = JSON.stringify([new Date()], function (key, value) {
43516         //              return this[key] instanceof Date
43517         //                  ? "Date(" + this[key] + ")"
43518         //                  : value;
43519         //          });
43520         //          // text is '["Date(---current time---)"]'
43521         //      JSON.parse(text, reviver)
43522         //          This method parses a JSON text to produce an object or array.
43523         //          It can throw a SyntaxError exception.
43524         //          The optional reviver parameter is a function that can filter and
43525         //          transform the results. It receives each of the keys and values,
43526         //          and its return value is used instead of the original value.
43527         //          If it returns what it received, then the structure is not modified.
43528         //          If it returns undefined then the member is deleted.
43529         //          Example:
43530         //          // Parse the text. Values that look like ISO date strings will
43531         //          // be converted to Date objects.
43532         //          myData = JSON.parse(text, function (key, value) {
43533         //              var a;
43534         //              if (typeof value === "string") {
43535         //                  a =
43536         //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
43537         //                  if (a) {
43538         //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
43539         //                          +a[5], +a[6]));
43540         //                  }
43541         //              }
43542         //              return value;
43543         //          });
43544         //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
43545         //              var d;
43546         //              if (typeof value === "string" &&
43547         //                      value.slice(0, 5) === "Date(" &&
43548         //                      value.slice(-1) === ")") {
43549         //                  d = new Date(value.slice(5, -1));
43550         //                  if (d) {
43551         //                      return d;
43552         //                  }
43553         //              }
43554         //              return value;
43555         //          });
43556         //  This is a reference implementation. You are free to copy, modify, or
43557         //  redistribute.
43558
43559         /*jslint
43560             eval, for, this
43561         */
43562
43563         /*property
43564             JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
43565             getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
43566             lastIndex, length, parse, prototype, push, replace, slice, stringify,
43567             test, toJSON, toString, valueOf
43568         */
43569         // Create a JSON object only if one does not already exist. We create the
43570         // methods in a closure to avoid creating global variables.
43571         if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
43572           JSON = {};
43573         }
43574
43575         (function () {
43576
43577           var rx_one = /^[\],:{}\s]*$/;
43578           var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
43579           var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
43580           var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
43581           var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43582           var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43583
43584           function f(n) {
43585             // Format integers to have at least two digits.
43586             return n < 10 ? "0" + n : n;
43587           }
43588
43589           function this_value() {
43590             return this.valueOf();
43591           }
43592
43593           if (typeof Date.prototype.toJSON !== "function") {
43594             Date.prototype.toJSON = function () {
43595               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;
43596             };
43597
43598             Boolean.prototype.toJSON = this_value;
43599             Number.prototype.toJSON = this_value;
43600             String.prototype.toJSON = this_value;
43601           }
43602
43603           var gap;
43604           var indent;
43605           var meta;
43606           var rep;
43607
43608           function quote(string) {
43609             // If the string contains no control characters, no quote characters, and no
43610             // backslash characters, then we can safely slap some quotes around it.
43611             // Otherwise we must also replace the offending characters with safe escape
43612             // sequences.
43613             rx_escapable.lastIndex = 0;
43614             return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
43615               var c = meta[a];
43616               return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43617             }) + "\"" : "\"" + string + "\"";
43618           }
43619
43620           function str(key, holder) {
43621             // Produce a string from holder[key].
43622             var i; // The loop counter.
43623
43624             var k; // The member key.
43625
43626             var v; // The member value.
43627
43628             var length;
43629             var mind = gap;
43630             var partial;
43631             var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
43632
43633             if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
43634               value = value.toJSON(key);
43635             } // If we were called with a replacer function, then call the replacer to
43636             // obtain a replacement value.
43637
43638
43639             if (typeof rep === "function") {
43640               value = rep.call(holder, key, value);
43641             } // What happens next depends on the value's type.
43642
43643
43644             switch (_typeof(value)) {
43645               case "string":
43646                 return quote(value);
43647
43648               case "number":
43649                 // JSON numbers must be finite. Encode non-finite numbers as null.
43650                 return isFinite(value) ? String(value) : "null";
43651
43652               case "boolean":
43653               case "null":
43654                 // If the value is a boolean or null, convert it to a string. Note:
43655                 // typeof null does not produce "null". The case is included here in
43656                 // the remote chance that this gets fixed someday.
43657                 return String(value);
43658               // If the type is "object", we might be dealing with an object or an array or
43659               // null.
43660
43661               case "object":
43662                 // Due to a specification blunder in ECMAScript, typeof null is "object",
43663                 // so watch out for that case.
43664                 if (!value) {
43665                   return "null";
43666                 } // Make an array to hold the partial results of stringifying this object value.
43667
43668
43669                 gap += indent;
43670                 partial = []; // Is the value an array?
43671
43672                 if (Object.prototype.toString.apply(value) === "[object Array]") {
43673                   // The value is an array. Stringify every element. Use null as a placeholder
43674                   // for non-JSON values.
43675                   length = value.length;
43676
43677                   for (i = 0; i < length; i += 1) {
43678                     partial[i] = str(i, value) || "null";
43679                   } // Join all of the elements together, separated with commas, and wrap them in
43680                   // brackets.
43681
43682
43683                   v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
43684                   gap = mind;
43685                   return v;
43686                 } // If the replacer is an array, use it to select the members to be stringified.
43687
43688
43689                 if (rep && _typeof(rep) === "object") {
43690                   length = rep.length;
43691
43692                   for (i = 0; i < length; i += 1) {
43693                     if (typeof rep[i] === "string") {
43694                       k = rep[i];
43695                       v = str(k, value);
43696
43697                       if (v) {
43698                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43699                       }
43700                     }
43701                   }
43702                 } else {
43703                   // Otherwise, iterate through all of the keys in the object.
43704                   for (k in value) {
43705                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43706                       v = str(k, value);
43707
43708                       if (v) {
43709                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43710                       }
43711                     }
43712                   }
43713                 } // Join all of the member texts together, separated with commas,
43714                 // and wrap them in braces.
43715
43716
43717                 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
43718                 gap = mind;
43719                 return v;
43720             }
43721           } // If the JSON object does not yet have a stringify method, give it one.
43722
43723
43724           if (typeof JSON.stringify !== "function") {
43725             meta = {
43726               // table of character substitutions
43727               "\b": "\\b",
43728               "\t": "\\t",
43729               "\n": "\\n",
43730               "\f": "\\f",
43731               "\r": "\\r",
43732               "\"": "\\\"",
43733               "\\": "\\\\"
43734             };
43735
43736             JSON.stringify = function (value, replacer, space) {
43737               // The stringify method takes a value and an optional replacer, and an optional
43738               // space parameter, and returns a JSON text. The replacer can be a function
43739               // that can replace values, or an array of strings that will select the keys.
43740               // A default replacer method can be provided. Use of the space parameter can
43741               // produce text that is more easily readable.
43742               var i;
43743               gap = "";
43744               indent = ""; // If the space parameter is a number, make an indent string containing that
43745               // many spaces.
43746
43747               if (typeof space === "number") {
43748                 for (i = 0; i < space; i += 1) {
43749                   indent += " ";
43750                 } // If the space parameter is a string, it will be used as the indent string.
43751
43752               } else if (typeof space === "string") {
43753                 indent = space;
43754               } // If there is a replacer, it must be a function or an array.
43755               // Otherwise, throw an error.
43756
43757
43758               rep = replacer;
43759
43760               if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
43761                 throw new Error("JSON.stringify");
43762               } // Make a fake root object containing our value under the key of "".
43763               // Return the result of stringifying the value.
43764
43765
43766               return str("", {
43767                 "": value
43768               });
43769             };
43770           } // If the JSON object does not yet have a parse method, give it one.
43771
43772
43773           if (typeof JSON.parse !== "function") {
43774             JSON.parse = function (text, reviver) {
43775               // The parse method takes a text and an optional reviver function, and returns
43776               // a JavaScript value if the text is a valid JSON text.
43777               var j;
43778
43779               function walk(holder, key) {
43780                 // The walk method is used to recursively walk the resulting structure so
43781                 // that modifications can be made.
43782                 var k;
43783                 var v;
43784                 var value = holder[key];
43785
43786                 if (value && _typeof(value) === "object") {
43787                   for (k in value) {
43788                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43789                       v = walk(value, k);
43790
43791                       if (v !== undefined) {
43792                         value[k] = v;
43793                       } else {
43794                         delete value[k];
43795                       }
43796                     }
43797                   }
43798                 }
43799
43800                 return reviver.call(holder, key, value);
43801               } // Parsing happens in four stages. In the first stage, we replace certain
43802               // Unicode characters with escape sequences. JavaScript handles many characters
43803               // incorrectly, either silently deleting them, or treating them as line endings.
43804
43805
43806               text = String(text);
43807               rx_dangerous.lastIndex = 0;
43808
43809               if (rx_dangerous.test(text)) {
43810                 text = text.replace(rx_dangerous, function (a) {
43811                   return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43812                 });
43813               } // In the second stage, we run the text against regular expressions that look
43814               // for non-JSON patterns. We are especially concerned with "()" and "new"
43815               // because they can cause invocation, and "=" because it can cause mutation.
43816               // But just to be safe, we want to reject all unexpected forms.
43817               // We split the second stage into 4 regexp operations in order to work around
43818               // crippling inefficiencies in IE's and Safari's regexp engines. First we
43819               // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
43820               // replace all simple value tokens with "]" characters. Third, we delete all
43821               // open brackets that follow a colon or comma or that begin the text. Finally,
43822               // we look to see that the remaining characters are only whitespace or "]" or
43823               // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
43824
43825
43826               if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
43827                 // In the third stage we use the eval function to compile the text into a
43828                 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
43829                 // in JavaScript: it can begin a block or an object literal. We wrap the text
43830                 // in parens to eliminate the ambiguity.
43831                 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
43832                 // each name/value pair to a reviver function for possible transformation.
43833
43834                 return typeof reviver === "function" ? walk({
43835                   "": j
43836                 }, "") : j;
43837               } // If the text is not JSON parseable, then a SyntaxError is thrown.
43838
43839
43840               throw new SyntaxError("JSON.parse");
43841             };
43842           }
43843         })();
43844
43845         var json2 = json2Plugin;
43846
43847         function json2Plugin() {
43848           return {};
43849         }
43850
43851         var plugins = [json2];
43852         var store_legacy = storeEngine.createStore(all, plugins);
43853
43854         //
43855         // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
43856         // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
43857         // does not support custom headers, which this uses everywhere.
43858
43859
43860         var osmAuth = function osmAuth(o) {
43861           var oauth = {}; // authenticated users will also have a request token secret, but it's
43862           // not used in transactions with the server
43863
43864           oauth.authenticated = function () {
43865             return !!(token('oauth_token') && token('oauth_token_secret'));
43866           };
43867
43868           oauth.logout = function () {
43869             token('oauth_token', '');
43870             token('oauth_token_secret', '');
43871             token('oauth_request_token_secret', '');
43872             return oauth;
43873           }; // TODO: detect lack of click event
43874
43875
43876           oauth.authenticate = function (callback) {
43877             if (oauth.authenticated()) return callback();
43878             oauth.logout(); // ## Getting a request token
43879
43880             var params = timenonce(getAuth(o)),
43881                 url = o.url + '/oauth/request_token';
43882             params.oauth_signature = ohauth_1.signature(o.oauth_secret, '', ohauth_1.baseString('POST', url, params));
43883
43884             if (!o.singlepage) {
43885               // Create a 600x550 popup window in the center of the screen
43886               var w = 600,
43887                   h = 550,
43888                   settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
43889                 return x.join('=');
43890               }).join(','),
43891                   popup = window.open('about:blank', 'oauth_window', settings);
43892               oauth.popupWindow = popup;
43893
43894               if (!popup) {
43895                 var error = new Error('Popup was blocked');
43896                 error.status = 'popup-blocked';
43897                 throw error;
43898               }
43899             } // Request a request token. When this is complete, the popup
43900             // window is redirected to OSM's authorization page.
43901
43902
43903             ohauth_1.xhr('POST', url, params, null, {}, reqTokenDone);
43904             o.loading();
43905
43906             function reqTokenDone(err, xhr) {
43907               o.done();
43908               if (err) return callback(err);
43909               var resp = ohauth_1.stringQs(xhr.response);
43910               token('oauth_request_token_secret', resp.oauth_token_secret);
43911               var authorize_url = o.url + '/oauth/authorize?' + ohauth_1.qsString({
43912                 oauth_token: resp.oauth_token,
43913                 oauth_callback: resolveUrl$1(o.landing)
43914               });
43915
43916               if (o.singlepage) {
43917                 location.href = authorize_url;
43918               } else {
43919                 popup.location = authorize_url;
43920               }
43921             } // Called by a function in a landing page, in the popup window. The
43922             // window closes itself.
43923
43924
43925             window.authComplete = function (token) {
43926               var oauth_token = ohauth_1.stringQs(token.split('?')[1]);
43927               get_access_token(oauth_token.oauth_token);
43928               delete window.authComplete;
43929             }; // ## Getting an request token
43930             //
43931             // At this point we have an `oauth_token`, brought in from a function
43932             // call on a landing page popup.
43933
43934
43935             function get_access_token(oauth_token) {
43936               var url = o.url + '/oauth/access_token',
43937                   params = timenonce(getAuth(o)),
43938                   request_token_secret = token('oauth_request_token_secret');
43939               params.oauth_token = oauth_token;
43940               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43941               //
43942               // The final token required for authentication. At this point
43943               // we have a `request token secret`
43944
43945               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43946               o.loading();
43947             }
43948
43949             function accessTokenDone(err, xhr) {
43950               o.done();
43951               if (err) return callback(err);
43952               var access_token = ohauth_1.stringQs(xhr.response);
43953               token('oauth_token', access_token.oauth_token);
43954               token('oauth_token_secret', access_token.oauth_token_secret);
43955               callback(null, oauth);
43956             }
43957           };
43958
43959           oauth.bringPopupWindowToFront = function () {
43960             var brougtPopupToFront = false;
43961
43962             try {
43963               // This may cause a cross-origin error:
43964               // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
43965               if (oauth.popupWindow && !oauth.popupWindow.closed) {
43966                 oauth.popupWindow.focus();
43967                 brougtPopupToFront = true;
43968               }
43969             } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
43970             }
43971
43972             return brougtPopupToFront;
43973           };
43974
43975           oauth.bootstrapToken = function (oauth_token, callback) {
43976             // ## Getting an request token
43977             // At this point we have an `oauth_token`, brought in from a function
43978             // call on a landing page popup.
43979             function get_access_token(oauth_token) {
43980               var url = o.url + '/oauth/access_token',
43981                   params = timenonce(getAuth(o)),
43982                   request_token_secret = token('oauth_request_token_secret');
43983               params.oauth_token = oauth_token;
43984               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43985               // The final token required for authentication. At this point
43986               // we have a `request token secret`
43987
43988               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43989               o.loading();
43990             }
43991
43992             function accessTokenDone(err, xhr) {
43993               o.done();
43994               if (err) return callback(err);
43995               var access_token = ohauth_1.stringQs(xhr.response);
43996               token('oauth_token', access_token.oauth_token);
43997               token('oauth_token_secret', access_token.oauth_token_secret);
43998               callback(null, oauth);
43999             }
44000
44001             get_access_token(oauth_token);
44002           }; // # xhr
44003           //
44004           // A single XMLHttpRequest wrapper that does authenticated calls if the
44005           // user has logged in.
44006
44007
44008           oauth.xhr = function (options, callback) {
44009             if (!oauth.authenticated()) {
44010               if (o.auto) {
44011                 return oauth.authenticate(run);
44012               } else {
44013                 callback('not authenticated', null);
44014                 return;
44015               }
44016             } else {
44017               return run();
44018             }
44019
44020             function run() {
44021               var params = timenonce(getAuth(o)),
44022                   oauth_token_secret = token('oauth_token_secret'),
44023                   url = options.prefix !== false ? o.url + options.path : options.path,
44024                   url_parts = url.replace(/#.*$/, '').split('?', 2),
44025                   base_url = url_parts[0],
44026                   query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
44027
44028               if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
44029                 params = immutable(params, ohauth_1.stringQs(options.content));
44030               }
44031
44032               params.oauth_token = token('oauth_token');
44033               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))));
44034               return ohauth_1.xhr(options.method, url, params, options.content, options.options, done);
44035             }
44036
44037             function done(err, xhr) {
44038               if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
44039             }
44040           }; // pre-authorize this object, if we can just get a token and token_secret
44041           // from the start
44042
44043
44044           oauth.preauth = function (c) {
44045             if (!c) return;
44046             if (c.oauth_token) token('oauth_token', c.oauth_token);
44047             if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
44048             return oauth;
44049           };
44050
44051           oauth.options = function (_) {
44052             if (!arguments.length) return o;
44053             o = _;
44054             o.url = o.url || 'https://www.openstreetmap.org';
44055             o.landing = o.landing || 'land.html';
44056             o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
44057             // by default, no-ops
44058
44059             o.loading = o.loading || function () {};
44060
44061             o.done = o.done || function () {};
44062
44063             return oauth.preauth(o);
44064           }; // 'stamp' an authentication object from `getAuth()`
44065           // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
44066           // and timestamp
44067
44068
44069           function timenonce(o) {
44070             o.oauth_timestamp = ohauth_1.timestamp();
44071             o.oauth_nonce = ohauth_1.nonce();
44072             return o;
44073           } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
44074           // can be used with multiple APIs and the keys in `localStorage`
44075           // will not clash
44076
44077
44078           var token;
44079
44080           if (store_legacy.enabled) {
44081             token = function token(x, y) {
44082               if (arguments.length === 1) return store_legacy.get(o.url + x);else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
44083             };
44084           } else {
44085             var storage = {};
44086
44087             token = function token(x, y) {
44088               if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
44089             };
44090           } // Get an authentication object. If you just add and remove properties
44091           // from a single object, you'll need to use `delete` to make sure that
44092           // it doesn't contain undesired properties for authentication
44093
44094
44095           function getAuth(o) {
44096             return {
44097               oauth_consumer_key: o.oauth_consumer_key,
44098               oauth_signature_method: 'HMAC-SHA1'
44099             };
44100           } // potentially pre-authorize
44101
44102
44103           oauth.options(o);
44104           return oauth;
44105         };
44106
44107         var JXON = new function () {
44108           var sValueProp = 'keyValue',
44109               sAttributesProp = 'keyAttributes',
44110               sAttrPref = '@',
44111
44112           /* you can customize these values */
44113           aCache = [],
44114               rIsNull = /^\s*$/,
44115               rIsBool = /^(?:true|false)$/i;
44116
44117           function parseText(sValue) {
44118             if (rIsNull.test(sValue)) {
44119               return null;
44120             }
44121
44122             if (rIsBool.test(sValue)) {
44123               return sValue.toLowerCase() === 'true';
44124             }
44125
44126             if (isFinite(sValue)) {
44127               return parseFloat(sValue);
44128             }
44129
44130             if (isFinite(Date.parse(sValue))) {
44131               return new Date(sValue);
44132             }
44133
44134             return sValue;
44135           }
44136
44137           function EmptyTree() {}
44138
44139           EmptyTree.prototype.toString = function () {
44140             return 'null';
44141           };
44142
44143           EmptyTree.prototype.valueOf = function () {
44144             return null;
44145           };
44146
44147           function objectify(vValue) {
44148             return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
44149           }
44150
44151           function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
44152             var nLevelStart = aCache.length,
44153                 bChildren = oParentNode.hasChildNodes(),
44154                 bAttributes = oParentNode.hasAttributes(),
44155                 bHighVerb = Boolean(nVerb & 2);
44156             var sProp,
44157                 vContent,
44158                 nLength = 0,
44159                 sCollectedTxt = '',
44160                 vResult = bHighVerb ? {} :
44161             /* put here the default value for empty nodes: */
44162             true;
44163
44164             if (bChildren) {
44165               for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
44166                 oNode = oParentNode.childNodes.item(nItem);
44167
44168                 if (oNode.nodeType === 4) {
44169                   sCollectedTxt += oNode.nodeValue;
44170                 }
44171                 /* nodeType is 'CDATASection' (4) */
44172                 else if (oNode.nodeType === 3) {
44173                     sCollectedTxt += oNode.nodeValue.trim();
44174                   }
44175                   /* nodeType is 'Text' (3) */
44176                   else if (oNode.nodeType === 1 && !oNode.prefix) {
44177                       aCache.push(oNode);
44178                     }
44179                 /* nodeType is 'Element' (1) */
44180
44181               }
44182             }
44183
44184             var nLevelEnd = aCache.length,
44185                 vBuiltVal = parseText(sCollectedTxt);
44186
44187             if (!bHighVerb && (bChildren || bAttributes)) {
44188               vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
44189             }
44190
44191             for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
44192               sProp = aCache[nElId].nodeName.toLowerCase();
44193               vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
44194
44195               if (vResult.hasOwnProperty(sProp)) {
44196                 if (vResult[sProp].constructor !== Array) {
44197                   vResult[sProp] = [vResult[sProp]];
44198                 }
44199
44200                 vResult[sProp].push(vContent);
44201               } else {
44202                 vResult[sProp] = vContent;
44203                 nLength++;
44204               }
44205             }
44206
44207             if (bAttributes) {
44208               var nAttrLen = oParentNode.attributes.length,
44209                   sAPrefix = bNesteAttr ? '' : sAttrPref,
44210                   oAttrParent = bNesteAttr ? {} : vResult;
44211
44212               for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
44213                 oAttrib = oParentNode.attributes.item(nAttrib);
44214                 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
44215               }
44216
44217               if (bNesteAttr) {
44218                 if (bFreeze) {
44219                   Object.freeze(oAttrParent);
44220                 }
44221
44222                 vResult[sAttributesProp] = oAttrParent;
44223                 nLength -= nAttrLen - 1;
44224               }
44225             }
44226
44227             if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
44228               vResult[sValueProp] = vBuiltVal;
44229             } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
44230               vResult = vBuiltVal;
44231             }
44232
44233             if (bFreeze && (bHighVerb || nLength > 0)) {
44234               Object.freeze(vResult);
44235             }
44236
44237             aCache.length = nLevelStart;
44238             return vResult;
44239           }
44240
44241           function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
44242             var vValue, oChild;
44243
44244             if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
44245               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
44246               /* verbosity level is 0 */
44247             } else if (oParentObj.constructor === Date) {
44248               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
44249             }
44250
44251             for (var sName in oParentObj) {
44252               vValue = oParentObj[sName];
44253
44254               if (isFinite(sName) || vValue instanceof Function) {
44255                 continue;
44256               }
44257               /* verbosity level is 0 */
44258
44259
44260               if (sName === sValueProp) {
44261                 if (vValue !== null && vValue !== true) {
44262                   oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
44263                 }
44264               } else if (sName === sAttributesProp) {
44265                 /* verbosity level is 3 */
44266                 for (var sAttrib in vValue) {
44267                   oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
44268                 }
44269               } else if (sName.charAt(0) === sAttrPref) {
44270                 oParentEl.setAttribute(sName.slice(1), vValue);
44271               } else if (vValue.constructor === Array) {
44272                 for (var nItem = 0; nItem < vValue.length; nItem++) {
44273                   oChild = oXMLDoc.createElement(sName);
44274                   loadObjTree(oXMLDoc, oChild, vValue[nItem]);
44275                   oParentEl.appendChild(oChild);
44276                 }
44277               } else {
44278                 oChild = oXMLDoc.createElement(sName);
44279
44280                 if (vValue instanceof Object) {
44281                   loadObjTree(oXMLDoc, oChild, vValue);
44282                 } else if (vValue !== null && vValue !== true) {
44283                   oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
44284                 }
44285
44286                 oParentEl.appendChild(oChild);
44287               }
44288             }
44289           }
44290
44291           this.build = function (oXMLParent, nVerbosity
44292           /* optional */
44293           , bFreeze
44294           /* optional */
44295           , bNesteAttributes
44296           /* optional */
44297           ) {
44298             var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
44299             /* put here the default verbosity level: */
44300             1;
44301
44302             return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
44303           };
44304
44305           this.unbuild = function (oObjTree) {
44306             var oNewDoc = document.implementation.createDocument('', '', null);
44307             loadObjTree(oNewDoc, oNewDoc, oObjTree);
44308             return oNewDoc;
44309           };
44310
44311           this.stringify = function (oObjTree) {
44312             return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
44313           };
44314         }(); // var myObject = JXON.build(doc);
44315         // we got our javascript object! try: alert(JSON.stringify(myObject));
44316         // var newDoc = JXON.unbuild(myObject);
44317         // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
44318
44319         var tiler$5 = utilTiler();
44320         var dispatch$6 = dispatch('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
44321         var urlroot = 'https://www.openstreetmap.org';
44322         var oauth = osmAuth({
44323           url: urlroot,
44324           oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
44325           oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
44326           loading: authLoading,
44327           done: authDone
44328         }); // hardcode default block of Google Maps
44329
44330         var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
44331         var _tileCache = {
44332           toLoad: {},
44333           loaded: {},
44334           inflight: {},
44335           seen: {},
44336           rtree: new RBush()
44337         };
44338         var _noteCache = {
44339           toLoad: {},
44340           loaded: {},
44341           inflight: {},
44342           inflightPost: {},
44343           note: {},
44344           closed: {},
44345           rtree: new RBush()
44346         };
44347         var _userCache = {
44348           toLoad: {},
44349           user: {}
44350         };
44351
44352         var _cachedApiStatus;
44353
44354         var _changeset = {};
44355
44356         var _deferred = new Set();
44357
44358         var _connectionID = 1;
44359         var _tileZoom$3 = 16;
44360         var _noteZoom = 12;
44361
44362         var _rateLimitError;
44363
44364         var _userChangesets;
44365
44366         var _userDetails;
44367
44368         var _off; // set a default but also load this from the API status
44369
44370
44371         var _maxWayNodes = 2000;
44372
44373         function authLoading() {
44374           dispatch$6.call('authLoading');
44375         }
44376
44377         function authDone() {
44378           dispatch$6.call('authDone');
44379         }
44380
44381         function abortRequest$5(controllerOrXHR) {
44382           if (controllerOrXHR) {
44383             controllerOrXHR.abort();
44384           }
44385         }
44386
44387         function hasInflightRequests(cache) {
44388           return Object.keys(cache.inflight).length;
44389         }
44390
44391         function abortUnwantedRequests$3(cache, visibleTiles) {
44392           Object.keys(cache.inflight).forEach(function (k) {
44393             if (cache.toLoad[k]) return;
44394             if (visibleTiles.find(function (tile) {
44395               return k === tile.id;
44396             })) return;
44397             abortRequest$5(cache.inflight[k]);
44398             delete cache.inflight[k];
44399           });
44400         }
44401
44402         function getLoc(attrs) {
44403           var lon = attrs.lon && attrs.lon.value;
44404           var lat = attrs.lat && attrs.lat.value;
44405           return [parseFloat(lon), parseFloat(lat)];
44406         }
44407
44408         function getNodes(obj) {
44409           var elems = obj.getElementsByTagName('nd');
44410           var nodes = new Array(elems.length);
44411
44412           for (var i = 0, l = elems.length; i < l; i++) {
44413             nodes[i] = 'n' + elems[i].attributes.ref.value;
44414           }
44415
44416           return nodes;
44417         }
44418
44419         function getNodesJSON(obj) {
44420           var elems = obj.nodes;
44421           var nodes = new Array(elems.length);
44422
44423           for (var i = 0, l = elems.length; i < l; i++) {
44424             nodes[i] = 'n' + elems[i];
44425           }
44426
44427           return nodes;
44428         }
44429
44430         function getTags(obj) {
44431           var elems = obj.getElementsByTagName('tag');
44432           var tags = {};
44433
44434           for (var i = 0, l = elems.length; i < l; i++) {
44435             var attrs = elems[i].attributes;
44436             tags[attrs.k.value] = attrs.v.value;
44437           }
44438
44439           return tags;
44440         }
44441
44442         function getMembers(obj) {
44443           var elems = obj.getElementsByTagName('member');
44444           var members = new Array(elems.length);
44445
44446           for (var i = 0, l = elems.length; i < l; i++) {
44447             var attrs = elems[i].attributes;
44448             members[i] = {
44449               id: attrs.type.value[0] + attrs.ref.value,
44450               type: attrs.type.value,
44451               role: attrs.role.value
44452             };
44453           }
44454
44455           return members;
44456         }
44457
44458         function getMembersJSON(obj) {
44459           var elems = obj.members;
44460           var members = new Array(elems.length);
44461
44462           for (var i = 0, l = elems.length; i < l; i++) {
44463             var attrs = elems[i];
44464             members[i] = {
44465               id: attrs.type[0] + attrs.ref,
44466               type: attrs.type,
44467               role: attrs.role
44468             };
44469           }
44470
44471           return members;
44472         }
44473
44474         function getVisible(attrs) {
44475           return !attrs.visible || attrs.visible.value !== 'false';
44476         }
44477
44478         function parseComments(comments) {
44479           var parsedComments = []; // for each comment
44480
44481           for (var i = 0; i < comments.length; i++) {
44482             var comment = comments[i];
44483
44484             if (comment.nodeName === 'comment') {
44485               var childNodes = comment.childNodes;
44486               var parsedComment = {};
44487
44488               for (var j = 0; j < childNodes.length; j++) {
44489                 var node = childNodes[j];
44490                 var nodeName = node.nodeName;
44491                 if (nodeName === '#text') continue;
44492                 parsedComment[nodeName] = node.textContent;
44493
44494                 if (nodeName === 'uid') {
44495                   var uid = node.textContent;
44496
44497                   if (uid && !_userCache.user[uid]) {
44498                     _userCache.toLoad[uid] = true;
44499                   }
44500                 }
44501               }
44502
44503               if (parsedComment) {
44504                 parsedComments.push(parsedComment);
44505               }
44506             }
44507           }
44508
44509           return parsedComments;
44510         }
44511
44512         function encodeNoteRtree(note) {
44513           return {
44514             minX: note.loc[0],
44515             minY: note.loc[1],
44516             maxX: note.loc[0],
44517             maxY: note.loc[1],
44518             data: note
44519           };
44520         }
44521
44522         var jsonparsers = {
44523           node: function nodeData(obj, uid) {
44524             return new osmNode({
44525               id: uid,
44526               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44527               version: obj.version && obj.version.toString(),
44528               changeset: obj.changeset && obj.changeset.toString(),
44529               timestamp: obj.timestamp,
44530               user: obj.user,
44531               uid: obj.uid && obj.uid.toString(),
44532               loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
44533               tags: obj.tags
44534             });
44535           },
44536           way: function wayData(obj, uid) {
44537             return new osmWay({
44538               id: uid,
44539               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44540               version: obj.version && obj.version.toString(),
44541               changeset: obj.changeset && obj.changeset.toString(),
44542               timestamp: obj.timestamp,
44543               user: obj.user,
44544               uid: obj.uid && obj.uid.toString(),
44545               tags: obj.tags,
44546               nodes: getNodesJSON(obj)
44547             });
44548           },
44549           relation: function relationData(obj, uid) {
44550             return new osmRelation({
44551               id: uid,
44552               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44553               version: obj.version && obj.version.toString(),
44554               changeset: obj.changeset && obj.changeset.toString(),
44555               timestamp: obj.timestamp,
44556               user: obj.user,
44557               uid: obj.uid && obj.uid.toString(),
44558               tags: obj.tags,
44559               members: getMembersJSON(obj)
44560             });
44561           }
44562         };
44563
44564         function parseJSON(payload, callback, options) {
44565           options = Object.assign({
44566             skipSeen: true
44567           }, options);
44568
44569           if (!payload) {
44570             return callback({
44571               message: 'No JSON',
44572               status: -1
44573             });
44574           }
44575
44576           var json = payload;
44577           if (_typeof(json) !== 'object') json = JSON.parse(payload);
44578           if (!json.elements) return callback({
44579             message: 'No JSON',
44580             status: -1
44581           });
44582           var children = json.elements;
44583           var handle = window.requestIdleCallback(function () {
44584             var results = [];
44585             var result;
44586
44587             for (var i = 0; i < children.length; i++) {
44588               result = parseChild(children[i]);
44589               if (result) results.push(result);
44590             }
44591
44592             callback(null, results);
44593           });
44594
44595           _deferred.add(handle);
44596
44597           function parseChild(child) {
44598             var parser = jsonparsers[child.type];
44599             if (!parser) return null;
44600             var uid;
44601             uid = osmEntity.id.fromOSM(child.type, child.id);
44602
44603             if (options.skipSeen) {
44604               if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44605
44606               _tileCache.seen[uid] = true;
44607             }
44608
44609             return parser(child, uid);
44610           }
44611         }
44612
44613         var parsers = {
44614           node: function nodeData(obj, uid) {
44615             var attrs = obj.attributes;
44616             return new osmNode({
44617               id: uid,
44618               visible: getVisible(attrs),
44619               version: attrs.version.value,
44620               changeset: attrs.changeset && attrs.changeset.value,
44621               timestamp: attrs.timestamp && attrs.timestamp.value,
44622               user: attrs.user && attrs.user.value,
44623               uid: attrs.uid && attrs.uid.value,
44624               loc: getLoc(attrs),
44625               tags: getTags(obj)
44626             });
44627           },
44628           way: function wayData(obj, uid) {
44629             var attrs = obj.attributes;
44630             return new osmWay({
44631               id: uid,
44632               visible: getVisible(attrs),
44633               version: attrs.version.value,
44634               changeset: attrs.changeset && attrs.changeset.value,
44635               timestamp: attrs.timestamp && attrs.timestamp.value,
44636               user: attrs.user && attrs.user.value,
44637               uid: attrs.uid && attrs.uid.value,
44638               tags: getTags(obj),
44639               nodes: getNodes(obj)
44640             });
44641           },
44642           relation: function relationData(obj, uid) {
44643             var attrs = obj.attributes;
44644             return new osmRelation({
44645               id: uid,
44646               visible: getVisible(attrs),
44647               version: attrs.version.value,
44648               changeset: attrs.changeset && attrs.changeset.value,
44649               timestamp: attrs.timestamp && attrs.timestamp.value,
44650               user: attrs.user && attrs.user.value,
44651               uid: attrs.uid && attrs.uid.value,
44652               tags: getTags(obj),
44653               members: getMembers(obj)
44654             });
44655           },
44656           note: function parseNote(obj, uid) {
44657             var attrs = obj.attributes;
44658             var childNodes = obj.childNodes;
44659             var props = {};
44660             props.id = uid;
44661             props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
44662
44663             var coincident = false;
44664             var epsilon = 0.00001;
44665
44666             do {
44667               if (coincident) {
44668                 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
44669               }
44670
44671               var bbox = geoExtent(props.loc).bbox();
44672               coincident = _noteCache.rtree.search(bbox).length;
44673             } while (coincident); // parse note contents
44674
44675
44676             for (var i = 0; i < childNodes.length; i++) {
44677               var node = childNodes[i];
44678               var nodeName = node.nodeName;
44679               if (nodeName === '#text') continue; // if the element is comments, parse the comments
44680
44681               if (nodeName === 'comments') {
44682                 props[nodeName] = parseComments(node.childNodes);
44683               } else {
44684                 props[nodeName] = node.textContent;
44685               }
44686             }
44687
44688             var note = new osmNote(props);
44689             var item = encodeNoteRtree(note);
44690             _noteCache.note[note.id] = note;
44691
44692             _noteCache.rtree.insert(item);
44693
44694             return note;
44695           },
44696           user: function parseUser(obj, uid) {
44697             var attrs = obj.attributes;
44698             var user = {
44699               id: uid,
44700               display_name: attrs.display_name && attrs.display_name.value,
44701               account_created: attrs.account_created && attrs.account_created.value,
44702               changesets_count: '0',
44703               active_blocks: '0'
44704             };
44705             var img = obj.getElementsByTagName('img');
44706
44707             if (img && img[0] && img[0].getAttribute('href')) {
44708               user.image_url = img[0].getAttribute('href');
44709             }
44710
44711             var changesets = obj.getElementsByTagName('changesets');
44712
44713             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
44714               user.changesets_count = changesets[0].getAttribute('count');
44715             }
44716
44717             var blocks = obj.getElementsByTagName('blocks');
44718
44719             if (blocks && blocks[0]) {
44720               var received = blocks[0].getElementsByTagName('received');
44721
44722               if (received && received[0] && received[0].getAttribute('active')) {
44723                 user.active_blocks = received[0].getAttribute('active');
44724               }
44725             }
44726
44727             _userCache.user[uid] = user;
44728             delete _userCache.toLoad[uid];
44729             return user;
44730           }
44731         };
44732
44733         function parseXML(xml, callback, options) {
44734           options = Object.assign({
44735             skipSeen: true
44736           }, options);
44737
44738           if (!xml || !xml.childNodes) {
44739             return callback({
44740               message: 'No XML',
44741               status: -1
44742             });
44743           }
44744
44745           var root = xml.childNodes[0];
44746           var children = root.childNodes;
44747           var handle = window.requestIdleCallback(function () {
44748             var results = [];
44749             var result;
44750
44751             for (var i = 0; i < children.length; i++) {
44752               result = parseChild(children[i]);
44753               if (result) results.push(result);
44754             }
44755
44756             callback(null, results);
44757           });
44758
44759           _deferred.add(handle);
44760
44761           function parseChild(child) {
44762             var parser = parsers[child.nodeName];
44763             if (!parser) return null;
44764             var uid;
44765
44766             if (child.nodeName === 'user') {
44767               uid = child.attributes.id.value;
44768
44769               if (options.skipSeen && _userCache.user[uid]) {
44770                 delete _userCache.toLoad[uid];
44771                 return null;
44772               }
44773             } else if (child.nodeName === 'note') {
44774               uid = child.getElementsByTagName('id')[0].textContent;
44775             } else {
44776               uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
44777
44778               if (options.skipSeen) {
44779                 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44780
44781                 _tileCache.seen[uid] = true;
44782               }
44783             }
44784
44785             return parser(child, uid);
44786           }
44787         } // replace or remove note from rtree
44788
44789
44790         function updateRtree$3(item, replace) {
44791           _noteCache.rtree.remove(item, function isEql(a, b) {
44792             return a.data.id === b.data.id;
44793           });
44794
44795           if (replace) {
44796             _noteCache.rtree.insert(item);
44797           }
44798         }
44799
44800         function wrapcb(thisArg, callback, cid) {
44801           return function (err, result) {
44802             if (err) {
44803               // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
44804               if (err.status === 400 || err.status === 401 || err.status === 403) {
44805                 thisArg.logout();
44806               }
44807
44808               return callback.call(thisArg, err);
44809             } else if (thisArg.getConnectionId() !== cid) {
44810               return callback.call(thisArg, {
44811                 message: 'Connection Switched',
44812                 status: -1
44813               });
44814             } else {
44815               return callback.call(thisArg, err, result);
44816             }
44817           };
44818         }
44819
44820         var serviceOsm = {
44821           init: function init() {
44822             utilRebind(this, dispatch$6, 'on');
44823           },
44824           reset: function reset() {
44825             Array.from(_deferred).forEach(function (handle) {
44826               window.cancelIdleCallback(handle);
44827
44828               _deferred["delete"](handle);
44829             });
44830             _connectionID++;
44831             _userChangesets = undefined;
44832             _userDetails = undefined;
44833             _rateLimitError = undefined;
44834             Object.values(_tileCache.inflight).forEach(abortRequest$5);
44835             Object.values(_noteCache.inflight).forEach(abortRequest$5);
44836             Object.values(_noteCache.inflightPost).forEach(abortRequest$5);
44837             if (_changeset.inflight) abortRequest$5(_changeset.inflight);
44838             _tileCache = {
44839               toLoad: {},
44840               loaded: {},
44841               inflight: {},
44842               seen: {},
44843               rtree: new RBush()
44844             };
44845             _noteCache = {
44846               toLoad: {},
44847               loaded: {},
44848               inflight: {},
44849               inflightPost: {},
44850               note: {},
44851               closed: {},
44852               rtree: new RBush()
44853             };
44854             _userCache = {
44855               toLoad: {},
44856               user: {}
44857             };
44858             _cachedApiStatus = undefined;
44859             _changeset = {};
44860             return this;
44861           },
44862           getConnectionId: function getConnectionId() {
44863             return _connectionID;
44864           },
44865           changesetURL: function changesetURL(changesetID) {
44866             return urlroot + '/changeset/' + changesetID;
44867           },
44868           changesetsURL: function changesetsURL(center, zoom) {
44869             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
44870             return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
44871           },
44872           entityURL: function entityURL(entity) {
44873             return urlroot + '/' + entity.type + '/' + entity.osmId();
44874           },
44875           historyURL: function historyURL(entity) {
44876             return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
44877           },
44878           userURL: function userURL(username) {
44879             return urlroot + '/user/' + username;
44880           },
44881           noteURL: function noteURL(note) {
44882             return urlroot + '/note/' + note.id;
44883           },
44884           noteReportURL: function noteReportURL(note) {
44885             return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
44886           },
44887           // Generic method to load data from the OSM API
44888           // Can handle either auth or unauth calls.
44889           loadFromAPI: function loadFromAPI(path, callback, options) {
44890             options = Object.assign({
44891               skipSeen: true
44892             }, options);
44893             var that = this;
44894             var cid = _connectionID;
44895
44896             function done(err, payload) {
44897               if (that.getConnectionId() !== cid) {
44898                 if (callback) callback({
44899                   message: 'Connection Switched',
44900                   status: -1
44901                 });
44902                 return;
44903               }
44904
44905               var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
44906               // Logout and retry the request..
44907
44908               if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
44909                 that.logout();
44910                 that.loadFromAPI(path, callback, options); // else, no retry..
44911               } else {
44912                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
44913                 // Set the rateLimitError flag and trigger a warning..
44914                 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
44915                   _rateLimitError = err;
44916                   dispatch$6.call('change');
44917                   that.reloadApiStatus();
44918                 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
44919                   // If the response's error state doesn't match the status,
44920                   // it's likely we lost or gained the connection so reload the status
44921                   that.reloadApiStatus();
44922                 }
44923
44924                 if (callback) {
44925                   if (err) {
44926                     return callback(err);
44927                   } else {
44928                     if (path.indexOf('.json') !== -1) {
44929                       return parseJSON(payload, callback, options);
44930                     } else {
44931                       return parseXML(payload, callback, options);
44932                     }
44933                   }
44934                 }
44935               }
44936             }
44937
44938             if (this.authenticated()) {
44939               return oauth.xhr({
44940                 method: 'GET',
44941                 path: path
44942               }, done);
44943             } else {
44944               var url = urlroot + path;
44945               var controller = new AbortController();
44946               d3_json(url, {
44947                 signal: controller.signal
44948               }).then(function (data) {
44949                 done(null, data);
44950               })["catch"](function (err) {
44951                 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
44952                 // but we can't access the response itself
44953                 // https://github.com/d3/d3-fetch/issues/27
44954
44955                 var match = err.message.match(/^\d{3}/);
44956
44957                 if (match) {
44958                   done({
44959                     status: +match[0],
44960                     statusText: err.message
44961                   });
44962                 } else {
44963                   done(err.message);
44964                 }
44965               });
44966               return controller;
44967             }
44968           },
44969           // Load a single entity by id (ways and relations use the `/full` call)
44970           // GET /api/0.6/node/#id
44971           // GET /api/0.6/[way|relation]/#id/full
44972           loadEntity: function loadEntity(id, callback) {
44973             var type = osmEntity.id.type(id);
44974             var osmID = osmEntity.id.toOSM(id);
44975             var options = {
44976               skipSeen: false
44977             };
44978             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
44979               if (callback) callback(err, {
44980                 data: entities
44981               });
44982             }, options);
44983           },
44984           // Load a single entity with a specific version
44985           // GET /api/0.6/[node|way|relation]/#id/#version
44986           loadEntityVersion: function loadEntityVersion(id, version, callback) {
44987             var type = osmEntity.id.type(id);
44988             var osmID = osmEntity.id.toOSM(id);
44989             var options = {
44990               skipSeen: false
44991             };
44992             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
44993               if (callback) callback(err, {
44994                 data: entities
44995               });
44996             }, options);
44997           },
44998           // Load multiple entities in chunks
44999           // (note: callback may be called multiple times)
45000           // Unlike `loadEntity`, child nodes and members are not fetched
45001           // GET /api/0.6/[nodes|ways|relations]?#parameters
45002           loadMultiple: function loadMultiple(ids, callback) {
45003             var that = this;
45004             var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
45005             Object.keys(groups).forEach(function (k) {
45006               var type = k + 's'; // nodes, ways, relations
45007
45008               var osmIDs = groups[k].map(function (id) {
45009                 return osmEntity.id.toOSM(id);
45010               });
45011               var options = {
45012                 skipSeen: false
45013               };
45014               utilArrayChunk(osmIDs, 150).forEach(function (arr) {
45015                 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
45016                   if (callback) callback(err, {
45017                     data: entities
45018                   });
45019                 }, options);
45020               });
45021             });
45022           },
45023           // Create, upload, and close a changeset
45024           // PUT /api/0.6/changeset/create
45025           // POST /api/0.6/changeset/#id/upload
45026           // PUT /api/0.6/changeset/#id/close
45027           putChangeset: function putChangeset(changeset, changes, callback) {
45028             var cid = _connectionID;
45029
45030             if (_changeset.inflight) {
45031               return callback({
45032                 message: 'Changeset already inflight',
45033                 status: -2
45034               }, changeset);
45035             } else if (_changeset.open) {
45036               // reuse existing open changeset..
45037               return createdChangeset.call(this, null, _changeset.open);
45038             } else {
45039               // Open a new changeset..
45040               var options = {
45041                 method: 'PUT',
45042                 path: '/api/0.6/changeset/create',
45043                 options: {
45044                   header: {
45045                     'Content-Type': 'text/xml'
45046                   }
45047                 },
45048                 content: JXON.stringify(changeset.asJXON())
45049               };
45050               _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
45051             }
45052
45053             function createdChangeset(err, changesetID) {
45054               _changeset.inflight = null;
45055
45056               if (err) {
45057                 return callback(err, changeset);
45058               }
45059
45060               _changeset.open = changesetID;
45061               changeset = changeset.update({
45062                 id: changesetID
45063               }); // Upload the changeset..
45064
45065               var options = {
45066                 method: 'POST',
45067                 path: '/api/0.6/changeset/' + changesetID + '/upload',
45068                 options: {
45069                   header: {
45070                     'Content-Type': 'text/xml'
45071                   }
45072                 },
45073                 content: JXON.stringify(changeset.osmChangeJXON(changes))
45074               };
45075               _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
45076             }
45077
45078             function uploadedChangeset(err) {
45079               _changeset.inflight = null;
45080               if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
45081               // Add delay to allow for postgres replication #1646 #2678
45082
45083               window.setTimeout(function () {
45084                 callback(null, changeset);
45085               }, 2500);
45086               _changeset.open = null; // At this point, we don't really care if the connection was switched..
45087               // Only try to close the changeset if we're still talking to the same server.
45088
45089               if (this.getConnectionId() === cid) {
45090                 // Still attempt to close changeset, but ignore response because #2667
45091                 oauth.xhr({
45092                   method: 'PUT',
45093                   path: '/api/0.6/changeset/' + changeset.id + '/close',
45094                   options: {
45095                     header: {
45096                       'Content-Type': 'text/xml'
45097                     }
45098                   }
45099                 }, function () {
45100                   return true;
45101                 });
45102               }
45103             }
45104           },
45105           // Load multiple users in chunks
45106           // (note: callback may be called multiple times)
45107           // GET /api/0.6/users?users=#id1,#id2,...,#idn
45108           loadUsers: function loadUsers(uids, callback) {
45109             var toLoad = [];
45110             var cached = [];
45111             utilArrayUniq(uids).forEach(function (uid) {
45112               if (_userCache.user[uid]) {
45113                 delete _userCache.toLoad[uid];
45114                 cached.push(_userCache.user[uid]);
45115               } else {
45116                 toLoad.push(uid);
45117               }
45118             });
45119
45120             if (cached.length || !this.authenticated()) {
45121               callback(undefined, cached);
45122               if (!this.authenticated()) return; // require auth
45123             }
45124
45125             utilArrayChunk(toLoad, 150).forEach(function (arr) {
45126               oauth.xhr({
45127                 method: 'GET',
45128                 path: '/api/0.6/users?users=' + arr.join()
45129               }, wrapcb(this, done, _connectionID));
45130             }.bind(this));
45131
45132             function done(err, xml) {
45133               if (err) {
45134                 return callback(err);
45135               }
45136
45137               var options = {
45138                 skipSeen: true
45139               };
45140               return parseXML(xml, function (err, results) {
45141                 if (err) {
45142                   return callback(err);
45143                 } else {
45144                   return callback(undefined, results);
45145                 }
45146               }, options);
45147             }
45148           },
45149           // Load a given user by id
45150           // GET /api/0.6/user/#id
45151           loadUser: function loadUser(uid, callback) {
45152             if (_userCache.user[uid] || !this.authenticated()) {
45153               // require auth
45154               delete _userCache.toLoad[uid];
45155               return callback(undefined, _userCache.user[uid]);
45156             }
45157
45158             oauth.xhr({
45159               method: 'GET',
45160               path: '/api/0.6/user/' + uid
45161             }, wrapcb(this, done, _connectionID));
45162
45163             function done(err, xml) {
45164               if (err) {
45165                 return callback(err);
45166               }
45167
45168               var options = {
45169                 skipSeen: true
45170               };
45171               return parseXML(xml, function (err, results) {
45172                 if (err) {
45173                   return callback(err);
45174                 } else {
45175                   return callback(undefined, results[0]);
45176                 }
45177               }, options);
45178             }
45179           },
45180           // Load the details of the logged-in user
45181           // GET /api/0.6/user/details
45182           userDetails: function userDetails(callback) {
45183             if (_userDetails) {
45184               // retrieve cached
45185               return callback(undefined, _userDetails);
45186             }
45187
45188             oauth.xhr({
45189               method: 'GET',
45190               path: '/api/0.6/user/details'
45191             }, wrapcb(this, done, _connectionID));
45192
45193             function done(err, xml) {
45194               if (err) {
45195                 return callback(err);
45196               }
45197
45198               var options = {
45199                 skipSeen: false
45200               };
45201               return parseXML(xml, function (err, results) {
45202                 if (err) {
45203                   return callback(err);
45204                 } else {
45205                   _userDetails = results[0];
45206                   return callback(undefined, _userDetails);
45207                 }
45208               }, options);
45209             }
45210           },
45211           // Load previous changesets for the logged in user
45212           // GET /api/0.6/changesets?user=#id
45213           userChangesets: function userChangesets(callback) {
45214             if (_userChangesets) {
45215               // retrieve cached
45216               return callback(undefined, _userChangesets);
45217             }
45218
45219             this.userDetails(wrapcb(this, gotDetails, _connectionID));
45220
45221             function gotDetails(err, user) {
45222               if (err) {
45223                 return callback(err);
45224               }
45225
45226               oauth.xhr({
45227                 method: 'GET',
45228                 path: '/api/0.6/changesets?user=' + user.id
45229               }, wrapcb(this, done, _connectionID));
45230             }
45231
45232             function done(err, xml) {
45233               if (err) {
45234                 return callback(err);
45235               }
45236
45237               _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
45238                 return {
45239                   tags: getTags(changeset)
45240                 };
45241               }).filter(function (changeset) {
45242                 var comment = changeset.tags.comment;
45243                 return comment && comment !== '';
45244               });
45245               return callback(undefined, _userChangesets);
45246             }
45247           },
45248           // Fetch the status of the OSM API
45249           // GET /api/capabilities
45250           status: function status(callback) {
45251             var url = urlroot + '/api/capabilities';
45252             var errback = wrapcb(this, done, _connectionID);
45253             d3_xml(url).then(function (data) {
45254               errback(null, data);
45255             })["catch"](function (err) {
45256               errback(err.message);
45257             });
45258
45259             function done(err, xml) {
45260               if (err) {
45261                 // the status is null if no response could be retrieved
45262                 return callback(err, null);
45263               } // update blocklists
45264
45265
45266               var elements = xml.getElementsByTagName('blacklist');
45267               var regexes = [];
45268
45269               for (var i = 0; i < elements.length; i++) {
45270                 var regexString = elements[i].getAttribute('regex'); // needs unencode?
45271
45272                 if (regexString) {
45273                   try {
45274                     var regex = new RegExp(regexString);
45275                     regexes.push(regex);
45276                   } catch (e) {
45277                     /* noop */
45278                   }
45279                 }
45280               }
45281
45282               if (regexes.length) {
45283                 _imageryBlocklists = regexes;
45284               }
45285
45286               if (_rateLimitError) {
45287                 return callback(_rateLimitError, 'rateLimited');
45288               } else {
45289                 var waynodes = xml.getElementsByTagName('waynodes');
45290                 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
45291                 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
45292                 var apiStatus = xml.getElementsByTagName('status');
45293                 var val = apiStatus[0].getAttribute('api');
45294                 return callback(undefined, val);
45295               }
45296             }
45297           },
45298           // Calls `status` and dispatches an `apiStatusChange` event if the returned
45299           // status differs from the cached status.
45300           reloadApiStatus: function reloadApiStatus() {
45301             // throttle to avoid unnecessary API calls
45302             if (!this.throttledReloadApiStatus) {
45303               var that = this;
45304               this.throttledReloadApiStatus = throttle(function () {
45305                 that.status(function (err, status) {
45306                   if (status !== _cachedApiStatus) {
45307                     _cachedApiStatus = status;
45308                     dispatch$6.call('apiStatusChange', that, err, status);
45309                   }
45310                 });
45311               }, 500);
45312             }
45313
45314             this.throttledReloadApiStatus();
45315           },
45316           // Returns the maximum number of nodes a single way can have
45317           maxWayNodes: function maxWayNodes() {
45318             return _maxWayNodes;
45319           },
45320           // Load data (entities) from the API in tiles
45321           // GET /api/0.6/map?bbox=
45322           loadTiles: function loadTiles(projection, callback) {
45323             if (_off) return; // determine the needed tiles to cover the view
45324
45325             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
45326
45327             var hadRequests = hasInflightRequests(_tileCache);
45328             abortUnwantedRequests$3(_tileCache, tiles);
45329
45330             if (hadRequests && !hasInflightRequests(_tileCache)) {
45331               dispatch$6.call('loaded'); // stop the spinner
45332             } // issue new requests..
45333
45334
45335             tiles.forEach(function (tile) {
45336               this.loadTile(tile, callback);
45337             }, this);
45338           },
45339           // Load a single data tile
45340           // GET /api/0.6/map?bbox=
45341           loadTile: function loadTile(tile, callback) {
45342             if (_off) return;
45343             if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45344
45345             if (!hasInflightRequests(_tileCache)) {
45346               dispatch$6.call('loading'); // start the spinner
45347             }
45348
45349             var path = '/api/0.6/map.json?bbox=';
45350             var options = {
45351               skipSeen: true
45352             };
45353             _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
45354
45355             function tileCallback(err, parsed) {
45356               delete _tileCache.inflight[tile.id];
45357
45358               if (!err) {
45359                 delete _tileCache.toLoad[tile.id];
45360                 _tileCache.loaded[tile.id] = true;
45361                 var bbox = tile.extent.bbox();
45362                 bbox.id = tile.id;
45363
45364                 _tileCache.rtree.insert(bbox);
45365               }
45366
45367               if (callback) {
45368                 callback(err, Object.assign({
45369                   data: parsed
45370                 }, tile));
45371               }
45372
45373               if (!hasInflightRequests(_tileCache)) {
45374                 dispatch$6.call('loaded'); // stop the spinner
45375               }
45376             }
45377           },
45378           isDataLoaded: function isDataLoaded(loc) {
45379             var bbox = {
45380               minX: loc[0],
45381               minY: loc[1],
45382               maxX: loc[0],
45383               maxY: loc[1]
45384             };
45385             return _tileCache.rtree.collides(bbox);
45386           },
45387           // load the tile that covers the given `loc`
45388           loadTileAtLoc: function loadTileAtLoc(loc, callback) {
45389             // Back off if the toLoad queue is filling up.. re #6417
45390             // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
45391             // let users safely edit geometries which extend to unloaded tiles.  We can drop some.)
45392             if (Object.keys(_tileCache.toLoad).length > 50) return;
45393             var k = geoZoomToScale(_tileZoom$3 + 1);
45394             var offset = geoRawMercator().scale(k)(loc);
45395             var projection = geoRawMercator().transform({
45396               k: k,
45397               x: -offset[0],
45398               y: -offset[1]
45399             });
45400             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection);
45401             tiles.forEach(function (tile) {
45402               if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45403               _tileCache.toLoad[tile.id] = true;
45404               this.loadTile(tile, callback);
45405             }, this);
45406           },
45407           // Load notes from the API in tiles
45408           // GET /api/0.6/notes?bbox=
45409           loadNotes: function loadNotes(projection, noteOptions) {
45410             noteOptions = Object.assign({
45411               limit: 10000,
45412               closed: 7
45413             }, noteOptions);
45414             if (_off) return;
45415             var that = this;
45416             var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
45417
45418             var throttleLoadUsers = throttle(function () {
45419               var uids = Object.keys(_userCache.toLoad);
45420               if (!uids.length) return;
45421               that.loadUsers(uids, function () {}); // eagerly load user details
45422             }, 750); // determine the needed tiles to cover the view
45423
45424
45425             var tiles = tiler$5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
45426
45427             abortUnwantedRequests$3(_noteCache, tiles); // issue new requests..
45428
45429             tiles.forEach(function (tile) {
45430               if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
45431               var options = {
45432                 skipSeen: false
45433               };
45434               _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
45435                 delete _noteCache.inflight[tile.id];
45436
45437                 if (!err) {
45438                   _noteCache.loaded[tile.id] = true;
45439                 }
45440
45441                 throttleLoadUsers();
45442                 dispatch$6.call('loadedNotes');
45443               }, options);
45444             });
45445           },
45446           // Create a note
45447           // POST /api/0.6/notes?params
45448           postNoteCreate: function postNoteCreate(note, callback) {
45449             if (!this.authenticated()) {
45450               return callback({
45451                 message: 'Not Authenticated',
45452                 status: -3
45453               }, note);
45454             }
45455
45456             if (_noteCache.inflightPost[note.id]) {
45457               return callback({
45458                 message: 'Note update already inflight',
45459                 status: -2
45460               }, note);
45461             }
45462
45463             if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
45464
45465             var comment = note.newComment;
45466
45467             if (note.newCategory && note.newCategory !== 'None') {
45468               comment += ' #' + note.newCategory;
45469             }
45470
45471             var path = '/api/0.6/notes?' + utilQsString({
45472               lon: note.loc[0],
45473               lat: note.loc[1],
45474               text: comment
45475             });
45476             _noteCache.inflightPost[note.id] = oauth.xhr({
45477               method: 'POST',
45478               path: path
45479             }, wrapcb(this, done, _connectionID));
45480
45481             function done(err, xml) {
45482               delete _noteCache.inflightPost[note.id];
45483
45484               if (err) {
45485                 return callback(err);
45486               } // we get the updated note back, remove from caches and reparse..
45487
45488
45489               this.removeNote(note);
45490               var options = {
45491                 skipSeen: false
45492               };
45493               return parseXML(xml, function (err, results) {
45494                 if (err) {
45495                   return callback(err);
45496                 } else {
45497                   return callback(undefined, results[0]);
45498                 }
45499               }, options);
45500             }
45501           },
45502           // Update a note
45503           // POST /api/0.6/notes/#id/comment?text=comment
45504           // POST /api/0.6/notes/#id/close?text=comment
45505           // POST /api/0.6/notes/#id/reopen?text=comment
45506           postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
45507             if (!this.authenticated()) {
45508               return callback({
45509                 message: 'Not Authenticated',
45510                 status: -3
45511               }, note);
45512             }
45513
45514             if (_noteCache.inflightPost[note.id]) {
45515               return callback({
45516                 message: 'Note update already inflight',
45517                 status: -2
45518               }, note);
45519             }
45520
45521             var action;
45522
45523             if (note.status !== 'closed' && newStatus === 'closed') {
45524               action = 'close';
45525             } else if (note.status !== 'open' && newStatus === 'open') {
45526               action = 'reopen';
45527             } else {
45528               action = 'comment';
45529               if (!note.newComment) return; // when commenting, comment required
45530             }
45531
45532             var path = '/api/0.6/notes/' + note.id + '/' + action;
45533
45534             if (note.newComment) {
45535               path += '?' + utilQsString({
45536                 text: note.newComment
45537               });
45538             }
45539
45540             _noteCache.inflightPost[note.id] = oauth.xhr({
45541               method: 'POST',
45542               path: path
45543             }, wrapcb(this, done, _connectionID));
45544
45545             function done(err, xml) {
45546               delete _noteCache.inflightPost[note.id];
45547
45548               if (err) {
45549                 return callback(err);
45550               } // we get the updated note back, remove from caches and reparse..
45551
45552
45553               this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
45554
45555               if (action === 'close') {
45556                 _noteCache.closed[note.id] = true;
45557               } else if (action === 'reopen') {
45558                 delete _noteCache.closed[note.id];
45559               }
45560
45561               var options = {
45562                 skipSeen: false
45563               };
45564               return parseXML(xml, function (err, results) {
45565                 if (err) {
45566                   return callback(err);
45567                 } else {
45568                   return callback(undefined, results[0]);
45569                 }
45570               }, options);
45571             }
45572           },
45573           "switch": function _switch(options) {
45574             urlroot = options.urlroot;
45575             oauth.options(Object.assign({
45576               url: urlroot,
45577               loading: authLoading,
45578               done: authDone
45579             }, options));
45580             this.reset();
45581             this.userChangesets(function () {}); // eagerly load user details/changesets
45582
45583             dispatch$6.call('change');
45584             return this;
45585           },
45586           toggle: function toggle(val) {
45587             _off = !val;
45588             return this;
45589           },
45590           isChangesetInflight: function isChangesetInflight() {
45591             return !!_changeset.inflight;
45592           },
45593           // get/set cached data
45594           // This is used to save/restore the state when entering/exiting the walkthrough
45595           // Also used for testing purposes.
45596           caches: function caches(obj) {
45597             function cloneCache(source) {
45598               var target = {};
45599               Object.keys(source).forEach(function (k) {
45600                 if (k === 'rtree') {
45601                   target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
45602                 } else if (k === 'note') {
45603                   target.note = {};
45604                   Object.keys(source.note).forEach(function (id) {
45605                     target.note[id] = osmNote(source.note[id]); // copy notes
45606                   });
45607                 } else {
45608                   target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
45609                 }
45610               });
45611               return target;
45612             }
45613
45614             if (!arguments.length) {
45615               return {
45616                 tile: cloneCache(_tileCache),
45617                 note: cloneCache(_noteCache),
45618                 user: cloneCache(_userCache)
45619               };
45620             } // access caches directly for testing (e.g., loading notes rtree)
45621
45622
45623             if (obj === 'get') {
45624               return {
45625                 tile: _tileCache,
45626                 note: _noteCache,
45627                 user: _userCache
45628               };
45629             }
45630
45631             if (obj.tile) {
45632               _tileCache = obj.tile;
45633               _tileCache.inflight = {};
45634             }
45635
45636             if (obj.note) {
45637               _noteCache = obj.note;
45638               _noteCache.inflight = {};
45639               _noteCache.inflightPost = {};
45640             }
45641
45642             if (obj.user) {
45643               _userCache = obj.user;
45644             }
45645
45646             return this;
45647           },
45648           logout: function logout() {
45649             _userChangesets = undefined;
45650             _userDetails = undefined;
45651             oauth.logout();
45652             dispatch$6.call('change');
45653             return this;
45654           },
45655           authenticated: function authenticated() {
45656             return oauth.authenticated();
45657           },
45658           authenticate: function authenticate(callback) {
45659             var that = this;
45660             var cid = _connectionID;
45661             _userChangesets = undefined;
45662             _userDetails = undefined;
45663
45664             function done(err, res) {
45665               if (err) {
45666                 if (callback) callback(err);
45667                 return;
45668               }
45669
45670               if (that.getConnectionId() !== cid) {
45671                 if (callback) callback({
45672                   message: 'Connection Switched',
45673                   status: -1
45674                 });
45675                 return;
45676               }
45677
45678               _rateLimitError = undefined;
45679               dispatch$6.call('change');
45680               if (callback) callback(err, res);
45681               that.userChangesets(function () {}); // eagerly load user details/changesets
45682             }
45683
45684             return oauth.authenticate(done);
45685           },
45686           imageryBlocklists: function imageryBlocklists() {
45687             return _imageryBlocklists;
45688           },
45689           tileZoom: function tileZoom(val) {
45690             if (!arguments.length) return _tileZoom$3;
45691             _tileZoom$3 = val;
45692             return this;
45693           },
45694           // get all cached notes covering the viewport
45695           notes: function notes(projection) {
45696             var viewport = projection.clipExtent();
45697             var min = [viewport[0][0], viewport[1][1]];
45698             var max = [viewport[1][0], viewport[0][1]];
45699             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
45700             return _noteCache.rtree.search(bbox).map(function (d) {
45701               return d.data;
45702             });
45703           },
45704           // get a single note from the cache
45705           getNote: function getNote(id) {
45706             return _noteCache.note[id];
45707           },
45708           // remove a single note from the cache
45709           removeNote: function removeNote(note) {
45710             if (!(note instanceof osmNote) || !note.id) return;
45711             delete _noteCache.note[note.id];
45712             updateRtree$3(encodeNoteRtree(note), false); // false = remove
45713           },
45714           // replace a single note in the cache
45715           replaceNote: function replaceNote(note) {
45716             if (!(note instanceof osmNote) || !note.id) return;
45717             _noteCache.note[note.id] = note;
45718             updateRtree$3(encodeNoteRtree(note), true); // true = replace
45719
45720             return note;
45721           },
45722           // Get an array of note IDs closed during this session.
45723           // Used to populate `closed:note` changeset tag
45724           getClosedIDs: function getClosedIDs() {
45725             return Object.keys(_noteCache.closed).sort();
45726           }
45727         };
45728
45729         var _apibase = 'https://wiki.openstreetmap.org/w/api.php';
45730         var _inflight$1 = {};
45731         var _wikibaseCache = {};
45732         var _localeIDs = {
45733           en: false
45734         };
45735
45736         var debouncedRequest = debounce(request, 500, {
45737           leading: false
45738         });
45739
45740         function request(url, callback) {
45741           if (_inflight$1[url]) return;
45742           var controller = new AbortController();
45743           _inflight$1[url] = controller;
45744           d3_json(url, {
45745             signal: controller.signal
45746           }).then(function (result) {
45747             delete _inflight$1[url];
45748             if (callback) callback(null, result);
45749           })["catch"](function (err) {
45750             delete _inflight$1[url];
45751             if (err.name === 'AbortError') return;
45752             if (callback) callback(err.message);
45753           });
45754         }
45755
45756         var serviceOsmWikibase = {
45757           init: function init() {
45758             _inflight$1 = {};
45759             _wikibaseCache = {};
45760             _localeIDs = {};
45761           },
45762           reset: function reset() {
45763             Object.values(_inflight$1).forEach(function (controller) {
45764               controller.abort();
45765             });
45766             _inflight$1 = {};
45767           },
45768
45769           /**
45770            * Get the best value for the property, or undefined if not found
45771            * @param entity object from wikibase
45772            * @param property string e.g. 'P4' for image
45773            * @param langCode string e.g. 'fr' for French
45774            */
45775           claimToValue: function claimToValue(entity, property, langCode) {
45776             if (!entity.claims[property]) return undefined;
45777             var locale = _localeIDs[langCode];
45778             var preferredPick, localePick;
45779             entity.claims[property].forEach(function (stmt) {
45780               // If exists, use value limited to the needed language (has a qualifier P26 = locale)
45781               // Or if not found, use the first value with the "preferred" rank
45782               if (!preferredPick && stmt.rank === 'preferred') {
45783                 preferredPick = stmt;
45784               }
45785
45786               if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
45787                 localePick = stmt;
45788               }
45789             });
45790             var result = localePick || preferredPick;
45791
45792             if (result) {
45793               var datavalue = result.mainsnak.datavalue;
45794               return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
45795             } else {
45796               return undefined;
45797             }
45798           },
45799
45800           /**
45801            * Convert monolingual property into a key-value object (language -> value)
45802            * @param entity object from wikibase
45803            * @param property string e.g. 'P31' for monolingual wiki page title
45804            */
45805           monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
45806             if (!entity || !entity.claims[property]) return undefined;
45807             return entity.claims[property].reduce(function (acc, obj) {
45808               var value = obj.mainsnak.datavalue.value;
45809               acc[value.language] = value.text;
45810               return acc;
45811             }, {});
45812           },
45813           toSitelink: function toSitelink(key, value) {
45814             var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
45815             return result.replace(/_/g, ' ').trim();
45816           },
45817           //
45818           // Pass params object of the form:
45819           // {
45820           //   key: 'string',
45821           //   value: 'string',
45822           //   langCode: 'string'
45823           // }
45824           //
45825           getEntity: function getEntity(params, callback) {
45826             var doRequest = params.debounce ? debouncedRequest : request;
45827             var that = this;
45828             var titles = [];
45829             var result = {};
45830             var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
45831             var keySitelink = params.key ? this.toSitelink(params.key) : false;
45832             var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
45833             var localeSitelink;
45834
45835             if (params.langCodes) {
45836               params.langCodes.forEach(function (langCode) {
45837                 if (_localeIDs[langCode] === undefined) {
45838                   // If this is the first time we are asking about this locale,
45839                   // fetch corresponding entity (if it exists), and cache it.
45840                   // If there is no such entry, cache `false` value to avoid re-requesting it.
45841                   localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
45842                   titles.push(localeSitelink);
45843                 }
45844               });
45845             }
45846
45847             if (rtypeSitelink) {
45848               if (_wikibaseCache[rtypeSitelink]) {
45849                 result.rtype = _wikibaseCache[rtypeSitelink];
45850               } else {
45851                 titles.push(rtypeSitelink);
45852               }
45853             }
45854
45855             if (keySitelink) {
45856               if (_wikibaseCache[keySitelink]) {
45857                 result.key = _wikibaseCache[keySitelink];
45858               } else {
45859                 titles.push(keySitelink);
45860               }
45861             }
45862
45863             if (tagSitelink) {
45864               if (_wikibaseCache[tagSitelink]) {
45865                 result.tag = _wikibaseCache[tagSitelink];
45866               } else {
45867                 titles.push(tagSitelink);
45868               }
45869             }
45870
45871             if (!titles.length) {
45872               // Nothing to do, we already had everything in the cache
45873               return callback(null, result);
45874             } // Requesting just the user language code
45875             // If backend recognizes the code, it will perform proper fallbacks,
45876             // and the result will contain the requested code. If not, all values are returned:
45877             // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
45878             // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
45879
45880
45881             var obj = {
45882               action: 'wbgetentities',
45883               sites: 'wiki',
45884               titles: titles.join('|'),
45885               languages: params.langCodes.join('|'),
45886               languagefallback: 1,
45887               origin: '*',
45888               format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
45889               // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
45890               // formatversion: 2,
45891
45892             };
45893             var url = _apibase + '?' + utilQsString(obj);
45894             doRequest(url, function (err, d) {
45895               if (err) {
45896                 callback(err);
45897               } else if (!d.success || d.error) {
45898                 callback(d.error.messages.map(function (v) {
45899                   return v.html['*'];
45900                 }).join('<br>'));
45901               } else {
45902                 var localeID = false;
45903                 Object.values(d.entities).forEach(function (res) {
45904                   if (res.missing !== '') {
45905                     var title = res.sitelinks.wiki.title;
45906
45907                     if (title === rtypeSitelink) {
45908                       _wikibaseCache[rtypeSitelink] = res;
45909                       result.rtype = res;
45910                     } else if (title === keySitelink) {
45911                       _wikibaseCache[keySitelink] = res;
45912                       result.key = res;
45913                     } else if (title === tagSitelink) {
45914                       _wikibaseCache[tagSitelink] = res;
45915                       result.tag = res;
45916                     } else if (title === localeSitelink) {
45917                       localeID = res.id;
45918                     } else {
45919                       console.log('Unexpected title ' + title); // eslint-disable-line no-console
45920                     }
45921                   }
45922                 });
45923
45924                 if (localeSitelink) {
45925                   // If locale ID is not found, store false to prevent repeated queries
45926                   that.addLocale(params.langCodes[0], localeID);
45927                 }
45928
45929                 callback(null, result);
45930               }
45931             });
45932           },
45933           //
45934           // Pass params object of the form:
45935           // {
45936           //   key: 'string',     // required
45937           //   value: 'string'    // optional
45938           // }
45939           //
45940           // Get an result object used to display tag documentation
45941           // {
45942           //   title:        'string',
45943           //   description:  'string',
45944           //   editURL:      'string',
45945           //   imageURL:     'string',
45946           //   wiki:         { title: 'string', text: 'string', url: 'string' }
45947           // }
45948           //
45949           getDocs: function getDocs(params, callback) {
45950             var that = this;
45951             var langCodes = _mainLocalizer.localeCodes().map(function (code) {
45952               return code.toLowerCase();
45953             });
45954             params.langCodes = langCodes;
45955             this.getEntity(params, function (err, data) {
45956               if (err) {
45957                 callback(err);
45958                 return;
45959               }
45960
45961               var entity = data.rtype || data.tag || data.key;
45962
45963               if (!entity) {
45964                 callback('No entity');
45965                 return;
45966               }
45967
45968               var i;
45969               var description;
45970
45971               for (i in langCodes) {
45972                 var _code = langCodes[i];
45973
45974                 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
45975                   description = entity.descriptions[_code];
45976                   break;
45977                 }
45978               }
45979
45980               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
45981
45982               var result = {
45983                 title: entity.title,
45984                 description: description ? description.value : '',
45985                 descriptionLocaleCode: description ? description.language : '',
45986                 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
45987               }; // add image
45988
45989               if (entity.claims) {
45990                 var imageroot;
45991                 var image = that.claimToValue(entity, 'P4', langCodes[0]);
45992
45993                 if (image) {
45994                   imageroot = 'https://commons.wikimedia.org/w/index.php';
45995                 } else {
45996                   image = that.claimToValue(entity, 'P28', langCodes[0]);
45997
45998                   if (image) {
45999                     imageroot = 'https://wiki.openstreetmap.org/w/index.php';
46000                   }
46001                 }
46002
46003                 if (imageroot && image) {
46004                   result.imageURL = imageroot + '?' + utilQsString({
46005                     title: 'Special:Redirect/file/' + image,
46006                     width: 400
46007                   });
46008                 }
46009               } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
46010               // If neither tag nor key data item contain a wiki page in the needed language nor English,
46011               // get the first found wiki page from either the tag or the key item.
46012
46013
46014               var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
46015               var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
46016               var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
46017               var wikis = [rtypeWiki, tagWiki, keyWiki];
46018
46019               for (i in wikis) {
46020                 var wiki = wikis[i];
46021
46022                 for (var j in langCodes) {
46023                   var code = langCodes[j];
46024                   var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
46025                   var info = getWikiInfo(wiki, code, referenceId);
46026
46027                   if (info) {
46028                     result.wiki = info;
46029                     break;
46030                   }
46031                 }
46032
46033                 if (result.wiki) break;
46034               }
46035
46036               callback(null, result); // Helper method to get wiki info if a given language exists
46037
46038               function getWikiInfo(wiki, langCode, tKey) {
46039                 if (wiki && wiki[langCode]) {
46040                   return {
46041                     title: wiki[langCode],
46042                     text: tKey,
46043                     url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
46044                   };
46045                 }
46046               }
46047             });
46048           },
46049           addLocale: function addLocale(langCode, qid) {
46050             // Makes it easier to unit test
46051             _localeIDs[langCode] = qid;
46052           },
46053           apibase: function apibase(val) {
46054             if (!arguments.length) return _apibase;
46055             _apibase = val;
46056             return this;
46057           }
46058         };
46059
46060         var jsonpCache = {};
46061         window.jsonpCache = jsonpCache;
46062         function jsonpRequest(url, callback) {
46063           var request = {
46064             abort: function abort() {}
46065           };
46066
46067           if (window.JSONP_FIX) {
46068             if (window.JSONP_DELAY === 0) {
46069               callback(window.JSONP_FIX);
46070             } else {
46071               var t = window.setTimeout(function () {
46072                 callback(window.JSONP_FIX);
46073               }, window.JSONP_DELAY || 0);
46074
46075               request.abort = function () {
46076                 window.clearTimeout(t);
46077               };
46078             }
46079
46080             return request;
46081           }
46082
46083           function rand() {
46084             var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
46085             var c = '';
46086             var i = -1;
46087
46088             while (++i < 15) {
46089               c += chars.charAt(Math.floor(Math.random() * 52));
46090             }
46091
46092             return c;
46093           }
46094
46095           function create(url) {
46096             var e = url.match(/callback=(\w+)/);
46097             var c = e ? e[1] : rand();
46098
46099             jsonpCache[c] = function (data) {
46100               if (jsonpCache[c]) {
46101                 callback(data);
46102               }
46103
46104               finalize();
46105             };
46106
46107             function finalize() {
46108               delete jsonpCache[c];
46109               script.remove();
46110             }
46111
46112             request.abort = finalize;
46113             return 'jsonpCache.' + c;
46114           }
46115
46116           var cb = create(url);
46117           var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
46118           return request;
46119         }
46120
46121         var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
46122         var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
46123         var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
46124         var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
46125         var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
46126         var maxResults$2 = 2000;
46127         var tileZoom$2 = 16.5;
46128         var tiler$6 = utilTiler().zoomExtent([tileZoom$2, tileZoom$2]).skipNullIsland(true);
46129         var dispatch$7 = dispatch('loadedImages', 'viewerChanged');
46130         var minHfov = 10; // zoom in degrees:  20, 10, 5
46131
46132         var maxHfov = 90; // zoom out degrees
46133
46134         var defaultHfov = 45;
46135         var _hires = false;
46136         var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
46137
46138         var _currScene = 0;
46139
46140         var _ssCache;
46141
46142         var _pannellumViewer;
46143
46144         var _sceneOptions = {
46145           showFullscreenCtrl: false,
46146           autoLoad: true,
46147           compass: true,
46148           yaw: 0,
46149           minHfov: minHfov,
46150           maxHfov: maxHfov,
46151           hfov: defaultHfov,
46152           type: 'cubemap',
46153           cubeMap: []
46154         };
46155
46156         var _loadViewerPromise$2;
46157         /**
46158          * abortRequest().
46159          */
46160
46161
46162         function abortRequest$6(i) {
46163           i.abort();
46164         }
46165         /**
46166          * localeTimeStamp().
46167          */
46168
46169
46170         function localeTimestamp(s) {
46171           if (!s) return null;
46172           var options = {
46173             day: 'numeric',
46174             month: 'short',
46175             year: 'numeric'
46176           };
46177           var d = new Date(s);
46178           if (isNaN(d.getTime())) return null;
46179           return d.toLocaleString(_mainLocalizer.localeCode(), options);
46180         }
46181         /**
46182          * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
46183          */
46184
46185
46186         function loadTiles$2(which, url, projection, margin) {
46187           var tiles = tiler$6.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
46188
46189           var cache = _ssCache[which];
46190           Object.keys(cache.inflight).forEach(function (k) {
46191             var wanted = tiles.find(function (tile) {
46192               return k.indexOf(tile.id + ',') === 0;
46193             });
46194
46195             if (!wanted) {
46196               abortRequest$6(cache.inflight[k]);
46197               delete cache.inflight[k];
46198             }
46199           });
46200           tiles.forEach(function (tile) {
46201             return loadNextTilePage$2(which, url, tile);
46202           });
46203         }
46204         /**
46205          * loadNextTilePage() load data for the next tile page in line.
46206          */
46207
46208
46209         function loadNextTilePage$2(which, url, tile) {
46210           var cache = _ssCache[which];
46211           var nextPage = cache.nextPage[tile.id] || 0;
46212           var id = tile.id + ',' + String(nextPage);
46213           if (cache.loaded[id] || cache.inflight[id]) return;
46214           cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
46215             cache.loaded[id] = true;
46216             delete cache.inflight[id];
46217             if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
46218
46219             bubbles.shift();
46220             var features = bubbles.map(function (bubble) {
46221               if (cache.points[bubble.id]) return null; // skip duplicates
46222
46223               var loc = [bubble.lo, bubble.la];
46224               var d = {
46225                 loc: loc,
46226                 key: bubble.id,
46227                 ca: bubble.he,
46228                 captured_at: bubble.cd,
46229                 captured_by: 'microsoft',
46230                 // nbn: bubble.nbn,
46231                 // pbn: bubble.pbn,
46232                 // ad: bubble.ad,
46233                 // rn: bubble.rn,
46234                 pr: bubble.pr,
46235                 // previous
46236                 ne: bubble.ne,
46237                 // next
46238                 pano: true,
46239                 sequenceKey: null
46240               };
46241               cache.points[bubble.id] = d; // a sequence starts here
46242
46243               if (bubble.pr === undefined) {
46244                 cache.leaders.push(bubble.id);
46245               }
46246
46247               return {
46248                 minX: loc[0],
46249                 minY: loc[1],
46250                 maxX: loc[0],
46251                 maxY: loc[1],
46252                 data: d
46253               };
46254             }).filter(Boolean);
46255             cache.rtree.load(features);
46256             connectSequences();
46257
46258             if (which === 'bubbles') {
46259               dispatch$7.call('loadedImages');
46260             }
46261           });
46262         } // call this sometimes to connect the bubbles into sequences
46263
46264
46265         function connectSequences() {
46266           var cache = _ssCache.bubbles;
46267           var keepLeaders = [];
46268
46269           for (var i = 0; i < cache.leaders.length; i++) {
46270             var bubble = cache.points[cache.leaders[i]];
46271             var seen = {}; // try to make a sequence.. use the key of the leader bubble.
46272
46273             var sequence = {
46274               key: bubble.key,
46275               bubbles: []
46276             };
46277             var complete = false;
46278
46279             do {
46280               sequence.bubbles.push(bubble);
46281               seen[bubble.key] = true;
46282
46283               if (bubble.ne === undefined) {
46284                 complete = true;
46285               } else {
46286                 bubble = cache.points[bubble.ne]; // advance to next
46287               }
46288             } while (bubble && !seen[bubble.key] && !complete);
46289
46290             if (complete) {
46291               _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
46292
46293               for (var j = 0; j < sequence.bubbles.length; j++) {
46294                 sequence.bubbles[j].sequenceKey = sequence.key;
46295               } // create a GeoJSON LineString
46296
46297
46298               sequence.geojson = {
46299                 type: 'LineString',
46300                 properties: {
46301                   captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
46302                   captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
46303                   key: sequence.key
46304                 },
46305                 coordinates: sequence.bubbles.map(function (d) {
46306                   return d.loc;
46307                 })
46308               };
46309             } else {
46310               keepLeaders.push(cache.leaders[i]);
46311             }
46312           } // couldn't complete these, save for later
46313
46314
46315           cache.leaders = keepLeaders;
46316         }
46317         /**
46318          * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
46319          */
46320
46321
46322         function getBubbles(url, tile, callback) {
46323           var rect = tile.extent.rectangle();
46324           var urlForRequest = url + utilQsString({
46325             n: rect[3],
46326             s: rect[1],
46327             e: rect[2],
46328             w: rect[0],
46329             c: maxResults$2,
46330             appkey: bubbleAppKey,
46331             jsCallback: '{callback}'
46332           });
46333           return jsonpRequest(urlForRequest, function (data) {
46334             if (!data || data.error) {
46335               callback(null);
46336             } else {
46337               callback(data);
46338             }
46339           });
46340         } // partition viewport into higher zoom tiles
46341
46342
46343         function partitionViewport$2(projection) {
46344           var z = geoScaleToZoom(projection.scale());
46345           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
46346
46347           var tiler = utilTiler().zoomExtent([z2, z2]);
46348           return tiler.getTiles(projection).map(function (tile) {
46349             return tile.extent;
46350           });
46351         } // no more than `limit` results per partition.
46352
46353
46354         function searchLimited$2(limit, projection, rtree) {
46355           limit = limit || 5;
46356           return partitionViewport$2(projection).reduce(function (result, extent) {
46357             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
46358               return d.data;
46359             });
46360             return found.length ? result.concat(found) : result;
46361           }, []);
46362         }
46363         /**
46364          * loadImage()
46365          */
46366
46367
46368         function loadImage(imgInfo) {
46369           return new Promise(function (resolve) {
46370             var img = new Image();
46371
46372             img.onload = function () {
46373               var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
46374               var ctx = canvas.getContext('2d');
46375               ctx.drawImage(img, imgInfo.x, imgInfo.y);
46376               resolve({
46377                 imgInfo: imgInfo,
46378                 status: 'ok'
46379               });
46380             };
46381
46382             img.onerror = function () {
46383               resolve({
46384                 data: imgInfo,
46385                 status: 'error'
46386               });
46387             };
46388
46389             img.setAttribute('crossorigin', '');
46390             img.src = imgInfo.url;
46391           });
46392         }
46393         /**
46394          * loadCanvas()
46395          */
46396
46397
46398         function loadCanvas(imageGroup) {
46399           return Promise.all(imageGroup.map(loadImage)).then(function (data) {
46400             var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
46401             var which = {
46402               '01': 0,
46403               '02': 1,
46404               '03': 2,
46405               '10': 3,
46406               '11': 4,
46407               '12': 5
46408             };
46409             var face = data[0].imgInfo.face;
46410             _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
46411             return {
46412               status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
46413             };
46414           });
46415         }
46416         /**
46417          * loadFaces()
46418          */
46419
46420
46421         function loadFaces(faceGroup) {
46422           return Promise.all(faceGroup.map(loadCanvas)).then(function () {
46423             return {
46424               status: 'loadFaces done'
46425             };
46426           });
46427         }
46428
46429         function setupCanvas(selection, reset) {
46430           if (reset) {
46431             selection.selectAll('#ideditor-stitcher-canvases').remove();
46432           } // Add the Streetside working canvases. These are used for 'stitching', or combining,
46433           // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
46434
46435
46436           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) {
46437             return 'ideditor-' + d;
46438           }).attr('width', _resolution).attr('height', _resolution);
46439         }
46440
46441         function qkToXY(qk) {
46442           var x = 0;
46443           var y = 0;
46444           var scale = 256;
46445
46446           for (var i = qk.length; i > 0; i--) {
46447             var key = qk[i - 1];
46448             x += +(key === '1' || key === '3') * scale;
46449             y += +(key === '2' || key === '3') * scale;
46450             scale *= 2;
46451           }
46452
46453           return [x, y];
46454         }
46455
46456         function getQuadKeys() {
46457           var dim = _resolution / 256;
46458           var quadKeys;
46459
46460           if (dim === 16) {
46461             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'];
46462           } else if (dim === 8) {
46463             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'];
46464           } else if (dim === 4) {
46465             quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
46466           } else {
46467             // dim === 2
46468             quadKeys = ['0', '1', '2', '3'];
46469           }
46470
46471           return quadKeys;
46472         }
46473
46474         var serviceStreetside = {
46475           /**
46476            * init() initialize streetside.
46477            */
46478           init: function init() {
46479             if (!_ssCache) {
46480               this.reset();
46481             }
46482
46483             this.event = utilRebind(this, dispatch$7, 'on');
46484           },
46485
46486           /**
46487            * reset() reset the cache.
46488            */
46489           reset: function reset() {
46490             if (_ssCache) {
46491               Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$6);
46492             }
46493
46494             _ssCache = {
46495               bubbles: {
46496                 inflight: {},
46497                 loaded: {},
46498                 nextPage: {},
46499                 rtree: new RBush(),
46500                 points: {},
46501                 leaders: []
46502               },
46503               sequences: {}
46504             };
46505           },
46506
46507           /**
46508            * bubbles()
46509            */
46510           bubbles: function bubbles(projection) {
46511             var limit = 5;
46512             return searchLimited$2(limit, projection, _ssCache.bubbles.rtree);
46513           },
46514           cachedImage: function cachedImage(imageKey) {
46515             return _ssCache.bubbles.points[imageKey];
46516           },
46517           sequences: function sequences(projection) {
46518             var viewport = projection.clipExtent();
46519             var min = [viewport[0][0], viewport[1][1]];
46520             var max = [viewport[1][0], viewport[0][1]];
46521             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
46522             var seen = {};
46523             var results = []; // all sequences for bubbles in viewport
46524
46525             _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
46526               var key = d.data.sequenceKey;
46527
46528               if (key && !seen[key]) {
46529                 seen[key] = true;
46530                 results.push(_ssCache.sequences[key].geojson);
46531               }
46532             });
46533
46534             return results;
46535           },
46536
46537           /**
46538            * loadBubbles()
46539            */
46540           loadBubbles: function loadBubbles(projection, margin) {
46541             // by default: request 2 nearby tiles so we can connect sequences.
46542             if (margin === undefined) margin = 2;
46543             loadTiles$2('bubbles', bubbleApi, projection, margin);
46544           },
46545           viewer: function viewer() {
46546             return _pannellumViewer;
46547           },
46548           initViewer: function initViewer() {
46549             if (!window.pannellum) return;
46550             if (_pannellumViewer) return;
46551             _currScene += 1;
46552
46553             var sceneID = _currScene.toString();
46554
46555             var options = {
46556               'default': {
46557                 firstScene: sceneID
46558               },
46559               scenes: {}
46560             };
46561             options.scenes[sceneID] = _sceneOptions;
46562             _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
46563           },
46564           ensureViewerLoaded: function ensureViewerLoaded(context) {
46565             if (_loadViewerPromise$2) return _loadViewerPromise$2; // create ms-wrapper, a photo wrapper class
46566
46567             var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
46568             // (used by all to house each custom photo viewer)
46569
46570             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
46571             var that = this;
46572             var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
46573
46574             wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
46575               select(window).on(pointerPrefix + 'move.streetside', function () {
46576                 dispatch$7.call('viewerChanged');
46577               }, true);
46578             }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
46579               select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
46580
46581               var t = timer(function (elapsed) {
46582                 dispatch$7.call('viewerChanged');
46583
46584                 if (elapsed > 2000) {
46585                   t.stop();
46586                 }
46587               });
46588             }).append('div').attr('class', 'photo-attribution fillD');
46589             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
46590             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
46591             controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
46592
46593             wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
46594
46595             context.ui().photoviewer.on('resize.streetside', function () {
46596               if (_pannellumViewer) {
46597                 _pannellumViewer.resize();
46598               }
46599             });
46600             _loadViewerPromise$2 = new Promise(function (resolve, reject) {
46601               var loadedCount = 0;
46602
46603               function loaded() {
46604                 loadedCount += 1; // wait until both files are loaded
46605
46606                 if (loadedCount === 2) resolve();
46607               }
46608
46609               var head = select('head'); // load streetside pannellum viewer css
46610
46611               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 () {
46612                 reject();
46613               }); // load streetside pannellum viewer js
46614
46615               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 () {
46616                 reject();
46617               });
46618             })["catch"](function () {
46619               _loadViewerPromise$2 = null;
46620             });
46621             return _loadViewerPromise$2;
46622
46623             function step(stepBy) {
46624               return function () {
46625                 var viewer = context.container().select('.photoviewer');
46626                 var selected = viewer.empty() ? undefined : viewer.datum();
46627                 if (!selected) return;
46628                 var nextID = stepBy === 1 ? selected.ne : selected.pr;
46629
46630                 var yaw = _pannellumViewer.getYaw();
46631
46632                 var ca = selected.ca + yaw;
46633                 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
46634
46635                 var meters = 35;
46636                 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
46637                 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46638                 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46639                 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
46640                 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
46641
46642                 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
46643                 poly = geoRotate(poly, -angle, origin);
46644                 var extent = poly.reduce(function (extent, point) {
46645                   return extent.extend(geoExtent(point));
46646                 }, geoExtent()); // find nearest other bubble in the search polygon
46647
46648                 var minDist = Infinity;
46649
46650                 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
46651                   if (d.data.key === selected.key) return;
46652                   if (!geoPointInPolygon(d.data.loc, poly)) return;
46653                   var dist = geoVecLength(d.data.loc, selected.loc);
46654                   var theta = selected.ca - d.data.ca;
46655                   var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
46656
46657                   if (minTheta > 20) {
46658                     dist += 5; // penalize distance if camera angles don't match
46659                   }
46660
46661                   if (dist < minDist) {
46662                     nextID = d.data.key;
46663                     minDist = dist;
46664                   }
46665                 });
46666
46667                 var nextBubble = nextID && that.cachedImage(nextID);
46668                 if (!nextBubble) return;
46669                 context.map().centerEase(nextBubble.loc);
46670                 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
46671               };
46672             }
46673           },
46674           yaw: function yaw(_yaw) {
46675             if (typeof _yaw !== 'number') return _yaw;
46676             _sceneOptions.yaw = _yaw;
46677             return this;
46678           },
46679
46680           /**
46681            * showViewer()
46682            */
46683           showViewer: function showViewer(context) {
46684             var wrap = context.container().select('.photoviewer').classed('hide', false);
46685             var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
46686
46687             if (isHidden) {
46688               wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
46689               wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
46690             }
46691
46692             return this;
46693           },
46694
46695           /**
46696            * hideViewer()
46697            */
46698           hideViewer: function hideViewer(context) {
46699             var viewer = context.container().select('.photoviewer');
46700             if (!viewer.empty()) viewer.datum(null);
46701             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
46702             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
46703             this.updateUrlImage(null);
46704             return this.setStyles(context, null, true);
46705           },
46706
46707           /**
46708            * selectImage().
46709            */
46710           selectImage: function selectImage(context, key) {
46711             var that = this;
46712             var d = this.cachedImage(key);
46713             var viewer = context.container().select('.photoviewer');
46714             if (!viewer.empty()) viewer.datum(d);
46715             this.setStyles(context, null, true);
46716             var wrap = context.container().select('.photoviewer .ms-wrapper');
46717             var attribution = wrap.selectAll('.photo-attribution').html('');
46718             wrap.selectAll('.pnlm-load-box') // display "loading.."
46719             .style('display', 'block');
46720             if (!d) return this;
46721             this.updateUrlImage(key);
46722             _sceneOptions.northOffset = d.ca;
46723             var line1 = attribution.append('div').attr('class', 'attribution-row');
46724             var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
46725
46726             var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
46727             label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
46728               d3_event.stopPropagation();
46729               _hires = !_hires;
46730               _resolution = _hires ? 1024 : 512;
46731               wrap.call(setupCanvas, true);
46732               var viewstate = {
46733                 yaw: _pannellumViewer.getYaw(),
46734                 pitch: _pannellumViewer.getPitch(),
46735                 hfov: _pannellumViewer.getHfov()
46736               };
46737               _sceneOptions = Object.assign(_sceneOptions, viewstate);
46738               that.selectImage(context, d.key).showViewer(context);
46739             });
46740             label.append('span').html(_t.html('streetside.hires'));
46741             var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
46742
46743             if (d.captured_by) {
46744               var yyyy = new Date().getFullYear();
46745               captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
46746               captureInfo.append('span').html('|');
46747             }
46748
46749             if (d.captured_at) {
46750               captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
46751             } // Add image links
46752
46753
46754             var line2 = attribution.append('div').attr('class', 'attribution-row');
46755             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'));
46756             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'));
46757             var bubbleIdQuadKey = d.key.toString(4);
46758             var paddingNeeded = 16 - bubbleIdQuadKey.length;
46759
46760             for (var i = 0; i < paddingNeeded; i++) {
46761               bubbleIdQuadKey = '0' + bubbleIdQuadKey;
46762             }
46763
46764             var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
46765             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
46766
46767             var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
46768
46769             var quadKeys = getQuadKeys();
46770             var faces = faceKeys.map(function (faceKey) {
46771               return quadKeys.map(function (quadKey) {
46772                 var xy = qkToXY(quadKey);
46773                 return {
46774                   face: faceKey,
46775                   url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
46776                   x: xy[0],
46777                   y: xy[1]
46778                 };
46779               });
46780             });
46781             loadFaces(faces).then(function () {
46782               if (!_pannellumViewer) {
46783                 that.initViewer();
46784               } else {
46785                 // make a new scene
46786                 _currScene += 1;
46787
46788                 var sceneID = _currScene.toString();
46789
46790                 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
46791
46792
46793                 if (_currScene > 2) {
46794                   sceneID = (_currScene - 1).toString();
46795
46796                   _pannellumViewer.removeScene(sceneID);
46797                 }
46798               }
46799             });
46800             return this;
46801           },
46802           getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
46803             return d && d.sequenceKey;
46804           },
46805           // Updates the currently highlighted sequence and selected bubble.
46806           // Reset is only necessary when interacting with the viewport because
46807           // this implicitly changes the currently selected bubble/sequence
46808           setStyles: function setStyles(context, hovered, reset) {
46809             if (reset) {
46810               // reset all layers
46811               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
46812               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
46813             }
46814
46815             var hoveredBubbleKey = hovered && hovered.key;
46816             var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
46817             var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
46818             var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
46819               return d.key;
46820             }) || [];
46821             var viewer = context.container().select('.photoviewer');
46822             var selected = viewer.empty() ? undefined : viewer.datum();
46823             var selectedBubbleKey = selected && selected.key;
46824             var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
46825             var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
46826             var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
46827               return d.key;
46828             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
46829
46830             var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
46831             context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
46832               return highlightedBubbleKeys.indexOf(d.key) !== -1;
46833             }).classed('hovered', function (d) {
46834               return d.key === hoveredBubbleKey;
46835             }).classed('currentView', function (d) {
46836               return d.key === selectedBubbleKey;
46837             });
46838             context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
46839               return d.properties.key === hoveredSequenceKey;
46840             }).classed('currentView', function (d) {
46841               return d.properties.key === selectedSequenceKey;
46842             }); // update viewfields if needed
46843
46844             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
46845
46846             function viewfieldPath() {
46847               var d = this.parentNode.__data__;
46848
46849               if (d.pano && d.key !== selectedBubbleKey) {
46850                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
46851               } else {
46852                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
46853               }
46854             }
46855
46856             return this;
46857           },
46858           updateUrlImage: function updateUrlImage(imageKey) {
46859             if (!window.mocha) {
46860               var hash = utilStringQs(window.location.hash);
46861
46862               if (imageKey) {
46863                 hash.photo = 'streetside/' + imageKey;
46864               } else {
46865                 delete hash.photo;
46866               }
46867
46868               window.location.replace('#' + utilQsString(hash, true));
46869             }
46870           },
46871
46872           /**
46873            * cache().
46874            */
46875           cache: function cache() {
46876             return _ssCache;
46877           }
46878         };
46879
46880         var _apibase$1 = 'https://taginfo.openstreetmap.org/api/4/';
46881         var _inflight$2 = {};
46882         var _popularKeys = {};
46883         var _taginfoCache = {};
46884         var tag_sorts = {
46885           point: 'count_nodes',
46886           vertex: 'count_nodes',
46887           area: 'count_ways',
46888           line: 'count_ways'
46889         };
46890         var tag_sort_members = {
46891           point: 'count_node_members',
46892           vertex: 'count_node_members',
46893           area: 'count_way_members',
46894           line: 'count_way_members',
46895           relation: 'count_relation_members'
46896         };
46897         var tag_filters = {
46898           point: 'nodes',
46899           vertex: 'nodes',
46900           area: 'ways',
46901           line: 'ways'
46902         };
46903         var tag_members_fractions = {
46904           point: 'count_node_members_fraction',
46905           vertex: 'count_node_members_fraction',
46906           area: 'count_way_members_fraction',
46907           line: 'count_way_members_fraction',
46908           relation: 'count_relation_members_fraction'
46909         };
46910
46911         function sets(params, n, o) {
46912           if (params.geometry && o[params.geometry]) {
46913             params[n] = o[params.geometry];
46914           }
46915
46916           return params;
46917         }
46918
46919         function setFilter(params) {
46920           return sets(params, 'filter', tag_filters);
46921         }
46922
46923         function setSort(params) {
46924           return sets(params, 'sortname', tag_sorts);
46925         }
46926
46927         function setSortMembers(params) {
46928           return sets(params, 'sortname', tag_sort_members);
46929         }
46930
46931         function clean(params) {
46932           return utilObjectOmit(params, ['geometry', 'debounce']);
46933         }
46934
46935         function filterKeys(type) {
46936           var count_type = type ? 'count_' + type : 'count_all';
46937           return function (d) {
46938             return parseFloat(d[count_type]) > 2500 || d.in_wiki;
46939           };
46940         }
46941
46942         function filterMultikeys(prefix) {
46943           return function (d) {
46944             // d.key begins with prefix, and d.key contains no additional ':'s
46945             var re = new RegExp('^' + prefix + '(.*)$');
46946             var matches = d.key.match(re) || [];
46947             return matches.length === 2 && matches[1].indexOf(':') === -1;
46948           };
46949         }
46950
46951         function filterValues(allowUpperCase) {
46952           return function (d) {
46953             if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
46954
46955             if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
46956
46957             return parseFloat(d.fraction) > 0.0;
46958           };
46959         }
46960
46961         function filterRoles(geometry) {
46962           return function (d) {
46963             if (d.role === '') return false; // exclude empty role
46964
46965             if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
46966
46967             return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
46968           };
46969         }
46970
46971         function valKey(d) {
46972           return {
46973             value: d.key,
46974             title: d.key
46975           };
46976         }
46977
46978         function valKeyDescription(d) {
46979           var obj = {
46980             value: d.value,
46981             title: d.description || d.value
46982           };
46983
46984           if (d.count) {
46985             obj.count = d.count;
46986           }
46987
46988           return obj;
46989         }
46990
46991         function roleKey(d) {
46992           return {
46993             value: d.role,
46994             title: d.role
46995           };
46996         } // sort keys with ':' lower than keys without ':'
46997
46998
46999         function sortKeys(a, b) {
47000           return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
47001         }
47002
47003         var debouncedRequest$1 = debounce(request$1, 300, {
47004           leading: false
47005         });
47006
47007         function request$1(url, params, exactMatch, callback, loaded) {
47008           if (_inflight$2[url]) return;
47009           if (checkCache(url, params, exactMatch, callback)) return;
47010           var controller = new AbortController();
47011           _inflight$2[url] = controller;
47012           d3_json(url, {
47013             signal: controller.signal
47014           }).then(function (result) {
47015             delete _inflight$2[url];
47016             if (loaded) loaded(null, result);
47017           })["catch"](function (err) {
47018             delete _inflight$2[url];
47019             if (err.name === 'AbortError') return;
47020             if (loaded) loaded(err.message);
47021           });
47022         }
47023
47024         function checkCache(url, params, exactMatch, callback) {
47025           var rp = params.rp || 25;
47026           var testQuery = params.query || '';
47027           var testUrl = url;
47028
47029           do {
47030             var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
47031
47032             if (hit && (url === testUrl || hit.length < rp)) {
47033               callback(null, hit);
47034               return true;
47035             } // don't try to shorten the query
47036
47037
47038             if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
47039             // that has returned fewer than max results (rp)
47040
47041             testQuery = testQuery.slice(0, -1);
47042             testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
47043           } while (testQuery.length >= 0);
47044
47045           return false;
47046         }
47047
47048         var serviceTaginfo = {
47049           init: function init() {
47050             _inflight$2 = {};
47051             _taginfoCache = {};
47052             _popularKeys = {
47053               // manually exclude some keys – #5377, #7485
47054               postal_code: true,
47055               full_name: true,
47056               loc_name: true,
47057               reg_name: true,
47058               short_name: true,
47059               sorting_name: true,
47060               artist_name: true,
47061               nat_name: true,
47062               long_name: true,
47063               'bridge:name': true
47064             }; // Fetch popular keys.  We'll exclude these from `values`
47065             // lookups because they stress taginfo, and they aren't likely
47066             // to yield meaningful autocomplete results.. see #3955
47067
47068             var params = {
47069               rp: 100,
47070               sortname: 'values_all',
47071               sortorder: 'desc',
47072               page: 1,
47073               debounce: false,
47074               lang: _mainLocalizer.languageCode()
47075             };
47076             this.keys(params, function (err, data) {
47077               if (err) return;
47078               data.forEach(function (d) {
47079                 if (d.value === 'opening_hours') return; // exception
47080
47081                 _popularKeys[d.value] = true;
47082               });
47083             });
47084           },
47085           reset: function reset() {
47086             Object.values(_inflight$2).forEach(function (controller) {
47087               controller.abort();
47088             });
47089             _inflight$2 = {};
47090           },
47091           keys: function keys(params, callback) {
47092             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47093             params = clean(setSort(params));
47094             params = Object.assign({
47095               rp: 10,
47096               sortname: 'count_all',
47097               sortorder: 'desc',
47098               page: 1,
47099               lang: _mainLocalizer.languageCode()
47100             }, params);
47101             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
47102             doRequest(url, params, false, callback, function (err, d) {
47103               if (err) {
47104                 callback(err);
47105               } else {
47106                 var f = filterKeys(params.filter);
47107                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
47108                 _taginfoCache[url] = result;
47109                 callback(null, result);
47110               }
47111             });
47112           },
47113           multikeys: function multikeys(params, callback) {
47114             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47115             params = clean(setSort(params));
47116             params = Object.assign({
47117               rp: 25,
47118               sortname: 'count_all',
47119               sortorder: 'desc',
47120               page: 1,
47121               lang: _mainLocalizer.languageCode()
47122             }, params);
47123             var prefix = params.query;
47124             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
47125             doRequest(url, params, true, callback, function (err, d) {
47126               if (err) {
47127                 callback(err);
47128               } else {
47129                 var f = filterMultikeys(prefix);
47130                 var result = d.data.filter(f).map(valKey);
47131                 _taginfoCache[url] = result;
47132                 callback(null, result);
47133               }
47134             });
47135           },
47136           values: function values(params, callback) {
47137             // Exclude popular keys from values lookups.. see #3955
47138             var key = params.key;
47139
47140             if (key && _popularKeys[key]) {
47141               callback(null, []);
47142               return;
47143             }
47144
47145             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47146             params = clean(setSort(setFilter(params)));
47147             params = Object.assign({
47148               rp: 25,
47149               sortname: 'count_all',
47150               sortorder: 'desc',
47151               page: 1,
47152               lang: _mainLocalizer.languageCode()
47153             }, params);
47154             var url = _apibase$1 + 'key/values?' + utilQsString(params);
47155             doRequest(url, params, false, callback, function (err, d) {
47156               if (err) {
47157                 callback(err);
47158               } else {
47159                 // In most cases we prefer taginfo value results with lowercase letters.
47160                 // A few OSM keys expect values to contain uppercase values (see #3377).
47161                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
47162                 // but these are the fields where taginfo value lookup is most useful.
47163                 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
47164                 var allowUpperCase = re.test(params.key);
47165                 var f = filterValues(allowUpperCase);
47166                 var result = d.data.filter(f).map(valKeyDescription);
47167                 _taginfoCache[url] = result;
47168                 callback(null, result);
47169               }
47170             });
47171           },
47172           roles: function roles(params, callback) {
47173             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47174             var geometry = params.geometry;
47175             params = clean(setSortMembers(params));
47176             params = Object.assign({
47177               rp: 25,
47178               sortname: 'count_all_members',
47179               sortorder: 'desc',
47180               page: 1,
47181               lang: _mainLocalizer.languageCode()
47182             }, params);
47183             var url = _apibase$1 + 'relation/roles?' + utilQsString(params);
47184             doRequest(url, params, true, callback, function (err, d) {
47185               if (err) {
47186                 callback(err);
47187               } else {
47188                 var f = filterRoles(geometry);
47189                 var result = d.data.filter(f).map(roleKey);
47190                 _taginfoCache[url] = result;
47191                 callback(null, result);
47192               }
47193             });
47194           },
47195           docs: function docs(params, callback) {
47196             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47197             params = clean(setSort(params));
47198             var path = 'key/wiki_pages?';
47199
47200             if (params.value) {
47201               path = 'tag/wiki_pages?';
47202             } else if (params.rtype) {
47203               path = 'relation/wiki_pages?';
47204             }
47205
47206             var url = _apibase$1 + path + utilQsString(params);
47207             doRequest(url, params, true, callback, function (err, d) {
47208               if (err) {
47209                 callback(err);
47210               } else {
47211                 _taginfoCache[url] = d.data;
47212                 callback(null, d.data);
47213               }
47214             });
47215           },
47216           apibase: function apibase(_) {
47217             if (!arguments.length) return _apibase$1;
47218             _apibase$1 = _;
47219             return this;
47220           }
47221         };
47222
47223         /**
47224          * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
47225          *
47226          * @name feature
47227          * @param {Geometry} geometry input geometry
47228          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47229          * @param {Object} [options={}] Optional Parameters
47230          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47231          * @param {string|number} [options.id] Identifier associated with the Feature
47232          * @returns {Feature} a GeoJSON Feature
47233          * @example
47234          * var geometry = {
47235          *   "type": "Point",
47236          *   "coordinates": [110, 50]
47237          * };
47238          *
47239          * var feature = turf.feature(geometry);
47240          *
47241          * //=feature
47242          */
47243
47244         function feature(geom, properties, options) {
47245           if (options === void 0) {
47246             options = {};
47247           }
47248
47249           var feat = {
47250             type: "Feature"
47251           };
47252
47253           if (options.id === 0 || options.id) {
47254             feat.id = options.id;
47255           }
47256
47257           if (options.bbox) {
47258             feat.bbox = options.bbox;
47259           }
47260
47261           feat.properties = properties || {};
47262           feat.geometry = geom;
47263           return feat;
47264         }
47265         /**
47266          * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
47267          *
47268          * @name polygon
47269          * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47270          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47271          * @param {Object} [options={}] Optional Parameters
47272          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47273          * @param {string|number} [options.id] Identifier associated with the Feature
47274          * @returns {Feature<Polygon>} Polygon Feature
47275          * @example
47276          * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
47277          *
47278          * //=polygon
47279          */
47280
47281         function polygon(coordinates, properties, options) {
47282           if (options === void 0) {
47283             options = {};
47284           }
47285
47286           for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
47287             var ring = coordinates_1[_i];
47288
47289             if (ring.length < 4) {
47290               throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
47291             }
47292
47293             for (var j = 0; j < ring[ring.length - 1].length; j++) {
47294               // Check if first point of Polygon contains two numbers
47295               if (ring[ring.length - 1][j] !== ring[0][j]) {
47296                 throw new Error("First and last Position are not equivalent.");
47297               }
47298             }
47299           }
47300
47301           var geom = {
47302             type: "Polygon",
47303             coordinates: coordinates
47304           };
47305           return feature(geom, properties, options);
47306         }
47307         /**
47308          * Creates a {@link LineString} {@link Feature} from an Array of Positions.
47309          *
47310          * @name lineString
47311          * @param {Array<Array<number>>} coordinates an array of Positions
47312          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47313          * @param {Object} [options={}] Optional Parameters
47314          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47315          * @param {string|number} [options.id] Identifier associated with the Feature
47316          * @returns {Feature<LineString>} LineString Feature
47317          * @example
47318          * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
47319          * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
47320          *
47321          * //=linestring1
47322          * //=linestring2
47323          */
47324
47325         function lineString(coordinates, properties, options) {
47326           if (options === void 0) {
47327             options = {};
47328           }
47329
47330           if (coordinates.length < 2) {
47331             throw new Error("coordinates must be an array of two or more positions");
47332           }
47333
47334           var geom = {
47335             type: "LineString",
47336             coordinates: coordinates
47337           };
47338           return feature(geom, properties, options);
47339         }
47340         /**
47341          * Creates a {@link Feature<MultiLineString>} based on a
47342          * coordinate array. Properties can be added optionally.
47343          *
47344          * @name multiLineString
47345          * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
47346          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47347          * @param {Object} [options={}] Optional Parameters
47348          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47349          * @param {string|number} [options.id] Identifier associated with the Feature
47350          * @returns {Feature<MultiLineString>} a MultiLineString feature
47351          * @throws {Error} if no coordinates are passed
47352          * @example
47353          * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
47354          *
47355          * //=multiLine
47356          */
47357
47358         function multiLineString(coordinates, properties, options) {
47359           if (options === void 0) {
47360             options = {};
47361           }
47362
47363           var geom = {
47364             type: "MultiLineString",
47365             coordinates: coordinates
47366           };
47367           return feature(geom, properties, options);
47368         }
47369         /**
47370          * Creates a {@link Feature<MultiPolygon>} based on a
47371          * coordinate array. Properties can be added optionally.
47372          *
47373          * @name multiPolygon
47374          * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
47375          * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47376          * @param {Object} [options={}] Optional Parameters
47377          * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47378          * @param {string|number} [options.id] Identifier associated with the Feature
47379          * @returns {Feature<MultiPolygon>} a multipolygon feature
47380          * @throws {Error} if no coordinates are passed
47381          * @example
47382          * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
47383          *
47384          * //=multiPoly
47385          *
47386          */
47387
47388         function multiPolygon(coordinates, properties, options) {
47389           if (options === void 0) {
47390             options = {};
47391           }
47392
47393           var geom = {
47394             type: "MultiPolygon",
47395             coordinates: coordinates
47396           };
47397           return feature(geom, properties, options);
47398         }
47399
47400         /**
47401          * Get Geometry from Feature or Geometry Object
47402          *
47403          * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
47404          * @returns {Geometry|null} GeoJSON Geometry Object
47405          * @throws {Error} if geojson is not a Feature or Geometry Object
47406          * @example
47407          * var point = {
47408          *   "type": "Feature",
47409          *   "properties": {},
47410          *   "geometry": {
47411          *     "type": "Point",
47412          *     "coordinates": [110, 40]
47413          *   }
47414          * }
47415          * var geom = turf.getGeom(point)
47416          * //={"type": "Point", "coordinates": [110, 40]}
47417          */
47418
47419         function getGeom(geojson) {
47420           if (geojson.type === "Feature") {
47421             return geojson.geometry;
47422           }
47423
47424           return geojson;
47425         }
47426
47427         // Cohen-Sutherland line clippign algorithm, adapted to efficiently
47428         // handle polylines rather than just segments
47429         function lineclip(points, bbox, result) {
47430           var len = points.length,
47431               codeA = bitCode(points[0], bbox),
47432               part = [],
47433               i,
47434               a,
47435               b,
47436               codeB,
47437               lastCode;
47438           if (!result) result = [];
47439
47440           for (i = 1; i < len; i++) {
47441             a = points[i - 1];
47442             b = points[i];
47443             codeB = lastCode = bitCode(b, bbox);
47444
47445             while (true) {
47446               if (!(codeA | codeB)) {
47447                 // accept
47448                 part.push(a);
47449
47450                 if (codeB !== lastCode) {
47451                   // segment went outside
47452                   part.push(b);
47453
47454                   if (i < len - 1) {
47455                     // start a new line
47456                     result.push(part);
47457                     part = [];
47458                   }
47459                 } else if (i === len - 1) {
47460                   part.push(b);
47461                 }
47462
47463                 break;
47464               } else if (codeA & codeB) {
47465                 // trivial reject
47466                 break;
47467               } else if (codeA) {
47468                 // a outside, intersect with clip edge
47469                 a = intersect(a, b, codeA, bbox);
47470                 codeA = bitCode(a, bbox);
47471               } else {
47472                 // b outside
47473                 b = intersect(a, b, codeB, bbox);
47474                 codeB = bitCode(b, bbox);
47475               }
47476             }
47477
47478             codeA = lastCode;
47479           }
47480
47481           if (part.length) result.push(part);
47482           return result;
47483         } // Sutherland-Hodgeman polygon clipping algorithm
47484
47485         function polygonclip(points, bbox) {
47486           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
47487
47488           for (edge = 1; edge <= 8; edge *= 2) {
47489             result = [];
47490             prev = points[points.length - 1];
47491             prevInside = !(bitCode(prev, bbox) & edge);
47492
47493             for (i = 0; i < points.length; i++) {
47494               p = points[i];
47495               inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
47496
47497               if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
47498               if (inside) result.push(p); // add a point if it's inside
47499
47500               prev = p;
47501               prevInside = inside;
47502             }
47503
47504             points = result;
47505             if (!points.length) break;
47506           }
47507
47508           return result;
47509         } // intersect a segment against one of the 4 lines that make up the bbox
47510
47511         function intersect(a, b, edge, bbox) {
47512           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] // top
47513           : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] // bottom
47514           : edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] // right
47515           : edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] // left
47516           : null;
47517         } // bit code reflects the point position relative to the bbox:
47518         //         left  mid  right
47519         //    top  1001  1000  1010
47520         //    mid  0001  0000  0010
47521         // bottom  0101  0100  0110
47522
47523
47524         function bitCode(p, bbox) {
47525           var code = 0;
47526           if (p[0] < bbox[0]) code |= 1; // left
47527           else if (p[0] > bbox[2]) code |= 2; // right
47528
47529           if (p[1] < bbox[1]) code |= 4; // bottom
47530           else if (p[1] > bbox[3]) code |= 8; // top
47531
47532           return code;
47533         }
47534
47535         /**
47536          * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
47537          * [lineclip](https://github.com/mapbox/lineclip).
47538          * May result in degenerate edges when clipping Polygons.
47539          *
47540          * @name bboxClip
47541          * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
47542          * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
47543          * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
47544          * @example
47545          * var bbox = [0, 0, 10, 10];
47546          * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
47547          *
47548          * var clipped = turf.bboxClip(poly, bbox);
47549          *
47550          * //addToMap
47551          * var addToMap = [bbox, poly, clipped]
47552          */
47553
47554         function bboxClip(feature, bbox) {
47555           var geom = getGeom(feature);
47556           var type = geom.type;
47557           var properties = feature.type === "Feature" ? feature.properties : {};
47558           var coords = geom.coordinates;
47559
47560           switch (type) {
47561             case "LineString":
47562             case "MultiLineString":
47563               var lines_1 = [];
47564
47565               if (type === "LineString") {
47566                 coords = [coords];
47567               }
47568
47569               coords.forEach(function (line) {
47570                 lineclip(line, bbox, lines_1);
47571               });
47572
47573               if (lines_1.length === 1) {
47574                 return lineString(lines_1[0], properties);
47575               }
47576
47577               return multiLineString(lines_1, properties);
47578
47579             case "Polygon":
47580               return polygon(clipPolygon(coords, bbox), properties);
47581
47582             case "MultiPolygon":
47583               return multiPolygon(coords.map(function (poly) {
47584                 return clipPolygon(poly, bbox);
47585               }), properties);
47586
47587             default:
47588               throw new Error("geometry " + type + " not supported");
47589           }
47590         }
47591
47592         function clipPolygon(rings, bbox) {
47593           var outRings = [];
47594
47595           for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
47596             var ring = rings_1[_i];
47597             var clipped = polygonclip(ring, bbox);
47598
47599             if (clipped.length > 0) {
47600               if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
47601                 clipped.push(clipped[0]);
47602               }
47603
47604               if (clipped.length >= 4) {
47605                 outRings.push(clipped);
47606               }
47607             }
47608           }
47609
47610           return outRings;
47611         }
47612
47613         var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
47614           if (!opts) opts = {};
47615           if (typeof opts === 'function') opts = {
47616             cmp: opts
47617           };
47618           var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
47619
47620           var cmp = opts.cmp && function (f) {
47621             return function (node) {
47622               return function (a, b) {
47623                 var aobj = {
47624                   key: a,
47625                   value: node[a]
47626                 };
47627                 var bobj = {
47628                   key: b,
47629                   value: node[b]
47630                 };
47631                 return f(aobj, bobj);
47632               };
47633             };
47634           }(opts.cmp);
47635
47636           var seen = [];
47637           return function stringify(node) {
47638             if (node && node.toJSON && typeof node.toJSON === 'function') {
47639               node = node.toJSON();
47640             }
47641
47642             if (node === undefined) return;
47643             if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
47644             if (_typeof(node) !== 'object') return JSON.stringify(node);
47645             var i, out;
47646
47647             if (Array.isArray(node)) {
47648               out = '[';
47649
47650               for (i = 0; i < node.length; i++) {
47651                 if (i) out += ',';
47652                 out += stringify(node[i]) || 'null';
47653               }
47654
47655               return out + ']';
47656             }
47657
47658             if (node === null) return 'null';
47659
47660             if (seen.indexOf(node) !== -1) {
47661               if (cycles) return JSON.stringify('__cycle__');
47662               throw new TypeError('Converting circular structure to JSON');
47663             }
47664
47665             var seenIndex = seen.push(node) - 1;
47666             var keys = Object.keys(node).sort(cmp && cmp(node));
47667             out = '';
47668
47669             for (i = 0; i < keys.length; i++) {
47670               var key = keys[i];
47671               var value = stringify(node[key]);
47672               if (!value) continue;
47673               if (out) out += ',';
47674               out += JSON.stringify(key) + ':' + value;
47675             }
47676
47677             seen.splice(seenIndex, 1);
47678             return '{' + out + '}';
47679           }(data);
47680         };
47681
47682         function DEFAULT_COMPARE(a, b) {
47683           return a > b ? 1 : a < b ? -1 : 0;
47684         }
47685
47686         var SplayTree = /*#__PURE__*/function () {
47687           function SplayTree() {
47688             var compare = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE;
47689             var noDuplicates = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
47690
47691             _classCallCheck(this, SplayTree);
47692
47693             this._compare = compare;
47694             this._root = null;
47695             this._size = 0;
47696             this._noDuplicates = !!noDuplicates;
47697           }
47698
47699           _createClass(SplayTree, [{
47700             key: "rotateLeft",
47701             value: function rotateLeft(x) {
47702               var y = x.right;
47703
47704               if (y) {
47705                 x.right = y.left;
47706                 if (y.left) y.left.parent = x;
47707                 y.parent = x.parent;
47708               }
47709
47710               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
47711               if (y) y.left = x;
47712               x.parent = y;
47713             }
47714           }, {
47715             key: "rotateRight",
47716             value: function rotateRight(x) {
47717               var y = x.left;
47718
47719               if (y) {
47720                 x.left = y.right;
47721                 if (y.right) y.right.parent = x;
47722                 y.parent = x.parent;
47723               }
47724
47725               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
47726               if (y) y.right = x;
47727               x.parent = y;
47728             }
47729           }, {
47730             key: "_splay",
47731             value: function _splay(x) {
47732               while (x.parent) {
47733                 var p = x.parent;
47734
47735                 if (!p.parent) {
47736                   if (p.left === x) this.rotateRight(p);else this.rotateLeft(p);
47737                 } else if (p.left === x && p.parent.left === p) {
47738                   this.rotateRight(p.parent);
47739                   this.rotateRight(p);
47740                 } else if (p.right === x && p.parent.right === p) {
47741                   this.rotateLeft(p.parent);
47742                   this.rotateLeft(p);
47743                 } else if (p.left === x && p.parent.right === p) {
47744                   this.rotateRight(p);
47745                   this.rotateLeft(p);
47746                 } else {
47747                   this.rotateLeft(p);
47748                   this.rotateRight(p);
47749                 }
47750               }
47751             }
47752           }, {
47753             key: "splay",
47754             value: function splay(x) {
47755               var p, gp, ggp, l, r;
47756
47757               while (x.parent) {
47758                 p = x.parent;
47759                 gp = p.parent;
47760
47761                 if (gp && gp.parent) {
47762                   ggp = gp.parent;
47763                   if (ggp.left === gp) ggp.left = x;else ggp.right = x;
47764                   x.parent = ggp;
47765                 } else {
47766                   x.parent = null;
47767                   this._root = x;
47768                 }
47769
47770                 l = x.left;
47771                 r = x.right;
47772
47773                 if (x === p.left) {
47774                   // left
47775                   if (gp) {
47776                     if (gp.left === p) {
47777                       /* zig-zig */
47778                       if (p.right) {
47779                         gp.left = p.right;
47780                         gp.left.parent = gp;
47781                       } else gp.left = null;
47782
47783                       p.right = gp;
47784                       gp.parent = p;
47785                     } else {
47786                       /* zig-zag */
47787                       if (l) {
47788                         gp.right = l;
47789                         l.parent = gp;
47790                       } else gp.right = null;
47791
47792                       x.left = gp;
47793                       gp.parent = x;
47794                     }
47795                   }
47796
47797                   if (r) {
47798                     p.left = r;
47799                     r.parent = p;
47800                   } else p.left = null;
47801
47802                   x.right = p;
47803                   p.parent = x;
47804                 } else {
47805                   // right
47806                   if (gp) {
47807                     if (gp.right === p) {
47808                       /* zig-zig */
47809                       if (p.left) {
47810                         gp.right = p.left;
47811                         gp.right.parent = gp;
47812                       } else gp.right = null;
47813
47814                       p.left = gp;
47815                       gp.parent = p;
47816                     } else {
47817                       /* zig-zag */
47818                       if (r) {
47819                         gp.left = r;
47820                         r.parent = gp;
47821                       } else gp.left = null;
47822
47823                       x.right = gp;
47824                       gp.parent = x;
47825                     }
47826                   }
47827
47828                   if (l) {
47829                     p.right = l;
47830                     l.parent = p;
47831                   } else p.right = null;
47832
47833                   x.left = p;
47834                   p.parent = x;
47835                 }
47836               }
47837             }
47838           }, {
47839             key: "replace",
47840             value: function replace(u, v) {
47841               if (!u.parent) this._root = v;else if (u === u.parent.left) u.parent.left = v;else u.parent.right = v;
47842               if (v) v.parent = u.parent;
47843             }
47844           }, {
47845             key: "minNode",
47846             value: function minNode() {
47847               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
47848               if (u) while (u.left) {
47849                 u = u.left;
47850               }
47851               return u;
47852             }
47853           }, {
47854             key: "maxNode",
47855             value: function maxNode() {
47856               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
47857               if (u) while (u.right) {
47858                 u = u.right;
47859               }
47860               return u;
47861             }
47862           }, {
47863             key: "insert",
47864             value: function insert(key, data) {
47865               var z = this._root;
47866               var p = null;
47867               var comp = this._compare;
47868               var cmp;
47869
47870               if (this._noDuplicates) {
47871                 while (z) {
47872                   p = z;
47873                   cmp = comp(z.key, key);
47874                   if (cmp === 0) return;else if (comp(z.key, key) < 0) z = z.right;else z = z.left;
47875                 }
47876               } else {
47877                 while (z) {
47878                   p = z;
47879                   if (comp(z.key, key) < 0) z = z.right;else z = z.left;
47880                 }
47881               }
47882
47883               z = {
47884                 key: key,
47885                 data: data,
47886                 left: null,
47887                 right: null,
47888                 parent: p
47889               };
47890               if (!p) this._root = z;else if (comp(p.key, z.key) < 0) p.right = z;else p.left = z;
47891               this.splay(z);
47892               this._size++;
47893               return z;
47894             }
47895           }, {
47896             key: "find",
47897             value: function find(key) {
47898               var z = this._root;
47899               var comp = this._compare;
47900
47901               while (z) {
47902                 var cmp = comp(z.key, key);
47903                 if (cmp < 0) z = z.right;else if (cmp > 0) z = z.left;else return z;
47904               }
47905
47906               return null;
47907             }
47908             /**
47909              * Whether the tree contains a node with the given key
47910              * @param  {Key} key
47911              * @return {boolean} true/false
47912              */
47913
47914           }, {
47915             key: "contains",
47916             value: function contains(key) {
47917               var node = this._root;
47918               var comparator = this._compare;
47919
47920               while (node) {
47921                 var cmp = comparator(key, node.key);
47922                 if (cmp === 0) return true;else if (cmp < 0) node = node.left;else node = node.right;
47923               }
47924
47925               return false;
47926             }
47927           }, {
47928             key: "remove",
47929             value: function remove(key) {
47930               var z = this.find(key);
47931               if (!z) return false;
47932               this.splay(z);
47933               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
47934                 var y = this.minNode(z.right);
47935
47936                 if (y.parent !== z) {
47937                   this.replace(y, y.right);
47938                   y.right = z.right;
47939                   y.right.parent = y;
47940                 }
47941
47942                 this.replace(z, y);
47943                 y.left = z.left;
47944                 y.left.parent = y;
47945               }
47946               this._size--;
47947               return true;
47948             }
47949           }, {
47950             key: "removeNode",
47951             value: function removeNode(z) {
47952               if (!z) return false;
47953               this.splay(z);
47954               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
47955                 var y = this.minNode(z.right);
47956
47957                 if (y.parent !== z) {
47958                   this.replace(y, y.right);
47959                   y.right = z.right;
47960                   y.right.parent = y;
47961                 }
47962
47963                 this.replace(z, y);
47964                 y.left = z.left;
47965                 y.left.parent = y;
47966               }
47967               this._size--;
47968               return true;
47969             }
47970           }, {
47971             key: "erase",
47972             value: function erase(key) {
47973               var z = this.find(key);
47974               if (!z) return;
47975               this.splay(z);
47976               var s = z.left;
47977               var t = z.right;
47978               var sMax = null;
47979
47980               if (s) {
47981                 s.parent = null;
47982                 sMax = this.maxNode(s);
47983                 this.splay(sMax);
47984                 this._root = sMax;
47985               }
47986
47987               if (t) {
47988                 if (s) sMax.right = t;else this._root = t;
47989                 t.parent = sMax;
47990               }
47991
47992               this._size--;
47993             }
47994             /**
47995              * Removes and returns the node with smallest key
47996              * @return {?Node}
47997              */
47998
47999           }, {
48000             key: "pop",
48001             value: function pop() {
48002               var node = this._root,
48003                   returnValue = null;
48004
48005               if (node) {
48006                 while (node.left) {
48007                   node = node.left;
48008                 }
48009
48010                 returnValue = {
48011                   key: node.key,
48012                   data: node.data
48013                 };
48014                 this.remove(node.key);
48015               }
48016
48017               return returnValue;
48018             }
48019             /* eslint-disable class-methods-use-this */
48020
48021             /**
48022              * Successor node
48023              * @param  {Node} node
48024              * @return {?Node}
48025              */
48026
48027           }, {
48028             key: "next",
48029             value: function next(node) {
48030               var successor = node;
48031
48032               if (successor) {
48033                 if (successor.right) {
48034                   successor = successor.right;
48035
48036                   while (successor && successor.left) {
48037                     successor = successor.left;
48038                   }
48039                 } else {
48040                   successor = node.parent;
48041
48042                   while (successor && successor.right === node) {
48043                     node = successor;
48044                     successor = successor.parent;
48045                   }
48046                 }
48047               }
48048
48049               return successor;
48050             }
48051             /**
48052              * Predecessor node
48053              * @param  {Node} node
48054              * @return {?Node}
48055              */
48056
48057           }, {
48058             key: "prev",
48059             value: function prev(node) {
48060               var predecessor = node;
48061
48062               if (predecessor) {
48063                 if (predecessor.left) {
48064                   predecessor = predecessor.left;
48065
48066                   while (predecessor && predecessor.right) {
48067                     predecessor = predecessor.right;
48068                   }
48069                 } else {
48070                   predecessor = node.parent;
48071
48072                   while (predecessor && predecessor.left === node) {
48073                     node = predecessor;
48074                     predecessor = predecessor.parent;
48075                   }
48076                 }
48077               }
48078
48079               return predecessor;
48080             }
48081             /* eslint-enable class-methods-use-this */
48082
48083             /**
48084              * @param  {forEachCallback} callback
48085              * @return {SplayTree}
48086              */
48087
48088           }, {
48089             key: "forEach",
48090             value: function forEach(callback) {
48091               var current = this._root;
48092               var s = [],
48093                   done = false,
48094                   i = 0;
48095
48096               while (!done) {
48097                 // Reach the left most Node of the current Node
48098                 if (current) {
48099                   // Place pointer to a tree node on the stack
48100                   // before traversing the node's left subtree
48101                   s.push(current);
48102                   current = current.left;
48103                 } else {
48104                   // BackTrack from the empty subtree and visit the Node
48105                   // at the top of the stack; however, if the stack is
48106                   // empty you are done
48107                   if (s.length > 0) {
48108                     current = s.pop();
48109                     callback(current, i++); // We have visited the node and its left
48110                     // subtree. Now, it's right subtree's turn
48111
48112                     current = current.right;
48113                   } else done = true;
48114                 }
48115               }
48116
48117               return this;
48118             }
48119             /**
48120              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
48121              * @param  {Key}      low
48122              * @param  {Key}      high
48123              * @param  {Function} fn
48124              * @param  {*?}       ctx
48125              * @return {SplayTree}
48126              */
48127
48128           }, {
48129             key: "range",
48130             value: function range(low, high, fn, ctx) {
48131               var Q = [];
48132               var compare = this._compare;
48133               var node = this._root,
48134                   cmp;
48135
48136               while (Q.length !== 0 || node) {
48137                 if (node) {
48138                   Q.push(node);
48139                   node = node.left;
48140                 } else {
48141                   node = Q.pop();
48142                   cmp = compare(node.key, high);
48143
48144                   if (cmp > 0) {
48145                     break;
48146                   } else if (compare(node.key, low) >= 0) {
48147                     if (fn.call(ctx, node)) return this; // stop if smth is returned
48148                   }
48149
48150                   node = node.right;
48151                 }
48152               }
48153
48154               return this;
48155             }
48156             /**
48157              * Returns all keys in order
48158              * @return {Array<Key>}
48159              */
48160
48161           }, {
48162             key: "keys",
48163             value: function keys() {
48164               var current = this._root;
48165               var s = [],
48166                   r = [],
48167                   done = false;
48168
48169               while (!done) {
48170                 if (current) {
48171                   s.push(current);
48172                   current = current.left;
48173                 } else {
48174                   if (s.length > 0) {
48175                     current = s.pop();
48176                     r.push(current.key);
48177                     current = current.right;
48178                   } else done = true;
48179                 }
48180               }
48181
48182               return r;
48183             }
48184             /**
48185              * Returns `data` fields of all nodes in order.
48186              * @return {Array<Value>}
48187              */
48188
48189           }, {
48190             key: "values",
48191             value: function values() {
48192               var current = this._root;
48193               var s = [],
48194                   r = [],
48195                   done = false;
48196
48197               while (!done) {
48198                 if (current) {
48199                   s.push(current);
48200                   current = current.left;
48201                 } else {
48202                   if (s.length > 0) {
48203                     current = s.pop();
48204                     r.push(current.data);
48205                     current = current.right;
48206                   } else done = true;
48207                 }
48208               }
48209
48210               return r;
48211             }
48212             /**
48213              * Returns node at given index
48214              * @param  {number} index
48215              * @return {?Node}
48216              */
48217
48218           }, {
48219             key: "at",
48220             value: function at(index) {
48221               // removed after a consideration, more misleading than useful
48222               // index = index % this.size;
48223               // if (index < 0) index = this.size - index;
48224               var current = this._root;
48225               var s = [],
48226                   done = false,
48227                   i = 0;
48228
48229               while (!done) {
48230                 if (current) {
48231                   s.push(current);
48232                   current = current.left;
48233                 } else {
48234                   if (s.length > 0) {
48235                     current = s.pop();
48236                     if (i === index) return current;
48237                     i++;
48238                     current = current.right;
48239                   } else done = true;
48240                 }
48241               }
48242
48243               return null;
48244             }
48245             /**
48246              * Bulk-load items. Both array have to be same size
48247              * @param  {Array<Key>}    keys
48248              * @param  {Array<Value>}  [values]
48249              * @param  {Boolean}       [presort=false] Pre-sort keys and values, using
48250              *                                         tree's comparator. Sorting is done
48251              *                                         in-place
48252              * @return {AVLTree}
48253              */
48254
48255           }, {
48256             key: "load",
48257             value: function load() {
48258               var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
48259               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
48260               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
48261               if (this._size !== 0) throw new Error('bulk-load: tree is not empty');
48262               var size = keys.length;
48263               if (presort) sort(keys, values, 0, size - 1, this._compare);
48264               this._root = loadRecursive(null, keys, values, 0, size);
48265               this._size = size;
48266               return this;
48267             }
48268           }, {
48269             key: "min",
48270             value: function min() {
48271               var node = this.minNode(this._root);
48272               if (node) return node.key;else return null;
48273             }
48274           }, {
48275             key: "max",
48276             value: function max() {
48277               var node = this.maxNode(this._root);
48278               if (node) return node.key;else return null;
48279             }
48280           }, {
48281             key: "isEmpty",
48282             value: function isEmpty() {
48283               return this._root === null;
48284             }
48285           }, {
48286             key: "size",
48287             get: function get() {
48288               return this._size;
48289             }
48290             /**
48291              * Create a tree and load it with items
48292              * @param  {Array<Key>}          keys
48293              * @param  {Array<Value>?}        [values]
48294               * @param  {Function?}            [comparator]
48295              * @param  {Boolean?}             [presort=false] Pre-sort keys and values, using
48296              *                                               tree's comparator. Sorting is done
48297              *                                               in-place
48298              * @param  {Boolean?}             [noDuplicates=false]   Allow duplicates
48299              * @return {SplayTree}
48300              */
48301
48302           }], [{
48303             key: "createTree",
48304             value: function createTree(keys, values, comparator, presort, noDuplicates) {
48305               return new SplayTree(comparator, noDuplicates).load(keys, values, presort);
48306             }
48307           }]);
48308
48309           return SplayTree;
48310         }();
48311
48312         function loadRecursive(parent, keys, values, start, end) {
48313           var size = end - start;
48314
48315           if (size > 0) {
48316             var middle = start + Math.floor(size / 2);
48317             var key = keys[middle];
48318             var data = values[middle];
48319             var node = {
48320               key: key,
48321               data: data,
48322               parent: parent
48323             };
48324             node.left = loadRecursive(node, keys, values, start, middle);
48325             node.right = loadRecursive(node, keys, values, middle + 1, end);
48326             return node;
48327           }
48328
48329           return null;
48330         }
48331
48332         function sort(keys, values, left, right, compare) {
48333           if (left >= right) return;
48334           var pivot = keys[left + right >> 1];
48335           var i = left - 1;
48336           var j = right + 1;
48337
48338           while (true) {
48339             do {
48340               i++;
48341             } while (compare(keys[i], pivot) < 0);
48342
48343             do {
48344               j--;
48345             } while (compare(keys[j], pivot) > 0);
48346
48347             if (i >= j) break;
48348             var tmp = keys[i];
48349             keys[i] = keys[j];
48350             keys[j] = tmp;
48351             tmp = values[i];
48352             values[i] = values[j];
48353             values[j] = tmp;
48354           }
48355
48356           sort(keys, values, left, j, compare);
48357           sort(keys, values, j + 1, right, compare);
48358         }
48359
48360         var NORMAL = 0;
48361         var NON_CONTRIBUTING = 1;
48362         var SAME_TRANSITION = 2;
48363         var DIFFERENT_TRANSITION = 3;
48364
48365         var INTERSECTION = 0;
48366         var UNION = 1;
48367         var DIFFERENCE = 2;
48368         var XOR = 3;
48369
48370         /**
48371          * @param  {SweepEvent} event
48372          * @param  {SweepEvent} prev
48373          * @param  {Operation} operation
48374          */
48375
48376         function computeFields(event, prev, operation) {
48377           // compute inOut and otherInOut fields
48378           if (prev === null) {
48379             event.inOut = false;
48380             event.otherInOut = true; // previous line segment in sweepline belongs to the same polygon
48381           } else {
48382             if (event.isSubject === prev.isSubject) {
48383               event.inOut = !prev.inOut;
48384               event.otherInOut = prev.otherInOut; // previous line segment in sweepline belongs to the clipping polygon
48385             } else {
48386               event.inOut = !prev.otherInOut;
48387               event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
48388             } // compute prevInResult field
48389
48390
48391             if (prev) {
48392               event.prevInResult = !inResult(prev, operation) || prev.isVertical() ? prev.prevInResult : prev;
48393             }
48394           } // check if the line segment belongs to the Boolean operation
48395
48396
48397           var isInResult = inResult(event, operation);
48398
48399           if (isInResult) {
48400             event.resultTransition = determineResultTransition(event, operation);
48401           } else {
48402             event.resultTransition = 0;
48403           }
48404         }
48405         /* eslint-disable indent */
48406
48407         function inResult(event, operation) {
48408           switch (event.type) {
48409             case NORMAL:
48410               switch (operation) {
48411                 case INTERSECTION:
48412                   return !event.otherInOut;
48413
48414                 case UNION:
48415                   return event.otherInOut;
48416
48417                 case DIFFERENCE:
48418                   // return (event.isSubject && !event.otherInOut) ||
48419                   //         (!event.isSubject && event.otherInOut);
48420                   return event.isSubject && event.otherInOut || !event.isSubject && !event.otherInOut;
48421
48422                 case XOR:
48423                   return true;
48424               }
48425
48426               break;
48427
48428             case SAME_TRANSITION:
48429               return operation === INTERSECTION || operation === UNION;
48430
48431             case DIFFERENT_TRANSITION:
48432               return operation === DIFFERENCE;
48433
48434             case NON_CONTRIBUTING:
48435               return false;
48436           }
48437
48438           return false;
48439         }
48440         /* eslint-enable indent */
48441
48442
48443         function determineResultTransition(event, operation) {
48444           var thisIn = !event.inOut;
48445           var thatIn = !event.otherInOut;
48446           var isIn;
48447
48448           switch (operation) {
48449             case INTERSECTION:
48450               isIn = thisIn && thatIn;
48451               break;
48452
48453             case UNION:
48454               isIn = thisIn || thatIn;
48455               break;
48456
48457             case XOR:
48458               isIn = thisIn ^ thatIn;
48459               break;
48460
48461             case DIFFERENCE:
48462               if (event.isSubject) {
48463                 isIn = thisIn && !thatIn;
48464               } else {
48465                 isIn = thatIn && !thisIn;
48466               }
48467
48468               break;
48469           }
48470
48471           return isIn ? +1 : -1;
48472         }
48473
48474         var SweepEvent = /*#__PURE__*/function () {
48475           /**
48476            * Sweepline event
48477            *
48478            * @class {SweepEvent}
48479            * @param {Array.<Number>}  point
48480            * @param {Boolean}         left
48481            * @param {SweepEvent=}     otherEvent
48482            * @param {Boolean}         isSubject
48483            * @param {Number}          edgeType
48484            */
48485           function SweepEvent(point, left, otherEvent, isSubject, edgeType) {
48486             _classCallCheck(this, SweepEvent);
48487
48488             /**
48489              * Is left endpoint?
48490              * @type {Boolean}
48491              */
48492             this.left = left;
48493             /**
48494              * @type {Array.<Number>}
48495              */
48496
48497             this.point = point;
48498             /**
48499              * Other edge reference
48500              * @type {SweepEvent}
48501              */
48502
48503             this.otherEvent = otherEvent;
48504             /**
48505              * Belongs to source or clipping polygon
48506              * @type {Boolean}
48507              */
48508
48509             this.isSubject = isSubject;
48510             /**
48511              * Edge contribution type
48512              * @type {Number}
48513              */
48514
48515             this.type = edgeType || NORMAL;
48516             /**
48517              * In-out transition for the sweepline crossing polygon
48518              * @type {Boolean}
48519              */
48520
48521             this.inOut = false;
48522             /**
48523              * @type {Boolean}
48524              */
48525
48526             this.otherInOut = false;
48527             /**
48528              * Previous event in result?
48529              * @type {SweepEvent}
48530              */
48531
48532             this.prevInResult = null;
48533             /**
48534              * Type of result transition (0 = not in result, +1 = out-in, -1, in-out)
48535              * @type {Number}
48536              */
48537
48538             this.resultTransition = 0; // connection step
48539
48540             /**
48541              * @type {Number}
48542              */
48543
48544             this.otherPos = -1;
48545             /**
48546              * @type {Number}
48547              */
48548
48549             this.outputContourId = -1;
48550             this.isExteriorRing = true; // TODO: Looks unused, remove?
48551           }
48552           /**
48553            * @param  {Array.<Number>}  p
48554            * @return {Boolean}
48555            */
48556
48557
48558           _createClass(SweepEvent, [{
48559             key: "isBelow",
48560             value: function isBelow(p) {
48561               var p0 = this.point,
48562                   p1 = this.otherEvent.point;
48563               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 :
48564               : (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;
48565             }
48566             /**
48567              * @param  {Array.<Number>}  p
48568              * @return {Boolean}
48569              */
48570
48571           }, {
48572             key: "isAbove",
48573             value: function isAbove(p) {
48574               return !this.isBelow(p);
48575             }
48576             /**
48577              * @return {Boolean}
48578              */
48579
48580           }, {
48581             key: "isVertical",
48582             value: function isVertical() {
48583               return this.point[0] === this.otherEvent.point[0];
48584             }
48585             /**
48586              * Does event belong to result?
48587              * @return {Boolean}
48588              */
48589
48590           }, {
48591             key: "inResult",
48592             get: function get() {
48593               return this.resultTransition !== 0;
48594             }
48595           }, {
48596             key: "clone",
48597             value: function clone() {
48598               var copy = new SweepEvent(this.point, this.left, this.otherEvent, this.isSubject, this.type);
48599               copy.contourId = this.contourId;
48600               copy.resultTransition = this.resultTransition;
48601               copy.prevInResult = this.prevInResult;
48602               copy.isExteriorRing = this.isExteriorRing;
48603               copy.inOut = this.inOut;
48604               copy.otherInOut = this.otherInOut;
48605               return copy;
48606             }
48607           }]);
48608
48609           return SweepEvent;
48610         }();
48611
48612         function equals(p1, p2) {
48613           if (p1[0] === p2[0]) {
48614             if (p1[1] === p2[1]) {
48615               return true;
48616             } else {
48617               return false;
48618             }
48619           }
48620
48621           return false;
48622         } // const EPSILON = 1e-9;
48623         // const abs = Math.abs;
48624         // TODO https://github.com/w8r/martinez/issues/6#issuecomment-262847164
48625         // Precision problem.
48626         //
48627         // module.exports = function equals(p1, p2) {
48628         //   return abs(p1[0] - p2[0]) <= EPSILON && abs(p1[1] - p2[1]) <= EPSILON;
48629         // };
48630
48631         var epsilon$1 = 1.1102230246251565e-16;
48632         var splitter = 134217729;
48633         var resulterrbound = (3 + 8 * epsilon$1) * epsilon$1; // fast_expansion_sum_zeroelim routine from oritinal code
48634
48635         function sum(elen, e, flen, f, h) {
48636           var Q, Qnew, hh, bvirt;
48637           var enow = e[0];
48638           var fnow = f[0];
48639           var eindex = 0;
48640           var findex = 0;
48641
48642           if (fnow > enow === fnow > -enow) {
48643             Q = enow;
48644             enow = e[++eindex];
48645           } else {
48646             Q = fnow;
48647             fnow = f[++findex];
48648           }
48649
48650           var hindex = 0;
48651
48652           if (eindex < elen && findex < flen) {
48653             if (fnow > enow === fnow > -enow) {
48654               Qnew = enow + Q;
48655               hh = Q - (Qnew - enow);
48656               enow = e[++eindex];
48657             } else {
48658               Qnew = fnow + Q;
48659               hh = Q - (Qnew - fnow);
48660               fnow = f[++findex];
48661             }
48662
48663             Q = Qnew;
48664
48665             if (hh !== 0) {
48666               h[hindex++] = hh;
48667             }
48668
48669             while (eindex < elen && findex < flen) {
48670               if (fnow > enow === fnow > -enow) {
48671                 Qnew = Q + enow;
48672                 bvirt = Qnew - Q;
48673                 hh = Q - (Qnew - bvirt) + (enow - bvirt);
48674                 enow = e[++eindex];
48675               } else {
48676                 Qnew = Q + fnow;
48677                 bvirt = Qnew - Q;
48678                 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
48679                 fnow = f[++findex];
48680               }
48681
48682               Q = Qnew;
48683
48684               if (hh !== 0) {
48685                 h[hindex++] = hh;
48686               }
48687             }
48688           }
48689
48690           while (eindex < elen) {
48691             Qnew = Q + enow;
48692             bvirt = Qnew - Q;
48693             hh = Q - (Qnew - bvirt) + (enow - bvirt);
48694             enow = e[++eindex];
48695             Q = Qnew;
48696
48697             if (hh !== 0) {
48698               h[hindex++] = hh;
48699             }
48700           }
48701
48702           while (findex < flen) {
48703             Qnew = Q + fnow;
48704             bvirt = Qnew - Q;
48705             hh = Q - (Qnew - bvirt) + (fnow - bvirt);
48706             fnow = f[++findex];
48707             Q = Qnew;
48708
48709             if (hh !== 0) {
48710               h[hindex++] = hh;
48711             }
48712           }
48713
48714           if (Q !== 0 || hindex === 0) {
48715             h[hindex++] = Q;
48716           }
48717
48718           return hindex;
48719         }
48720         function estimate(elen, e) {
48721           var Q = e[0];
48722
48723           for (var i = 1; i < elen; i++) {
48724             Q += e[i];
48725           }
48726
48727           return Q;
48728         }
48729         function vec(n) {
48730           return new Float64Array(n);
48731         }
48732
48733         var ccwerrboundA = (3 + 16 * epsilon$1) * epsilon$1;
48734         var ccwerrboundB = (2 + 12 * epsilon$1) * epsilon$1;
48735         var ccwerrboundC = (9 + 64 * epsilon$1) * epsilon$1 * epsilon$1;
48736         var B = vec(4);
48737         var C1 = vec(8);
48738         var C2 = vec(12);
48739         var D = vec(16);
48740         var u = vec(4);
48741
48742         function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
48743           var acxtail, acytail, bcxtail, bcytail;
48744
48745           var bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
48746
48747           var acx = ax - cx;
48748           var bcx = bx - cx;
48749           var acy = ay - cy;
48750           var bcy = by - cy;
48751           s1 = acx * bcy;
48752           c = splitter * acx;
48753           ahi = c - (c - acx);
48754           alo = acx - ahi;
48755           c = splitter * bcy;
48756           bhi = c - (c - bcy);
48757           blo = bcy - bhi;
48758           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
48759           t1 = acy * bcx;
48760           c = splitter * acy;
48761           ahi = c - (c - acy);
48762           alo = acy - ahi;
48763           c = splitter * bcx;
48764           bhi = c - (c - bcx);
48765           blo = bcx - bhi;
48766           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
48767           _i = s0 - t0;
48768           bvirt = s0 - _i;
48769           B[0] = s0 - (_i + bvirt) + (bvirt - t0);
48770           _j = s1 + _i;
48771           bvirt = _j - s1;
48772           _0 = s1 - (_j - bvirt) + (_i - bvirt);
48773           _i = _0 - t1;
48774           bvirt = _0 - _i;
48775           B[1] = _0 - (_i + bvirt) + (bvirt - t1);
48776           u3 = _j + _i;
48777           bvirt = u3 - _j;
48778           B[2] = _j - (u3 - bvirt) + (_i - bvirt);
48779           B[3] = u3;
48780           var det = estimate(4, B);
48781           var errbound = ccwerrboundB * detsum;
48782
48783           if (det >= errbound || -det >= errbound) {
48784             return det;
48785           }
48786
48787           bvirt = ax - acx;
48788           acxtail = ax - (acx + bvirt) + (bvirt - cx);
48789           bvirt = bx - bcx;
48790           bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
48791           bvirt = ay - acy;
48792           acytail = ay - (acy + bvirt) + (bvirt - cy);
48793           bvirt = by - bcy;
48794           bcytail = by - (bcy + bvirt) + (bvirt - cy);
48795
48796           if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
48797             return det;
48798           }
48799
48800           errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
48801           det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
48802           if (det >= errbound || -det >= errbound) return det;
48803           s1 = acxtail * bcy;
48804           c = splitter * acxtail;
48805           ahi = c - (c - acxtail);
48806           alo = acxtail - ahi;
48807           c = splitter * bcy;
48808           bhi = c - (c - bcy);
48809           blo = bcy - bhi;
48810           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
48811           t1 = acytail * bcx;
48812           c = splitter * acytail;
48813           ahi = c - (c - acytail);
48814           alo = acytail - ahi;
48815           c = splitter * bcx;
48816           bhi = c - (c - bcx);
48817           blo = bcx - bhi;
48818           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
48819           _i = s0 - t0;
48820           bvirt = s0 - _i;
48821           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
48822           _j = s1 + _i;
48823           bvirt = _j - s1;
48824           _0 = s1 - (_j - bvirt) + (_i - bvirt);
48825           _i = _0 - t1;
48826           bvirt = _0 - _i;
48827           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
48828           u3 = _j + _i;
48829           bvirt = u3 - _j;
48830           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
48831           u[3] = u3;
48832           var C1len = sum(4, B, 4, u, C1);
48833           s1 = acx * bcytail;
48834           c = splitter * acx;
48835           ahi = c - (c - acx);
48836           alo = acx - ahi;
48837           c = splitter * bcytail;
48838           bhi = c - (c - bcytail);
48839           blo = bcytail - bhi;
48840           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
48841           t1 = acy * bcxtail;
48842           c = splitter * acy;
48843           ahi = c - (c - acy);
48844           alo = acy - ahi;
48845           c = splitter * bcxtail;
48846           bhi = c - (c - bcxtail);
48847           blo = bcxtail - bhi;
48848           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
48849           _i = s0 - t0;
48850           bvirt = s0 - _i;
48851           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
48852           _j = s1 + _i;
48853           bvirt = _j - s1;
48854           _0 = s1 - (_j - bvirt) + (_i - bvirt);
48855           _i = _0 - t1;
48856           bvirt = _0 - _i;
48857           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
48858           u3 = _j + _i;
48859           bvirt = u3 - _j;
48860           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
48861           u[3] = u3;
48862           var C2len = sum(C1len, C1, 4, u, C2);
48863           s1 = acxtail * bcytail;
48864           c = splitter * acxtail;
48865           ahi = c - (c - acxtail);
48866           alo = acxtail - ahi;
48867           c = splitter * bcytail;
48868           bhi = c - (c - bcytail);
48869           blo = bcytail - bhi;
48870           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
48871           t1 = acytail * bcxtail;
48872           c = splitter * acytail;
48873           ahi = c - (c - acytail);
48874           alo = acytail - ahi;
48875           c = splitter * bcxtail;
48876           bhi = c - (c - bcxtail);
48877           blo = bcxtail - bhi;
48878           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
48879           _i = s0 - t0;
48880           bvirt = s0 - _i;
48881           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
48882           _j = s1 + _i;
48883           bvirt = _j - s1;
48884           _0 = s1 - (_j - bvirt) + (_i - bvirt);
48885           _i = _0 - t1;
48886           bvirt = _0 - _i;
48887           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
48888           u3 = _j + _i;
48889           bvirt = u3 - _j;
48890           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
48891           u[3] = u3;
48892           var Dlen = sum(C2len, C2, 4, u, D);
48893           return D[Dlen - 1];
48894         }
48895
48896         function orient2d(ax, ay, bx, by, cx, cy) {
48897           var detleft = (ay - cy) * (bx - cx);
48898           var detright = (ax - cx) * (by - cy);
48899           var det = detleft - detright;
48900           if (detleft === 0 || detright === 0 || detleft > 0 !== detright > 0) return det;
48901           var detsum = Math.abs(detleft + detright);
48902           if (Math.abs(det) >= ccwerrboundA * detsum) return det;
48903           return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
48904         }
48905
48906         /**
48907          * Signed area of the triangle (p0, p1, p2)
48908          * @param  {Array.<Number>} p0
48909          * @param  {Array.<Number>} p1
48910          * @param  {Array.<Number>} p2
48911          * @return {Number}
48912          */
48913
48914         function signedArea(p0, p1, p2) {
48915           var res = orient2d(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
48916           if (res > 0) return -1;
48917           if (res < 0) return 1;
48918           return 0;
48919         }
48920
48921         /**
48922          * @param  {SweepEvent} e1
48923          * @param  {SweepEvent} e2
48924          * @return {Number}
48925          */
48926
48927         function compareEvents(e1, e2) {
48928           var p1 = e1.point;
48929           var p2 = e2.point; // Different x-coordinate
48930
48931           if (p1[0] > p2[0]) return 1;
48932           if (p1[0] < p2[0]) return -1; // Different points, but same x-coordinate
48933           // Event with lower y-coordinate is processed first
48934
48935           if (p1[1] !== p2[1]) return p1[1] > p2[1] ? 1 : -1;
48936           return specialCases(e1, e2, p1);
48937         }
48938         /* eslint-disable no-unused-vars */
48939
48940         function specialCases(e1, e2, p1, p2) {
48941           // Same coordinates, but one is a left endpoint and the other is
48942           // a right endpoint. The right endpoint is processed first
48943           if (e1.left !== e2.left) return e1.left ? 1 : -1; // const p2 = e1.otherEvent.point, p3 = e2.otherEvent.point;
48944           // const sa = (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
48945           // Same coordinates, both events
48946           // are left endpoints or right endpoints.
48947           // not collinear
48948
48949           if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0) {
48950             // the event associate to the bottom segment is processed first
48951             return !e1.isBelow(e2.otherEvent.point) ? 1 : -1;
48952           }
48953
48954           return !e1.isSubject && e2.isSubject ? 1 : -1;
48955         }
48956         /* eslint-enable no-unused-vars */
48957
48958         /**
48959          * @param  {SweepEvent} se
48960          * @param  {Array.<Number>} p
48961          * @param  {Queue} queue
48962          * @return {Queue}
48963          */
48964
48965         function divideSegment(se, p, queue) {
48966           var r = new SweepEvent(p, false, se, se.isSubject);
48967           var l = new SweepEvent(p, true, se.otherEvent, se.isSubject);
48968           /* eslint-disable no-console */
48969
48970           if (equals(se.point, se.otherEvent.point)) {
48971             console.warn('what is that, a collapsed segment?', se);
48972           }
48973           /* eslint-enable no-console */
48974
48975
48976           r.contourId = l.contourId = se.contourId; // avoid a rounding error. The left event would be processed after the right event
48977
48978           if (compareEvents(l, se.otherEvent) > 0) {
48979             se.otherEvent.left = true;
48980             l.left = false;
48981           } // avoid a rounding error. The left event would be processed after the right event
48982           // if (compareEvents(se, r) > 0) {}
48983
48984
48985           se.otherEvent.otherEvent = l;
48986           se.otherEvent = r;
48987           queue.push(l);
48988           queue.push(r);
48989           return queue;
48990         }
48991
48992         //const EPS = 1e-9;
48993
48994         /**
48995          * Finds the magnitude of the cross product of two vectors (if we pretend
48996          * they're in three dimensions)
48997          *
48998          * @param {Object} a First vector
48999          * @param {Object} b Second vector
49000          * @private
49001          * @returns {Number} The magnitude of the cross product
49002          */
49003         function crossProduct(a, b) {
49004           return a[0] * b[1] - a[1] * b[0];
49005         }
49006         /**
49007          * Finds the dot product of two vectors.
49008          *
49009          * @param {Object} a First vector
49010          * @param {Object} b Second vector
49011          * @private
49012          * @returns {Number} The dot product
49013          */
49014
49015
49016         function dotProduct(a, b) {
49017           return a[0] * b[0] + a[1] * b[1];
49018         }
49019         /**
49020          * Finds the intersection (if any) between two line segments a and b, given the
49021          * line segments' end points a1, a2 and b1, b2.
49022          *
49023          * This algorithm is based on Schneider and Eberly.
49024          * http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf
49025          * Page 244.
49026          *
49027          * @param {Array.<Number>} a1 point of first line
49028          * @param {Array.<Number>} a2 point of first line
49029          * @param {Array.<Number>} b1 point of second line
49030          * @param {Array.<Number>} b2 point of second line
49031          * @param {Boolean=}       noEndpointTouch whether to skip single touchpoints
49032          *                                         (meaning connected segments) as
49033          *                                         intersections
49034          * @returns {Array.<Array.<Number>>|Null} If the lines intersect, the point of
49035          * intersection. If they overlap, the two end points of the overlapping segment.
49036          * Otherwise, null.
49037          */
49038
49039
49040         function intersection (a1, a2, b1, b2, noEndpointTouch) {
49041           // The algorithm expects our lines in the form P + sd, where P is a point,
49042           // s is on the interval [0, 1], and d is a vector.
49043           // We are passed two points. P can be the first point of each pair. The
49044           // vector, then, could be thought of as the distance (in x and y components)
49045           // from the first point to the second point.
49046           // So first, let's make our vectors:
49047           var va = [a2[0] - a1[0], a2[1] - a1[1]];
49048           var vb = [b2[0] - b1[0], b2[1] - b1[1]]; // We also define a function to convert back to regular point form:
49049
49050           /* eslint-disable arrow-body-style */
49051
49052           function toPoint(p, s, d) {
49053             return [p[0] + s * d[0], p[1] + s * d[1]];
49054           }
49055           /* eslint-enable arrow-body-style */
49056           // The rest is pretty much a straight port of the algorithm.
49057
49058
49059           var e = [b1[0] - a1[0], b1[1] - a1[1]];
49060           var kross = crossProduct(va, vb);
49061           var sqrKross = kross * kross;
49062           var sqrLenA = dotProduct(va, va); //const sqrLenB  = dotProduct(vb, vb);
49063           // Check for line intersection. This works because of the properties of the
49064           // cross product -- specifically, two vectors are parallel if and only if the
49065           // cross product is the 0 vector. The full calculation involves relative error
49066           // to account for possible very small line segments. See Schneider & Eberly
49067           // for details.
49068
49069           if (sqrKross > 0
49070           /* EPS * sqrLenB * sqLenA */
49071           ) {
49072               // If they're not parallel, then (because these are line segments) they
49073               // still might not actually intersect. This code checks that the
49074               // intersection point of the lines is actually on both line segments.
49075               var s = crossProduct(e, vb) / kross;
49076
49077               if (s < 0 || s > 1) {
49078                 // not on line segment a
49079                 return null;
49080               }
49081
49082               var t = crossProduct(e, va) / kross;
49083
49084               if (t < 0 || t > 1) {
49085                 // not on line segment b
49086                 return null;
49087               }
49088
49089               if (s === 0 || s === 1) {
49090                 // on an endpoint of line segment a
49091                 return noEndpointTouch ? null : [toPoint(a1, s, va)];
49092               }
49093
49094               if (t === 0 || t === 1) {
49095                 // on an endpoint of line segment b
49096                 return noEndpointTouch ? null : [toPoint(b1, t, vb)];
49097               }
49098
49099               return [toPoint(a1, s, va)];
49100             } // If we've reached this point, then the lines are either parallel or the
49101           // same, but the segments could overlap partially or fully, or not at all.
49102           // So we need to find the overlap, if any. To do that, we can use e, which is
49103           // the (vector) difference between the two initial points. If this is parallel
49104           // with the line itself, then the two lines are the same line, and there will
49105           // be overlap.
49106           //const sqrLenE = dotProduct(e, e);
49107
49108
49109           kross = crossProduct(e, va);
49110           sqrKross = kross * kross;
49111
49112           if (sqrKross > 0
49113           /* EPS * sqLenB * sqLenE */
49114           ) {
49115               // Lines are just parallel, not the same. No overlap.
49116               return null;
49117             }
49118
49119           var sa = dotProduct(va, e) / sqrLenA;
49120           var sb = sa + dotProduct(va, vb) / sqrLenA;
49121           var smin = Math.min(sa, sb);
49122           var smax = Math.max(sa, sb); // this is, essentially, the FindIntersection acting on floats from
49123           // Schneider & Eberly, just inlined into this function.
49124
49125           if (smin <= 1 && smax >= 0) {
49126             // overlap on an end point
49127             if (smin === 1) {
49128               return noEndpointTouch ? null : [toPoint(a1, smin > 0 ? smin : 0, va)];
49129             }
49130
49131             if (smax === 0) {
49132               return noEndpointTouch ? null : [toPoint(a1, smax < 1 ? smax : 1, va)];
49133             }
49134
49135             if (noEndpointTouch && smin === 0 && smax === 1) return null; // There's overlap on a segment -- two points of intersection. Return both.
49136
49137             return [toPoint(a1, smin > 0 ? smin : 0, va), toPoint(a1, smax < 1 ? smax : 1, va)];
49138           }
49139
49140           return null;
49141         }
49142
49143         /**
49144          * @param  {SweepEvent} se1
49145          * @param  {SweepEvent} se2
49146          * @param  {Queue}      queue
49147          * @return {Number}
49148          */
49149
49150         function possibleIntersection(se1, se2, queue) {
49151           // that disallows self-intersecting polygons,
49152           // did cost us half a day, so I'll leave it
49153           // out of respect
49154           // if (se1.isSubject === se2.isSubject) return;
49155           var inter = intersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
49156           var nintersections = inter ? inter.length : 0;
49157           if (nintersections === 0) return 0; // no intersection
49158           // the line segments intersect at an endpoint of both line segments
49159
49160           if (nintersections === 1 && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point))) {
49161             return 0;
49162           }
49163
49164           if (nintersections === 2 && se1.isSubject === se2.isSubject) {
49165             // if(se1.contourId === se2.contourId){
49166             // console.warn('Edges of the same polygon overlap',
49167             //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
49168             // }
49169             //throw new Error('Edges of the same polygon overlap');
49170             return 0;
49171           } // The line segments associated to se1 and se2 intersect
49172
49173
49174           if (nintersections === 1) {
49175             // if the intersection point is not an endpoint of se1
49176             if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
49177               divideSegment(se1, inter[0], queue);
49178             } // if the intersection point is not an endpoint of se2
49179
49180
49181             if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) {
49182               divideSegment(se2, inter[0], queue);
49183             }
49184
49185             return 1;
49186           } // The line segments associated to se1 and se2 overlap
49187
49188
49189           var events = [];
49190           var leftCoincide = false;
49191           var rightCoincide = false;
49192
49193           if (equals(se1.point, se2.point)) {
49194             leftCoincide = true; // linked
49195           } else if (compareEvents(se1, se2) === 1) {
49196             events.push(se2, se1);
49197           } else {
49198             events.push(se1, se2);
49199           }
49200
49201           if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
49202             rightCoincide = true;
49203           } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
49204             events.push(se2.otherEvent, se1.otherEvent);
49205           } else {
49206             events.push(se1.otherEvent, se2.otherEvent);
49207           }
49208
49209           if (leftCoincide && rightCoincide || leftCoincide) {
49210             // both line segments are equal or share the left endpoint
49211             se2.type = NON_CONTRIBUTING;
49212             se1.type = se2.inOut === se1.inOut ? SAME_TRANSITION : DIFFERENT_TRANSITION;
49213
49214             if (leftCoincide && !rightCoincide) {
49215               // honestly no idea, but changing events selection from [2, 1]
49216               // to [0, 1] fixes the overlapping self-intersecting polygons issue
49217               divideSegment(events[1].otherEvent, events[0].point, queue);
49218             }
49219
49220             return 2;
49221           } // the line segments share the right endpoint
49222
49223
49224           if (rightCoincide) {
49225             divideSegment(events[0], events[1].point, queue);
49226             return 3;
49227           } // no line segment includes totally the other one
49228
49229
49230           if (events[0] !== events[3].otherEvent) {
49231             divideSegment(events[0], events[1].point, queue);
49232             divideSegment(events[1], events[2].point, queue);
49233             return 3;
49234           } // one line segment includes the other one
49235
49236
49237           divideSegment(events[0], events[1].point, queue);
49238           divideSegment(events[3].otherEvent, events[2].point, queue);
49239           return 3;
49240         }
49241
49242         /**
49243          * @param  {SweepEvent} le1
49244          * @param  {SweepEvent} le2
49245          * @return {Number}
49246          */
49247
49248         function compareSegments(le1, le2) {
49249           if (le1 === le2) return 0; // Segments are not collinear
49250
49251           if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 || signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
49252             // If they share their left endpoint use the right endpoint to sort
49253             if (equals(le1.point, le2.point)) return le1.isBelow(le2.otherEvent.point) ? -1 : 1; // Different left endpoint: use the left endpoint to sort
49254
49255             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
49256             // into S after the line segment associated to e2 ?
49257
49258             if (compareEvents(le1, le2) === 1) return le2.isAbove(le1.point) ? -1 : 1; // The line segment associated to e2 has been inserted
49259             // into S after the line segment associated to e1
49260
49261             return le1.isBelow(le2.point) ? -1 : 1;
49262           }
49263
49264           if (le1.isSubject === le2.isSubject) {
49265             // same polygon
49266             var p1 = le1.point,
49267                 p2 = le2.point;
49268
49269             if (p1[0] === p2[0] && p1[1] === p2[1]
49270             /*equals(le1.point, le2.point)*/
49271             ) {
49272                 p1 = le1.otherEvent.point;
49273                 p2 = le2.otherEvent.point;
49274                 if (p1[0] === p2[0] && p1[1] === p2[1]) return 0;else return le1.contourId > le2.contourId ? 1 : -1;
49275               }
49276           } else {
49277             // Segments are collinear, but belong to separate polygons
49278             return le1.isSubject ? -1 : 1;
49279           }
49280
49281           return compareEvents(le1, le2) === 1 ? 1 : -1;
49282         }
49283
49284         function subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation) {
49285           var sweepLine = new SplayTree(compareSegments);
49286           var sortedEvents = [];
49287           var rightbound = Math.min(sbbox[2], cbbox[2]);
49288           var prev, next, begin;
49289
49290           while (eventQueue.length !== 0) {
49291             var event = eventQueue.pop();
49292             sortedEvents.push(event); // optimization by bboxes for intersection and difference goes here
49293
49294             if (operation === INTERSECTION && event.point[0] > rightbound || operation === DIFFERENCE && event.point[0] > sbbox[2]) {
49295               break;
49296             }
49297
49298             if (event.left) {
49299               next = prev = sweepLine.insert(event);
49300               begin = sweepLine.minNode();
49301               if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
49302               next = sweepLine.next(next);
49303               var prevEvent = prev ? prev.key : null;
49304               var prevprevEvent = void 0;
49305               computeFields(event, prevEvent, operation);
49306
49307               if (next) {
49308                 if (possibleIntersection(event, next.key, eventQueue) === 2) {
49309                   computeFields(event, prevEvent, operation);
49310                   computeFields(event, next.key, operation);
49311                 }
49312               }
49313
49314               if (prev) {
49315                 if (possibleIntersection(prev.key, event, eventQueue) === 2) {
49316                   var prevprev = prev;
49317                   if (prevprev !== begin) prevprev = sweepLine.prev(prevprev);else prevprev = null;
49318                   prevprevEvent = prevprev ? prevprev.key : null;
49319                   computeFields(prevEvent, prevprevEvent, operation);
49320                   computeFields(event, prevEvent, operation);
49321                 }
49322               }
49323             } else {
49324               event = event.otherEvent;
49325               next = prev = sweepLine.find(event);
49326
49327               if (prev && next) {
49328                 if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
49329                 next = sweepLine.next(next);
49330                 sweepLine.remove(event);
49331
49332                 if (next && prev) {
49333                   possibleIntersection(prev.key, next.key, eventQueue);
49334                 }
49335               }
49336             }
49337           }
49338
49339           return sortedEvents;
49340         }
49341
49342         var Contour = /*#__PURE__*/function () {
49343           /**
49344            * Contour
49345            *
49346            * @class {Contour}
49347            */
49348           function Contour() {
49349             _classCallCheck(this, Contour);
49350
49351             this.points = [];
49352             this.holeIds = [];
49353             this.holeOf = null;
49354             this.depth = null;
49355           }
49356
49357           _createClass(Contour, [{
49358             key: "isExterior",
49359             value: function isExterior() {
49360               return this.holeOf == null;
49361             }
49362           }]);
49363
49364           return Contour;
49365         }();
49366
49367         /**
49368          * @param  {Array.<SweepEvent>} sortedEvents
49369          * @return {Array.<SweepEvent>}
49370          */
49371
49372         function orderEvents(sortedEvents) {
49373           var event, i, len, tmp;
49374           var resultEvents = [];
49375
49376           for (i = 0, len = sortedEvents.length; i < len; i++) {
49377             event = sortedEvents[i];
49378
49379             if (event.left && event.inResult || !event.left && event.otherEvent.inResult) {
49380               resultEvents.push(event);
49381             }
49382           } // Due to overlapping edges the resultEvents array can be not wholly sorted
49383
49384
49385           var sorted = false;
49386
49387           while (!sorted) {
49388             sorted = true;
49389
49390             for (i = 0, len = resultEvents.length; i < len; i++) {
49391               if (i + 1 < len && compareEvents(resultEvents[i], resultEvents[i + 1]) === 1) {
49392                 tmp = resultEvents[i];
49393                 resultEvents[i] = resultEvents[i + 1];
49394                 resultEvents[i + 1] = tmp;
49395                 sorted = false;
49396               }
49397             }
49398           }
49399
49400           for (i = 0, len = resultEvents.length; i < len; i++) {
49401             event = resultEvents[i];
49402             event.otherPos = i;
49403           } // imagine, the right event is found in the beginning of the queue,
49404           // when his left counterpart is not marked yet
49405
49406
49407           for (i = 0, len = resultEvents.length; i < len; i++) {
49408             event = resultEvents[i];
49409
49410             if (!event.left) {
49411               tmp = event.otherPos;
49412               event.otherPos = event.otherEvent.otherPos;
49413               event.otherEvent.otherPos = tmp;
49414             }
49415           }
49416
49417           return resultEvents;
49418         }
49419         /**
49420          * @param  {Number} pos
49421          * @param  {Array.<SweepEvent>} resultEvents
49422          * @param  {Object>}    processed
49423          * @return {Number}
49424          */
49425
49426
49427         function nextPos(pos, resultEvents, processed, origPos) {
49428           var newPos = pos + 1,
49429               p = resultEvents[pos].point,
49430               p1;
49431           var length = resultEvents.length;
49432           if (newPos < length) p1 = resultEvents[newPos].point;
49433
49434           while (newPos < length && p1[0] === p[0] && p1[1] === p[1]) {
49435             if (!processed[newPos]) {
49436               return newPos;
49437             } else {
49438               newPos++;
49439             }
49440
49441             p1 = resultEvents[newPos].point;
49442           }
49443
49444           newPos = pos - 1;
49445
49446           while (processed[newPos] && newPos > origPos) {
49447             newPos--;
49448           }
49449
49450           return newPos;
49451         }
49452
49453         function initializeContourFromContext(event, contours, contourId) {
49454           var contour = new Contour();
49455
49456           if (event.prevInResult != null) {
49457             var prevInResult = event.prevInResult; // Note that it is valid to query the "previous in result" for its output contour id,
49458             // because we must have already processed it (i.e., assigned an output contour id)
49459             // in an earlier iteration, otherwise it wouldn't be possible that it is "previous in
49460             // result".
49461
49462             var lowerContourId = prevInResult.outputContourId;
49463             var lowerResultTransition = prevInResult.resultTransition;
49464
49465             if (lowerResultTransition > 0) {
49466               // We are inside. Now we have to check if the thing below us is another hole or
49467               // an exterior contour.
49468               var lowerContour = contours[lowerContourId];
49469
49470               if (lowerContour.holeOf != null) {
49471                 // The lower contour is a hole => Connect the new contour as a hole to its parent,
49472                 // and use same depth.
49473                 var parentContourId = lowerContour.holeOf;
49474                 contours[parentContourId].holeIds.push(contourId);
49475                 contour.holeOf = parentContourId;
49476                 contour.depth = contours[lowerContourId].depth;
49477               } else {
49478                 // The lower contour is an exterior contour => Connect the new contour as a hole,
49479                 // and increment depth.
49480                 contours[lowerContourId].holeIds.push(contourId);
49481                 contour.holeOf = lowerContourId;
49482                 contour.depth = contours[lowerContourId].depth + 1;
49483               }
49484             } else {
49485               // We are outside => this contour is an exterior contour of same depth.
49486               contour.holeOf = null;
49487               contour.depth = contours[lowerContourId].depth;
49488             }
49489           } else {
49490             // There is no lower/previous contour => this contour is an exterior contour of depth 0.
49491             contour.holeOf = null;
49492             contour.depth = 0;
49493           }
49494
49495           return contour;
49496         }
49497         /**
49498          * @param  {Array.<SweepEvent>} sortedEvents
49499          * @return {Array.<*>} polygons
49500          */
49501
49502
49503         function connectEdges(sortedEvents) {
49504           var i, len;
49505           var resultEvents = orderEvents(sortedEvents); // "false"-filled array
49506
49507           var processed = {};
49508           var contours = [];
49509
49510           var _loop = function _loop() {
49511             if (processed[i]) {
49512               return "continue";
49513             }
49514
49515             var contourId = contours.length;
49516             var contour = initializeContourFromContext(resultEvents[i], contours, contourId); // Helper function that combines marking an event as processed with assigning its output contour ID
49517
49518             var markAsProcessed = function markAsProcessed(pos) {
49519               processed[pos] = true;
49520               resultEvents[pos].outputContourId = contourId;
49521             };
49522
49523             var pos = i;
49524             var origPos = i;
49525             var initial = resultEvents[i].point;
49526             contour.points.push(initial);
49527             /* eslint no-constant-condition: "off" */
49528
49529             while (true) {
49530               markAsProcessed(pos);
49531               pos = resultEvents[pos].otherPos;
49532               markAsProcessed(pos);
49533               contour.points.push(resultEvents[pos].point);
49534               pos = nextPos(pos, resultEvents, processed, origPos);
49535
49536               if (pos == origPos) {
49537                 break;
49538               }
49539             }
49540
49541             contours.push(contour);
49542           };
49543
49544           for (i = 0, len = resultEvents.length; i < len; i++) {
49545             var _ret = _loop();
49546
49547             if (_ret === "continue") continue;
49548           }
49549
49550           return contours;
49551         }
49552
49553         var tinyqueue = TinyQueue;
49554         var _default = TinyQueue;
49555
49556         function TinyQueue(data, compare) {
49557           if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
49558           this.data = data || [];
49559           this.length = this.data.length;
49560           this.compare = compare || defaultCompare$1;
49561
49562           if (this.length > 0) {
49563             for (var i = (this.length >> 1) - 1; i >= 0; i--) {
49564               this._down(i);
49565             }
49566           }
49567         }
49568
49569         function defaultCompare$1(a, b) {
49570           return a < b ? -1 : a > b ? 1 : 0;
49571         }
49572
49573         TinyQueue.prototype = {
49574           push: function push(item) {
49575             this.data.push(item);
49576             this.length++;
49577
49578             this._up(this.length - 1);
49579           },
49580           pop: function pop() {
49581             if (this.length === 0) return undefined;
49582             var top = this.data[0];
49583             this.length--;
49584
49585             if (this.length > 0) {
49586               this.data[0] = this.data[this.length];
49587
49588               this._down(0);
49589             }
49590
49591             this.data.pop();
49592             return top;
49593           },
49594           peek: function peek() {
49595             return this.data[0];
49596           },
49597           _up: function _up(pos) {
49598             var data = this.data;
49599             var compare = this.compare;
49600             var item = data[pos];
49601
49602             while (pos > 0) {
49603               var parent = pos - 1 >> 1;
49604               var current = data[parent];
49605               if (compare(item, current) >= 0) break;
49606               data[pos] = current;
49607               pos = parent;
49608             }
49609
49610             data[pos] = item;
49611           },
49612           _down: function _down(pos) {
49613             var data = this.data;
49614             var compare = this.compare;
49615             var halfLength = this.length >> 1;
49616             var item = data[pos];
49617
49618             while (pos < halfLength) {
49619               var left = (pos << 1) + 1;
49620               var right = left + 1;
49621               var best = data[left];
49622
49623               if (right < this.length && compare(data[right], best) < 0) {
49624                 left = right;
49625                 best = data[right];
49626               }
49627
49628               if (compare(best, item) >= 0) break;
49629               data[pos] = best;
49630               pos = left;
49631             }
49632
49633             data[pos] = item;
49634           }
49635         };
49636         tinyqueue["default"] = _default;
49637
49638         var max$5 = Math.max;
49639         var min$8 = Math.min;
49640         var contourId = 0;
49641
49642         function processPolygon(contourOrHole, isSubject, depth, Q, bbox, isExteriorRing) {
49643           var i, len, s1, s2, e1, e2;
49644
49645           for (i = 0, len = contourOrHole.length - 1; i < len; i++) {
49646             s1 = contourOrHole[i];
49647             s2 = contourOrHole[i + 1];
49648             e1 = new SweepEvent(s1, false, undefined, isSubject);
49649             e2 = new SweepEvent(s2, false, e1, isSubject);
49650             e1.otherEvent = e2;
49651
49652             if (s1[0] === s2[0] && s1[1] === s2[1]) {
49653               continue; // skip collapsed edges, or it breaks
49654             }
49655
49656             e1.contourId = e2.contourId = depth;
49657
49658             if (!isExteriorRing) {
49659               e1.isExteriorRing = false;
49660               e2.isExteriorRing = false;
49661             }
49662
49663             if (compareEvents(e1, e2) > 0) {
49664               e2.left = true;
49665             } else {
49666               e1.left = true;
49667             }
49668
49669             var x = s1[0],
49670                 y = s1[1];
49671             bbox[0] = min$8(bbox[0], x);
49672             bbox[1] = min$8(bbox[1], y);
49673             bbox[2] = max$5(bbox[2], x);
49674             bbox[3] = max$5(bbox[3], y); // Pushing it so the queue is sorted from left to right,
49675             // with object on the left having the highest priority.
49676
49677             Q.push(e1);
49678             Q.push(e2);
49679           }
49680         }
49681
49682         function fillQueue(subject, clipping, sbbox, cbbox, operation) {
49683           var eventQueue = new tinyqueue(null, compareEvents);
49684           var polygonSet, isExteriorRing, i, ii, j, jj; //, k, kk;
49685
49686           for (i = 0, ii = subject.length; i < ii; i++) {
49687             polygonSet = subject[i];
49688
49689             for (j = 0, jj = polygonSet.length; j < jj; j++) {
49690               isExteriorRing = j === 0;
49691               if (isExteriorRing) contourId++;
49692               processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
49693             }
49694           }
49695
49696           for (i = 0, ii = clipping.length; i < ii; i++) {
49697             polygonSet = clipping[i];
49698
49699             for (j = 0, jj = polygonSet.length; j < jj; j++) {
49700               isExteriorRing = j === 0;
49701               if (operation === DIFFERENCE) isExteriorRing = false;
49702               if (isExteriorRing) contourId++;
49703               processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
49704             }
49705           }
49706
49707           return eventQueue;
49708         }
49709
49710         var EMPTY = [];
49711
49712         function trivialOperation(subject, clipping, operation) {
49713           var result = null;
49714
49715           if (subject.length * clipping.length === 0) {
49716             if (operation === INTERSECTION) {
49717               result = EMPTY;
49718             } else if (operation === DIFFERENCE) {
49719               result = subject;
49720             } else if (operation === UNION || operation === XOR) {
49721               result = subject.length === 0 ? clipping : subject;
49722             }
49723           }
49724
49725           return result;
49726         }
49727
49728         function compareBBoxes(subject, clipping, sbbox, cbbox, operation) {
49729           var result = null;
49730
49731           if (sbbox[0] > cbbox[2] || cbbox[0] > sbbox[2] || sbbox[1] > cbbox[3] || cbbox[1] > sbbox[3]) {
49732             if (operation === INTERSECTION) {
49733               result = EMPTY;
49734             } else if (operation === DIFFERENCE) {
49735               result = subject;
49736             } else if (operation === UNION || operation === XOR) {
49737               result = subject.concat(clipping);
49738             }
49739           }
49740
49741           return result;
49742         }
49743
49744         function _boolean(subject, clipping, operation) {
49745           if (typeof subject[0][0][0] === 'number') {
49746             subject = [subject];
49747           }
49748
49749           if (typeof clipping[0][0][0] === 'number') {
49750             clipping = [clipping];
49751           }
49752
49753           var trivial = trivialOperation(subject, clipping, operation);
49754
49755           if (trivial) {
49756             return trivial === EMPTY ? null : trivial;
49757           }
49758
49759           var sbbox = [Infinity, Infinity, -Infinity, -Infinity];
49760           var cbbox = [Infinity, Infinity, -Infinity, -Infinity]; // console.time('fill queue');
49761
49762           var eventQueue = fillQueue(subject, clipping, sbbox, cbbox, operation); //console.timeEnd('fill queue');
49763
49764           trivial = compareBBoxes(subject, clipping, sbbox, cbbox, operation);
49765
49766           if (trivial) {
49767             return trivial === EMPTY ? null : trivial;
49768           } // console.time('subdivide edges');
49769
49770
49771           var sortedEvents = subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation); //console.timeEnd('subdivide edges');
49772           // console.time('connect vertices');
49773
49774           var contours = connectEdges(sortedEvents); //console.timeEnd('connect vertices');
49775           // Convert contours to polygons
49776
49777           var polygons = [];
49778
49779           for (var i = 0; i < contours.length; i++) {
49780             var contour = contours[i];
49781
49782             if (contour.isExterior()) {
49783               // The exterior ring goes first
49784               var rings = [contour.points]; // Followed by holes if any
49785
49786               for (var j = 0; j < contour.holeIds.length; j++) {
49787                 var holeId = contour.holeIds[j];
49788                 rings.push(contours[holeId].points);
49789               }
49790
49791               polygons.push(rings);
49792             }
49793           }
49794
49795           return polygons;
49796         }
49797
49798         function union(subject, clipping) {
49799           return _boolean(subject, clipping, UNION);
49800         }
49801
49802         /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
49803         var read$6 = function read(buffer, offset, isLE, mLen, nBytes) {
49804           var e, m;
49805           var eLen = nBytes * 8 - mLen - 1;
49806           var eMax = (1 << eLen) - 1;
49807           var eBias = eMax >> 1;
49808           var nBits = -7;
49809           var i = isLE ? nBytes - 1 : 0;
49810           var d = isLE ? -1 : 1;
49811           var s = buffer[offset + i];
49812           i += d;
49813           e = s & (1 << -nBits) - 1;
49814           s >>= -nBits;
49815           nBits += eLen;
49816
49817           for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
49818
49819           m = e & (1 << -nBits) - 1;
49820           e >>= -nBits;
49821           nBits += mLen;
49822
49823           for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
49824
49825           if (e === 0) {
49826             e = 1 - eBias;
49827           } else if (e === eMax) {
49828             return m ? NaN : (s ? -1 : 1) * Infinity;
49829           } else {
49830             m = m + Math.pow(2, mLen);
49831             e = e - eBias;
49832           }
49833
49834           return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
49835         };
49836
49837         var write$6 = function write(buffer, value, offset, isLE, mLen, nBytes) {
49838           var e, m, c;
49839           var eLen = nBytes * 8 - mLen - 1;
49840           var eMax = (1 << eLen) - 1;
49841           var eBias = eMax >> 1;
49842           var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
49843           var i = isLE ? 0 : nBytes - 1;
49844           var d = isLE ? 1 : -1;
49845           var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
49846           value = Math.abs(value);
49847
49848           if (isNaN(value) || value === Infinity) {
49849             m = isNaN(value) ? 1 : 0;
49850             e = eMax;
49851           } else {
49852             e = Math.floor(Math.log(value) / Math.LN2);
49853
49854             if (value * (c = Math.pow(2, -e)) < 1) {
49855               e--;
49856               c *= 2;
49857             }
49858
49859             if (e + eBias >= 1) {
49860               value += rt / c;
49861             } else {
49862               value += rt * Math.pow(2, 1 - eBias);
49863             }
49864
49865             if (value * c >= 2) {
49866               e++;
49867               c /= 2;
49868             }
49869
49870             if (e + eBias >= eMax) {
49871               m = 0;
49872               e = eMax;
49873             } else if (e + eBias >= 1) {
49874               m = (value * c - 1) * Math.pow(2, mLen);
49875               e = e + eBias;
49876             } else {
49877               m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
49878               e = 0;
49879             }
49880           }
49881
49882           for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
49883
49884           e = e << mLen | m;
49885           eLen += mLen;
49886
49887           for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
49888
49889           buffer[offset + i - d] |= s * 128;
49890         };
49891
49892         var ieee754$1 = {
49893           read: read$6,
49894           write: write$6
49895         };
49896
49897         var pbf = Pbf;
49898
49899         function Pbf(buf) {
49900           this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
49901           this.pos = 0;
49902           this.type = 0;
49903           this.length = this.buf.length;
49904         }
49905
49906         Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
49907
49908         Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
49909
49910         Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
49911
49912         Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
49913
49914         var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
49915             SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
49916         // data structures (which currently switch structure types at 12 bytes or more)
49917
49918         var TEXT_DECODER_MIN_LENGTH = 12;
49919         var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
49920         Pbf.prototype = {
49921           destroy: function destroy() {
49922             this.buf = null;
49923           },
49924           // === READING =================================================================
49925           readFields: function readFields(readField, result, end) {
49926             end = end || this.length;
49927
49928             while (this.pos < end) {
49929               var val = this.readVarint(),
49930                   tag = val >> 3,
49931                   startPos = this.pos;
49932               this.type = val & 0x7;
49933               readField(tag, result, this);
49934               if (this.pos === startPos) this.skip(val);
49935             }
49936
49937             return result;
49938           },
49939           readMessage: function readMessage(readField, result) {
49940             return this.readFields(readField, result, this.readVarint() + this.pos);
49941           },
49942           readFixed32: function readFixed32() {
49943             var val = readUInt32(this.buf, this.pos);
49944             this.pos += 4;
49945             return val;
49946           },
49947           readSFixed32: function readSFixed32() {
49948             var val = readInt32(this.buf, this.pos);
49949             this.pos += 4;
49950             return val;
49951           },
49952           // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
49953           readFixed64: function readFixed64() {
49954             var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
49955             this.pos += 8;
49956             return val;
49957           },
49958           readSFixed64: function readSFixed64() {
49959             var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
49960             this.pos += 8;
49961             return val;
49962           },
49963           readFloat: function readFloat() {
49964             var val = ieee754$1.read(this.buf, this.pos, true, 23, 4);
49965             this.pos += 4;
49966             return val;
49967           },
49968           readDouble: function readDouble() {
49969             var val = ieee754$1.read(this.buf, this.pos, true, 52, 8);
49970             this.pos += 8;
49971             return val;
49972           },
49973           readVarint: function readVarint(isSigned) {
49974             var buf = this.buf,
49975                 val,
49976                 b;
49977             b = buf[this.pos++];
49978             val = b & 0x7f;
49979             if (b < 0x80) return val;
49980             b = buf[this.pos++];
49981             val |= (b & 0x7f) << 7;
49982             if (b < 0x80) return val;
49983             b = buf[this.pos++];
49984             val |= (b & 0x7f) << 14;
49985             if (b < 0x80) return val;
49986             b = buf[this.pos++];
49987             val |= (b & 0x7f) << 21;
49988             if (b < 0x80) return val;
49989             b = buf[this.pos];
49990             val |= (b & 0x0f) << 28;
49991             return readVarintRemainder(val, isSigned, this);
49992           },
49993           readVarint64: function readVarint64() {
49994             // for compatibility with v2.0.1
49995             return this.readVarint(true);
49996           },
49997           readSVarint: function readSVarint() {
49998             var num = this.readVarint();
49999             return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
50000           },
50001           readBoolean: function readBoolean() {
50002             return Boolean(this.readVarint());
50003           },
50004           readString: function readString() {
50005             var end = this.readVarint() + this.pos;
50006             var pos = this.pos;
50007             this.pos = end;
50008
50009             if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
50010               // longer strings are fast with the built-in browser TextDecoder API
50011               return readUtf8TextDecoder(this.buf, pos, end);
50012             } // short strings are fast with our custom implementation
50013
50014
50015             return readUtf8(this.buf, pos, end);
50016           },
50017           readBytes: function readBytes() {
50018             var end = this.readVarint() + this.pos,
50019                 buffer = this.buf.subarray(this.pos, end);
50020             this.pos = end;
50021             return buffer;
50022           },
50023           // verbose for performance reasons; doesn't affect gzipped size
50024           readPackedVarint: function readPackedVarint(arr, isSigned) {
50025             if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
50026             var end = readPackedEnd(this);
50027             arr = arr || [];
50028
50029             while (this.pos < end) {
50030               arr.push(this.readVarint(isSigned));
50031             }
50032
50033             return arr;
50034           },
50035           readPackedSVarint: function readPackedSVarint(arr) {
50036             if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
50037             var end = readPackedEnd(this);
50038             arr = arr || [];
50039
50040             while (this.pos < end) {
50041               arr.push(this.readSVarint());
50042             }
50043
50044             return arr;
50045           },
50046           readPackedBoolean: function readPackedBoolean(arr) {
50047             if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
50048             var end = readPackedEnd(this);
50049             arr = arr || [];
50050
50051             while (this.pos < end) {
50052               arr.push(this.readBoolean());
50053             }
50054
50055             return arr;
50056           },
50057           readPackedFloat: function readPackedFloat(arr) {
50058             if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
50059             var end = readPackedEnd(this);
50060             arr = arr || [];
50061
50062             while (this.pos < end) {
50063               arr.push(this.readFloat());
50064             }
50065
50066             return arr;
50067           },
50068           readPackedDouble: function readPackedDouble(arr) {
50069             if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
50070             var end = readPackedEnd(this);
50071             arr = arr || [];
50072
50073             while (this.pos < end) {
50074               arr.push(this.readDouble());
50075             }
50076
50077             return arr;
50078           },
50079           readPackedFixed32: function readPackedFixed32(arr) {
50080             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
50081             var end = readPackedEnd(this);
50082             arr = arr || [];
50083
50084             while (this.pos < end) {
50085               arr.push(this.readFixed32());
50086             }
50087
50088             return arr;
50089           },
50090           readPackedSFixed32: function readPackedSFixed32(arr) {
50091             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
50092             var end = readPackedEnd(this);
50093             arr = arr || [];
50094
50095             while (this.pos < end) {
50096               arr.push(this.readSFixed32());
50097             }
50098
50099             return arr;
50100           },
50101           readPackedFixed64: function readPackedFixed64(arr) {
50102             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
50103             var end = readPackedEnd(this);
50104             arr = arr || [];
50105
50106             while (this.pos < end) {
50107               arr.push(this.readFixed64());
50108             }
50109
50110             return arr;
50111           },
50112           readPackedSFixed64: function readPackedSFixed64(arr) {
50113             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
50114             var end = readPackedEnd(this);
50115             arr = arr || [];
50116
50117             while (this.pos < end) {
50118               arr.push(this.readSFixed64());
50119             }
50120
50121             return arr;
50122           },
50123           skip: function skip(val) {
50124             var type = val & 0x7;
50125             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);
50126           },
50127           // === WRITING =================================================================
50128           writeTag: function writeTag(tag, type) {
50129             this.writeVarint(tag << 3 | type);
50130           },
50131           realloc: function realloc(min) {
50132             var length = this.length || 16;
50133
50134             while (length < this.pos + min) {
50135               length *= 2;
50136             }
50137
50138             if (length !== this.length) {
50139               var buf = new Uint8Array(length);
50140               buf.set(this.buf);
50141               this.buf = buf;
50142               this.length = length;
50143             }
50144           },
50145           finish: function finish() {
50146             this.length = this.pos;
50147             this.pos = 0;
50148             return this.buf.subarray(0, this.length);
50149           },
50150           writeFixed32: function writeFixed32(val) {
50151             this.realloc(4);
50152             writeInt32(this.buf, val, this.pos);
50153             this.pos += 4;
50154           },
50155           writeSFixed32: function writeSFixed32(val) {
50156             this.realloc(4);
50157             writeInt32(this.buf, val, this.pos);
50158             this.pos += 4;
50159           },
50160           writeFixed64: function writeFixed64(val) {
50161             this.realloc(8);
50162             writeInt32(this.buf, val & -1, this.pos);
50163             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
50164             this.pos += 8;
50165           },
50166           writeSFixed64: function writeSFixed64(val) {
50167             this.realloc(8);
50168             writeInt32(this.buf, val & -1, this.pos);
50169             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
50170             this.pos += 8;
50171           },
50172           writeVarint: function writeVarint(val) {
50173             val = +val || 0;
50174
50175             if (val > 0xfffffff || val < 0) {
50176               writeBigVarint(val, this);
50177               return;
50178             }
50179
50180             this.realloc(4);
50181             this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
50182             if (val <= 0x7f) return;
50183             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
50184             if (val <= 0x7f) return;
50185             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
50186             if (val <= 0x7f) return;
50187             this.buf[this.pos++] = val >>> 7 & 0x7f;
50188           },
50189           writeSVarint: function writeSVarint(val) {
50190             this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
50191           },
50192           writeBoolean: function writeBoolean(val) {
50193             this.writeVarint(Boolean(val));
50194           },
50195           writeString: function writeString(str) {
50196             str = String(str);
50197             this.realloc(str.length * 4);
50198             this.pos++; // reserve 1 byte for short string length
50199
50200             var startPos = this.pos; // write the string directly to the buffer and see how much was written
50201
50202             this.pos = writeUtf8(this.buf, str, this.pos);
50203             var len = this.pos - startPos;
50204             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
50205
50206             this.pos = startPos - 1;
50207             this.writeVarint(len);
50208             this.pos += len;
50209           },
50210           writeFloat: function writeFloat(val) {
50211             this.realloc(4);
50212             ieee754$1.write(this.buf, val, this.pos, true, 23, 4);
50213             this.pos += 4;
50214           },
50215           writeDouble: function writeDouble(val) {
50216             this.realloc(8);
50217             ieee754$1.write(this.buf, val, this.pos, true, 52, 8);
50218             this.pos += 8;
50219           },
50220           writeBytes: function writeBytes(buffer) {
50221             var len = buffer.length;
50222             this.writeVarint(len);
50223             this.realloc(len);
50224
50225             for (var i = 0; i < len; i++) {
50226               this.buf[this.pos++] = buffer[i];
50227             }
50228           },
50229           writeRawMessage: function writeRawMessage(fn, obj) {
50230             this.pos++; // reserve 1 byte for short message length
50231             // write the message directly to the buffer and see how much was written
50232
50233             var startPos = this.pos;
50234             fn(obj, this);
50235             var len = this.pos - startPos;
50236             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
50237
50238             this.pos = startPos - 1;
50239             this.writeVarint(len);
50240             this.pos += len;
50241           },
50242           writeMessage: function writeMessage(tag, fn, obj) {
50243             this.writeTag(tag, Pbf.Bytes);
50244             this.writeRawMessage(fn, obj);
50245           },
50246           writePackedVarint: function writePackedVarint(tag, arr) {
50247             if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
50248           },
50249           writePackedSVarint: function writePackedSVarint(tag, arr) {
50250             if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
50251           },
50252           writePackedBoolean: function writePackedBoolean(tag, arr) {
50253             if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
50254           },
50255           writePackedFloat: function writePackedFloat(tag, arr) {
50256             if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
50257           },
50258           writePackedDouble: function writePackedDouble(tag, arr) {
50259             if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
50260           },
50261           writePackedFixed32: function writePackedFixed32(tag, arr) {
50262             if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
50263           },
50264           writePackedSFixed32: function writePackedSFixed32(tag, arr) {
50265             if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
50266           },
50267           writePackedFixed64: function writePackedFixed64(tag, arr) {
50268             if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
50269           },
50270           writePackedSFixed64: function writePackedSFixed64(tag, arr) {
50271             if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
50272           },
50273           writeBytesField: function writeBytesField(tag, buffer) {
50274             this.writeTag(tag, Pbf.Bytes);
50275             this.writeBytes(buffer);
50276           },
50277           writeFixed32Field: function writeFixed32Field(tag, val) {
50278             this.writeTag(tag, Pbf.Fixed32);
50279             this.writeFixed32(val);
50280           },
50281           writeSFixed32Field: function writeSFixed32Field(tag, val) {
50282             this.writeTag(tag, Pbf.Fixed32);
50283             this.writeSFixed32(val);
50284           },
50285           writeFixed64Field: function writeFixed64Field(tag, val) {
50286             this.writeTag(tag, Pbf.Fixed64);
50287             this.writeFixed64(val);
50288           },
50289           writeSFixed64Field: function writeSFixed64Field(tag, val) {
50290             this.writeTag(tag, Pbf.Fixed64);
50291             this.writeSFixed64(val);
50292           },
50293           writeVarintField: function writeVarintField(tag, val) {
50294             this.writeTag(tag, Pbf.Varint);
50295             this.writeVarint(val);
50296           },
50297           writeSVarintField: function writeSVarintField(tag, val) {
50298             this.writeTag(tag, Pbf.Varint);
50299             this.writeSVarint(val);
50300           },
50301           writeStringField: function writeStringField(tag, str) {
50302             this.writeTag(tag, Pbf.Bytes);
50303             this.writeString(str);
50304           },
50305           writeFloatField: function writeFloatField(tag, val) {
50306             this.writeTag(tag, Pbf.Fixed32);
50307             this.writeFloat(val);
50308           },
50309           writeDoubleField: function writeDoubleField(tag, val) {
50310             this.writeTag(tag, Pbf.Fixed64);
50311             this.writeDouble(val);
50312           },
50313           writeBooleanField: function writeBooleanField(tag, val) {
50314             this.writeVarintField(tag, Boolean(val));
50315           }
50316         };
50317
50318         function readVarintRemainder(l, s, p) {
50319           var buf = p.buf,
50320               h,
50321               b;
50322           b = buf[p.pos++];
50323           h = (b & 0x70) >> 4;
50324           if (b < 0x80) return toNum(l, h, s);
50325           b = buf[p.pos++];
50326           h |= (b & 0x7f) << 3;
50327           if (b < 0x80) return toNum(l, h, s);
50328           b = buf[p.pos++];
50329           h |= (b & 0x7f) << 10;
50330           if (b < 0x80) return toNum(l, h, s);
50331           b = buf[p.pos++];
50332           h |= (b & 0x7f) << 17;
50333           if (b < 0x80) return toNum(l, h, s);
50334           b = buf[p.pos++];
50335           h |= (b & 0x7f) << 24;
50336           if (b < 0x80) return toNum(l, h, s);
50337           b = buf[p.pos++];
50338           h |= (b & 0x01) << 31;
50339           if (b < 0x80) return toNum(l, h, s);
50340           throw new Error('Expected varint not more than 10 bytes');
50341         }
50342
50343         function readPackedEnd(pbf) {
50344           return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
50345         }
50346
50347         function toNum(low, high, isSigned) {
50348           if (isSigned) {
50349             return high * 0x100000000 + (low >>> 0);
50350           }
50351
50352           return (high >>> 0) * 0x100000000 + (low >>> 0);
50353         }
50354
50355         function writeBigVarint(val, pbf) {
50356           var low, high;
50357
50358           if (val >= 0) {
50359             low = val % 0x100000000 | 0;
50360             high = val / 0x100000000 | 0;
50361           } else {
50362             low = ~(-val % 0x100000000);
50363             high = ~(-val / 0x100000000);
50364
50365             if (low ^ 0xffffffff) {
50366               low = low + 1 | 0;
50367             } else {
50368               low = 0;
50369               high = high + 1 | 0;
50370             }
50371           }
50372
50373           if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
50374             throw new Error('Given varint doesn\'t fit into 10 bytes');
50375           }
50376
50377           pbf.realloc(10);
50378           writeBigVarintLow(low, high, pbf);
50379           writeBigVarintHigh(high, pbf);
50380         }
50381
50382         function writeBigVarintLow(low, high, pbf) {
50383           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50384           low >>>= 7;
50385           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50386           low >>>= 7;
50387           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50388           low >>>= 7;
50389           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
50390           low >>>= 7;
50391           pbf.buf[pbf.pos] = low & 0x7f;
50392         }
50393
50394         function writeBigVarintHigh(high, pbf) {
50395           var lsb = (high & 0x07) << 4;
50396           pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
50397           if (!high) return;
50398           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50399           if (!high) return;
50400           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50401           if (!high) return;
50402           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50403           if (!high) return;
50404           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
50405           if (!high) return;
50406           pbf.buf[pbf.pos++] = high & 0x7f;
50407         }
50408
50409         function makeRoomForExtraLength(startPos, len, pbf) {
50410           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
50411
50412           pbf.realloc(extraLen);
50413
50414           for (var i = pbf.pos - 1; i >= startPos; i--) {
50415             pbf.buf[i + extraLen] = pbf.buf[i];
50416           }
50417         }
50418
50419         function _writePackedVarint(arr, pbf) {
50420           for (var i = 0; i < arr.length; i++) {
50421             pbf.writeVarint(arr[i]);
50422           }
50423         }
50424
50425         function _writePackedSVarint(arr, pbf) {
50426           for (var i = 0; i < arr.length; i++) {
50427             pbf.writeSVarint(arr[i]);
50428           }
50429         }
50430
50431         function _writePackedFloat(arr, pbf) {
50432           for (var i = 0; i < arr.length; i++) {
50433             pbf.writeFloat(arr[i]);
50434           }
50435         }
50436
50437         function _writePackedDouble(arr, pbf) {
50438           for (var i = 0; i < arr.length; i++) {
50439             pbf.writeDouble(arr[i]);
50440           }
50441         }
50442
50443         function _writePackedBoolean(arr, pbf) {
50444           for (var i = 0; i < arr.length; i++) {
50445             pbf.writeBoolean(arr[i]);
50446           }
50447         }
50448
50449         function _writePackedFixed(arr, pbf) {
50450           for (var i = 0; i < arr.length; i++) {
50451             pbf.writeFixed32(arr[i]);
50452           }
50453         }
50454
50455         function _writePackedSFixed(arr, pbf) {
50456           for (var i = 0; i < arr.length; i++) {
50457             pbf.writeSFixed32(arr[i]);
50458           }
50459         }
50460
50461         function _writePackedFixed2(arr, pbf) {
50462           for (var i = 0; i < arr.length; i++) {
50463             pbf.writeFixed64(arr[i]);
50464           }
50465         }
50466
50467         function _writePackedSFixed2(arr, pbf) {
50468           for (var i = 0; i < arr.length; i++) {
50469             pbf.writeSFixed64(arr[i]);
50470           }
50471         } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
50472
50473
50474         function readUInt32(buf, pos) {
50475           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
50476         }
50477
50478         function writeInt32(buf, val, pos) {
50479           buf[pos] = val;
50480           buf[pos + 1] = val >>> 8;
50481           buf[pos + 2] = val >>> 16;
50482           buf[pos + 3] = val >>> 24;
50483         }
50484
50485         function readInt32(buf, pos) {
50486           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
50487         }
50488
50489         function readUtf8(buf, pos, end) {
50490           var str = '';
50491           var i = pos;
50492
50493           while (i < end) {
50494             var b0 = buf[i];
50495             var c = null; // codepoint
50496
50497             var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
50498             if (i + bytesPerSequence > end) break;
50499             var b1, b2, b3;
50500
50501             if (bytesPerSequence === 1) {
50502               if (b0 < 0x80) {
50503                 c = b0;
50504               }
50505             } else if (bytesPerSequence === 2) {
50506               b1 = buf[i + 1];
50507
50508               if ((b1 & 0xC0) === 0x80) {
50509                 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
50510
50511                 if (c <= 0x7F) {
50512                   c = null;
50513                 }
50514               }
50515             } else if (bytesPerSequence === 3) {
50516               b1 = buf[i + 1];
50517               b2 = buf[i + 2];
50518
50519               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
50520                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
50521
50522                 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
50523                   c = null;
50524                 }
50525               }
50526             } else if (bytesPerSequence === 4) {
50527               b1 = buf[i + 1];
50528               b2 = buf[i + 2];
50529               b3 = buf[i + 3];
50530
50531               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
50532                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
50533
50534                 if (c <= 0xFFFF || c >= 0x110000) {
50535                   c = null;
50536                 }
50537               }
50538             }
50539
50540             if (c === null) {
50541               c = 0xFFFD;
50542               bytesPerSequence = 1;
50543             } else if (c > 0xFFFF) {
50544               c -= 0x10000;
50545               str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
50546               c = 0xDC00 | c & 0x3FF;
50547             }
50548
50549             str += String.fromCharCode(c);
50550             i += bytesPerSequence;
50551           }
50552
50553           return str;
50554         }
50555
50556         function readUtf8TextDecoder(buf, pos, end) {
50557           return utf8TextDecoder.decode(buf.subarray(pos, end));
50558         }
50559
50560         function writeUtf8(buf, str, pos) {
50561           for (var i = 0, c, lead; i < str.length; i++) {
50562             c = str.charCodeAt(i); // code point
50563
50564             if (c > 0xD7FF && c < 0xE000) {
50565               if (lead) {
50566                 if (c < 0xDC00) {
50567                   buf[pos++] = 0xEF;
50568                   buf[pos++] = 0xBF;
50569                   buf[pos++] = 0xBD;
50570                   lead = c;
50571                   continue;
50572                 } else {
50573                   c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
50574                   lead = null;
50575                 }
50576               } else {
50577                 if (c > 0xDBFF || i + 1 === str.length) {
50578                   buf[pos++] = 0xEF;
50579                   buf[pos++] = 0xBF;
50580                   buf[pos++] = 0xBD;
50581                 } else {
50582                   lead = c;
50583                 }
50584
50585                 continue;
50586               }
50587             } else if (lead) {
50588               buf[pos++] = 0xEF;
50589               buf[pos++] = 0xBF;
50590               buf[pos++] = 0xBD;
50591               lead = null;
50592             }
50593
50594             if (c < 0x80) {
50595               buf[pos++] = c;
50596             } else {
50597               if (c < 0x800) {
50598                 buf[pos++] = c >> 0x6 | 0xC0;
50599               } else {
50600                 if (c < 0x10000) {
50601                   buf[pos++] = c >> 0xC | 0xE0;
50602                 } else {
50603                   buf[pos++] = c >> 0x12 | 0xF0;
50604                   buf[pos++] = c >> 0xC & 0x3F | 0x80;
50605                 }
50606
50607                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
50608               }
50609
50610               buf[pos++] = c & 0x3F | 0x80;
50611             }
50612           }
50613
50614           return pos;
50615         }
50616
50617         var pointGeometry = Point;
50618         /**
50619          * A standalone point geometry with useful accessor, comparison, and
50620          * modification methods.
50621          *
50622          * @class Point
50623          * @param {Number} x the x-coordinate. this could be longitude or screen
50624          * pixels, or any other sort of unit.
50625          * @param {Number} y the y-coordinate. this could be latitude or screen
50626          * pixels, or any other sort of unit.
50627          * @example
50628          * var point = new Point(-77, 38);
50629          */
50630
50631         function Point(x, y) {
50632           this.x = x;
50633           this.y = y;
50634         }
50635
50636         Point.prototype = {
50637           /**
50638            * Clone this point, returning a new point that can be modified
50639            * without affecting the old one.
50640            * @return {Point} the clone
50641            */
50642           clone: function clone() {
50643             return new Point(this.x, this.y);
50644           },
50645
50646           /**
50647            * Add this point's x & y coordinates to another point,
50648            * yielding a new point.
50649            * @param {Point} p the other point
50650            * @return {Point} output point
50651            */
50652           add: function add(p) {
50653             return this.clone()._add(p);
50654           },
50655
50656           /**
50657            * Subtract this point's x & y coordinates to from point,
50658            * yielding a new point.
50659            * @param {Point} p the other point
50660            * @return {Point} output point
50661            */
50662           sub: function sub(p) {
50663             return this.clone()._sub(p);
50664           },
50665
50666           /**
50667            * Multiply this point's x & y coordinates by point,
50668            * yielding a new point.
50669            * @param {Point} p the other point
50670            * @return {Point} output point
50671            */
50672           multByPoint: function multByPoint(p) {
50673             return this.clone()._multByPoint(p);
50674           },
50675
50676           /**
50677            * Divide this point's x & y coordinates by point,
50678            * yielding a new point.
50679            * @param {Point} p the other point
50680            * @return {Point} output point
50681            */
50682           divByPoint: function divByPoint(p) {
50683             return this.clone()._divByPoint(p);
50684           },
50685
50686           /**
50687            * Multiply this point's x & y coordinates by a factor,
50688            * yielding a new point.
50689            * @param {Point} k factor
50690            * @return {Point} output point
50691            */
50692           mult: function mult(k) {
50693             return this.clone()._mult(k);
50694           },
50695
50696           /**
50697            * Divide this point's x & y coordinates by a factor,
50698            * yielding a new point.
50699            * @param {Point} k factor
50700            * @return {Point} output point
50701            */
50702           div: function div(k) {
50703             return this.clone()._div(k);
50704           },
50705
50706           /**
50707            * Rotate this point around the 0, 0 origin by an angle a,
50708            * given in radians
50709            * @param {Number} a angle to rotate around, in radians
50710            * @return {Point} output point
50711            */
50712           rotate: function rotate(a) {
50713             return this.clone()._rotate(a);
50714           },
50715
50716           /**
50717            * Rotate this point around p point by an angle a,
50718            * given in radians
50719            * @param {Number} a angle to rotate around, in radians
50720            * @param {Point} p Point to rotate around
50721            * @return {Point} output point
50722            */
50723           rotateAround: function rotateAround(a, p) {
50724             return this.clone()._rotateAround(a, p);
50725           },
50726
50727           /**
50728            * Multiply this point by a 4x1 transformation matrix
50729            * @param {Array<Number>} m transformation matrix
50730            * @return {Point} output point
50731            */
50732           matMult: function matMult(m) {
50733             return this.clone()._matMult(m);
50734           },
50735
50736           /**
50737            * Calculate this point but as a unit vector from 0, 0, meaning
50738            * that the distance from the resulting point to the 0, 0
50739            * coordinate will be equal to 1 and the angle from the resulting
50740            * point to the 0, 0 coordinate will be the same as before.
50741            * @return {Point} unit vector point
50742            */
50743           unit: function unit() {
50744             return this.clone()._unit();
50745           },
50746
50747           /**
50748            * Compute a perpendicular point, where the new y coordinate
50749            * is the old x coordinate and the new x coordinate is the old y
50750            * coordinate multiplied by -1
50751            * @return {Point} perpendicular point
50752            */
50753           perp: function perp() {
50754             return this.clone()._perp();
50755           },
50756
50757           /**
50758            * Return a version of this point with the x & y coordinates
50759            * rounded to integers.
50760            * @return {Point} rounded point
50761            */
50762           round: function round() {
50763             return this.clone()._round();
50764           },
50765
50766           /**
50767            * Return the magitude of this point: this is the Euclidean
50768            * distance from the 0, 0 coordinate to this point's x and y
50769            * coordinates.
50770            * @return {Number} magnitude
50771            */
50772           mag: function mag() {
50773             return Math.sqrt(this.x * this.x + this.y * this.y);
50774           },
50775
50776           /**
50777            * Judge whether this point is equal to another point, returning
50778            * true or false.
50779            * @param {Point} other the other point
50780            * @return {boolean} whether the points are equal
50781            */
50782           equals: function equals(other) {
50783             return this.x === other.x && this.y === other.y;
50784           },
50785
50786           /**
50787            * Calculate the distance from this point to another point
50788            * @param {Point} p the other point
50789            * @return {Number} distance
50790            */
50791           dist: function dist(p) {
50792             return Math.sqrt(this.distSqr(p));
50793           },
50794
50795           /**
50796            * Calculate the distance from this point to another point,
50797            * without the square root step. Useful if you're comparing
50798            * relative distances.
50799            * @param {Point} p the other point
50800            * @return {Number} distance
50801            */
50802           distSqr: function distSqr(p) {
50803             var dx = p.x - this.x,
50804                 dy = p.y - this.y;
50805             return dx * dx + dy * dy;
50806           },
50807
50808           /**
50809            * Get the angle from the 0, 0 coordinate to this point, in radians
50810            * coordinates.
50811            * @return {Number} angle
50812            */
50813           angle: function angle() {
50814             return Math.atan2(this.y, this.x);
50815           },
50816
50817           /**
50818            * Get the angle from this point to another point, in radians
50819            * @param {Point} b the other point
50820            * @return {Number} angle
50821            */
50822           angleTo: function angleTo(b) {
50823             return Math.atan2(this.y - b.y, this.x - b.x);
50824           },
50825
50826           /**
50827            * Get the angle between this point and another point, in radians
50828            * @param {Point} b the other point
50829            * @return {Number} angle
50830            */
50831           angleWith: function angleWith(b) {
50832             return this.angleWithSep(b.x, b.y);
50833           },
50834
50835           /*
50836            * Find the angle of the two vectors, solving the formula for
50837            * the cross product a x b = |a||b|sin(θ) for θ.
50838            * @param {Number} x the x-coordinate
50839            * @param {Number} y the y-coordinate
50840            * @return {Number} the angle in radians
50841            */
50842           angleWithSep: function angleWithSep(x, y) {
50843             return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
50844           },
50845           _matMult: function _matMult(m) {
50846             var x = m[0] * this.x + m[1] * this.y,
50847                 y = m[2] * this.x + m[3] * this.y;
50848             this.x = x;
50849             this.y = y;
50850             return this;
50851           },
50852           _add: function _add(p) {
50853             this.x += p.x;
50854             this.y += p.y;
50855             return this;
50856           },
50857           _sub: function _sub(p) {
50858             this.x -= p.x;
50859             this.y -= p.y;
50860             return this;
50861           },
50862           _mult: function _mult(k) {
50863             this.x *= k;
50864             this.y *= k;
50865             return this;
50866           },
50867           _div: function _div(k) {
50868             this.x /= k;
50869             this.y /= k;
50870             return this;
50871           },
50872           _multByPoint: function _multByPoint(p) {
50873             this.x *= p.x;
50874             this.y *= p.y;
50875             return this;
50876           },
50877           _divByPoint: function _divByPoint(p) {
50878             this.x /= p.x;
50879             this.y /= p.y;
50880             return this;
50881           },
50882           _unit: function _unit() {
50883             this._div(this.mag());
50884
50885             return this;
50886           },
50887           _perp: function _perp() {
50888             var y = this.y;
50889             this.y = this.x;
50890             this.x = -y;
50891             return this;
50892           },
50893           _rotate: function _rotate(angle) {
50894             var cos = Math.cos(angle),
50895                 sin = Math.sin(angle),
50896                 x = cos * this.x - sin * this.y,
50897                 y = sin * this.x + cos * this.y;
50898             this.x = x;
50899             this.y = y;
50900             return this;
50901           },
50902           _rotateAround: function _rotateAround(angle, p) {
50903             var cos = Math.cos(angle),
50904                 sin = Math.sin(angle),
50905                 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
50906                 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
50907             this.x = x;
50908             this.y = y;
50909             return this;
50910           },
50911           _round: function _round() {
50912             this.x = Math.round(this.x);
50913             this.y = Math.round(this.y);
50914             return this;
50915           }
50916         };
50917         /**
50918          * Construct a point from an array if necessary, otherwise if the input
50919          * is already a Point, or an unknown type, return it unchanged
50920          * @param {Array<Number>|Point|*} a any kind of input value
50921          * @return {Point} constructed point, or passed-through value.
50922          * @example
50923          * // this
50924          * var point = Point.convert([0, 1]);
50925          * // is equivalent to
50926          * var point = new Point(0, 1);
50927          */
50928
50929         Point.convert = function (a) {
50930           if (a instanceof Point) {
50931             return a;
50932           }
50933
50934           if (Array.isArray(a)) {
50935             return new Point(a[0], a[1]);
50936           }
50937
50938           return a;
50939         };
50940
50941         var vectortilefeature = VectorTileFeature;
50942
50943         function VectorTileFeature(pbf, end, extent, keys, values) {
50944           // Public
50945           this.properties = {};
50946           this.extent = extent;
50947           this.type = 0; // Private
50948
50949           this._pbf = pbf;
50950           this._geometry = -1;
50951           this._keys = keys;
50952           this._values = values;
50953           pbf.readFields(readFeature, this, end);
50954         }
50955
50956         function readFeature(tag, feature, pbf) {
50957           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;
50958         }
50959
50960         function readTag(pbf, feature) {
50961           var end = pbf.readVarint() + pbf.pos;
50962
50963           while (pbf.pos < end) {
50964             var key = feature._keys[pbf.readVarint()],
50965                 value = feature._values[pbf.readVarint()];
50966
50967             feature.properties[key] = value;
50968           }
50969         }
50970
50971         VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
50972
50973         VectorTileFeature.prototype.loadGeometry = function () {
50974           var pbf = this._pbf;
50975           pbf.pos = this._geometry;
50976           var end = pbf.readVarint() + pbf.pos,
50977               cmd = 1,
50978               length = 0,
50979               x = 0,
50980               y = 0,
50981               lines = [],
50982               line;
50983
50984           while (pbf.pos < end) {
50985             if (length <= 0) {
50986               var cmdLen = pbf.readVarint();
50987               cmd = cmdLen & 0x7;
50988               length = cmdLen >> 3;
50989             }
50990
50991             length--;
50992
50993             if (cmd === 1 || cmd === 2) {
50994               x += pbf.readSVarint();
50995               y += pbf.readSVarint();
50996
50997               if (cmd === 1) {
50998                 // moveTo
50999                 if (line) lines.push(line);
51000                 line = [];
51001               }
51002
51003               line.push(new pointGeometry(x, y));
51004             } else if (cmd === 7) {
51005               // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
51006               if (line) {
51007                 line.push(line[0].clone()); // closePolygon
51008               }
51009             } else {
51010               throw new Error('unknown command ' + cmd);
51011             }
51012           }
51013
51014           if (line) lines.push(line);
51015           return lines;
51016         };
51017
51018         VectorTileFeature.prototype.bbox = function () {
51019           var pbf = this._pbf;
51020           pbf.pos = this._geometry;
51021           var end = pbf.readVarint() + pbf.pos,
51022               cmd = 1,
51023               length = 0,
51024               x = 0,
51025               y = 0,
51026               x1 = Infinity,
51027               x2 = -Infinity,
51028               y1 = Infinity,
51029               y2 = -Infinity;
51030
51031           while (pbf.pos < end) {
51032             if (length <= 0) {
51033               var cmdLen = pbf.readVarint();
51034               cmd = cmdLen & 0x7;
51035               length = cmdLen >> 3;
51036             }
51037
51038             length--;
51039
51040             if (cmd === 1 || cmd === 2) {
51041               x += pbf.readSVarint();
51042               y += pbf.readSVarint();
51043               if (x < x1) x1 = x;
51044               if (x > x2) x2 = x;
51045               if (y < y1) y1 = y;
51046               if (y > y2) y2 = y;
51047             } else if (cmd !== 7) {
51048               throw new Error('unknown command ' + cmd);
51049             }
51050           }
51051
51052           return [x1, y1, x2, y2];
51053         };
51054
51055         VectorTileFeature.prototype.toGeoJSON = function (x, y, z) {
51056           var size = this.extent * Math.pow(2, z),
51057               x0 = this.extent * x,
51058               y0 = this.extent * y,
51059               coords = this.loadGeometry(),
51060               type = VectorTileFeature.types[this.type],
51061               i,
51062               j;
51063
51064           function project(line) {
51065             for (var j = 0; j < line.length; j++) {
51066               var p = line[j],
51067                   y2 = 180 - (p.y + y0) * 360 / size;
51068               line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
51069             }
51070           }
51071
51072           switch (this.type) {
51073             case 1:
51074               var points = [];
51075
51076               for (i = 0; i < coords.length; i++) {
51077                 points[i] = coords[i][0];
51078               }
51079
51080               coords = points;
51081               project(coords);
51082               break;
51083
51084             case 2:
51085               for (i = 0; i < coords.length; i++) {
51086                 project(coords[i]);
51087               }
51088
51089               break;
51090
51091             case 3:
51092               coords = classifyRings(coords);
51093
51094               for (i = 0; i < coords.length; i++) {
51095                 for (j = 0; j < coords[i].length; j++) {
51096                   project(coords[i][j]);
51097                 }
51098               }
51099
51100               break;
51101           }
51102
51103           if (coords.length === 1) {
51104             coords = coords[0];
51105           } else {
51106             type = 'Multi' + type;
51107           }
51108
51109           var result = {
51110             type: "Feature",
51111             geometry: {
51112               type: type,
51113               coordinates: coords
51114             },
51115             properties: this.properties
51116           };
51117
51118           if ('id' in this) {
51119             result.id = this.id;
51120           }
51121
51122           return result;
51123         }; // classifies an array of rings into polygons with outer rings and holes
51124
51125
51126         function classifyRings(rings) {
51127           var len = rings.length;
51128           if (len <= 1) return [rings];
51129           var polygons = [],
51130               polygon,
51131               ccw;
51132
51133           for (var i = 0; i < len; i++) {
51134             var area = signedArea$1(rings[i]);
51135             if (area === 0) continue;
51136             if (ccw === undefined) ccw = area < 0;
51137
51138             if (ccw === area < 0) {
51139               if (polygon) polygons.push(polygon);
51140               polygon = [rings[i]];
51141             } else {
51142               polygon.push(rings[i]);
51143             }
51144           }
51145
51146           if (polygon) polygons.push(polygon);
51147           return polygons;
51148         }
51149
51150         function signedArea$1(ring) {
51151           var sum = 0;
51152
51153           for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
51154             p1 = ring[i];
51155             p2 = ring[j];
51156             sum += (p2.x - p1.x) * (p1.y + p2.y);
51157           }
51158
51159           return sum;
51160         }
51161
51162         var vectortilelayer = VectorTileLayer;
51163
51164         function VectorTileLayer(pbf, end) {
51165           // Public
51166           this.version = 1;
51167           this.name = null;
51168           this.extent = 4096;
51169           this.length = 0; // Private
51170
51171           this._pbf = pbf;
51172           this._keys = [];
51173           this._values = [];
51174           this._features = [];
51175           pbf.readFields(readLayer, this, end);
51176           this.length = this._features.length;
51177         }
51178
51179         function readLayer(tag, layer, pbf) {
51180           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));
51181         }
51182
51183         function readValueMessage(pbf) {
51184           var value = null,
51185               end = pbf.readVarint() + pbf.pos;
51186
51187           while (pbf.pos < end) {
51188             var tag = pbf.readVarint() >> 3;
51189             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;
51190           }
51191
51192           return value;
51193         } // return feature `i` from this layer as a `VectorTileFeature`
51194
51195
51196         VectorTileLayer.prototype.feature = function (i) {
51197           if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
51198           this._pbf.pos = this._features[i];
51199
51200           var end = this._pbf.readVarint() + this._pbf.pos;
51201
51202           return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
51203         };
51204
51205         var vectortile = VectorTile;
51206
51207         function VectorTile(pbf, end) {
51208           this.layers = pbf.readFields(readTile, {}, end);
51209         }
51210
51211         function readTile(tag, layers, pbf) {
51212           if (tag === 3) {
51213             var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
51214             if (layer.length) layers[layer.name] = layer;
51215           }
51216         }
51217
51218         var VectorTile$1 = vectortile;
51219         var VectorTileFeature$1 = vectortilefeature;
51220         var VectorTileLayer$1 = vectortilelayer;
51221         var vectorTile = {
51222           VectorTile: VectorTile$1,
51223           VectorTileFeature: VectorTileFeature$1,
51224           VectorTileLayer: VectorTileLayer$1
51225         };
51226
51227         var tiler$7 = utilTiler().tileSize(512).margin(1);
51228         var dispatch$8 = dispatch('loadedData');
51229
51230         var _vtCache;
51231
51232         function abortRequest$7(controller) {
51233           controller.abort();
51234         }
51235
51236         function vtToGeoJSON(data, tile, mergeCache) {
51237           var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
51238           var layers = Object.keys(vectorTile$1.layers);
51239
51240           if (!Array.isArray(layers)) {
51241             layers = [layers];
51242           }
51243
51244           var features = [];
51245           layers.forEach(function (layerID) {
51246             var layer = vectorTile$1.layers[layerID];
51247
51248             if (layer) {
51249               for (var i = 0; i < layer.length; i++) {
51250                 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
51251                 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
51252
51253                 if (geometry.type === 'Polygon') {
51254                   geometry.type = 'MultiPolygon';
51255                   geometry.coordinates = [geometry.coordinates];
51256                 }
51257
51258                 var isClipped = false; // Clip to tile bounds
51259
51260                 if (geometry.type === 'MultiPolygon') {
51261                   var featureClip = bboxClip(feature, tile.extent.rectangle());
51262
51263                   if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
51264                     // feature = featureClip;
51265                     isClipped = true;
51266                   }
51267
51268                   if (!feature.geometry.coordinates.length) continue; // not actually on this tile
51269
51270                   if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
51271                 } // Generate some unique IDs and add some metadata
51272
51273
51274                 var featurehash = utilHashcode(fastJsonStableStringify(feature));
51275                 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
51276                 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
51277                 feature.__featurehash__ = featurehash;
51278                 feature.__propertyhash__ = propertyhash;
51279                 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
51280
51281                 if (isClipped && geometry.type === 'MultiPolygon') {
51282                   var merged = mergeCache[propertyhash];
51283
51284                   if (merged && merged.length) {
51285                     var other = merged[0];
51286                     var coords = union(feature.geometry.coordinates, other.geometry.coordinates);
51287
51288                     if (!coords || !coords.length) {
51289                       continue; // something failed in martinez union
51290                     }
51291
51292                     merged.push(feature);
51293
51294                     for (var j = 0; j < merged.length; j++) {
51295                       // all these features get...
51296                       merged[j].geometry.coordinates = coords; // same coords
51297
51298                       merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
51299                     }
51300                   } else {
51301                     mergeCache[propertyhash] = [feature];
51302                   }
51303                 }
51304               }
51305             }
51306           });
51307           return features;
51308         }
51309
51310         function loadTile(source, tile) {
51311           if (source.loaded[tile.id] || source.inflight[tile.id]) return;
51312           var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
51313           .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
51314             var subdomains = r.split(',');
51315             return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
51316           });
51317           var controller = new AbortController();
51318           source.inflight[tile.id] = controller;
51319           fetch(url, {
51320             signal: controller.signal
51321           }).then(function (response) {
51322             if (!response.ok) {
51323               throw new Error(response.status + ' ' + response.statusText);
51324             }
51325
51326             source.loaded[tile.id] = [];
51327             delete source.inflight[tile.id];
51328             return response.arrayBuffer();
51329           }).then(function (data) {
51330             if (!data) {
51331               throw new Error('No Data');
51332             }
51333
51334             var z = tile.xyz[2];
51335
51336             if (!source.canMerge[z]) {
51337               source.canMerge[z] = {}; // initialize mergeCache
51338             }
51339
51340             source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
51341             dispatch$8.call('loadedData');
51342           })["catch"](function () {
51343             source.loaded[tile.id] = [];
51344             delete source.inflight[tile.id];
51345           });
51346         }
51347
51348         var serviceVectorTile = {
51349           init: function init() {
51350             if (!_vtCache) {
51351               this.reset();
51352             }
51353
51354             this.event = utilRebind(this, dispatch$8, 'on');
51355           },
51356           reset: function reset() {
51357             for (var sourceID in _vtCache) {
51358               var source = _vtCache[sourceID];
51359
51360               if (source && source.inflight) {
51361                 Object.values(source.inflight).forEach(abortRequest$7);
51362               }
51363             }
51364
51365             _vtCache = {};
51366           },
51367           addSource: function addSource(sourceID, template) {
51368             _vtCache[sourceID] = {
51369               template: template,
51370               inflight: {},
51371               loaded: {},
51372               canMerge: {}
51373             };
51374             return _vtCache[sourceID];
51375           },
51376           data: function data(sourceID, projection) {
51377             var source = _vtCache[sourceID];
51378             if (!source) return [];
51379             var tiles = tiler$7.getTiles(projection);
51380             var seen = {};
51381             var results = [];
51382
51383             for (var i = 0; i < tiles.length; i++) {
51384               var features = source.loaded[tiles[i].id];
51385               if (!features || !features.length) continue;
51386
51387               for (var j = 0; j < features.length; j++) {
51388                 var feature = features[j];
51389                 var hash = feature.__featurehash__;
51390                 if (seen[hash]) continue;
51391                 seen[hash] = true; // return a shallow copy, because the hash may change
51392                 // later if this feature gets merged with another
51393
51394                 results.push(Object.assign({}, feature)); // shallow copy
51395               }
51396             }
51397
51398             return results;
51399           },
51400           loadTiles: function loadTiles(sourceID, template, projection) {
51401             var source = _vtCache[sourceID];
51402
51403             if (!source) {
51404               source = this.addSource(sourceID, template);
51405             }
51406
51407             var tiles = tiler$7.getTiles(projection); // abort inflight requests that are no longer needed
51408
51409             Object.keys(source.inflight).forEach(function (k) {
51410               var wanted = tiles.find(function (tile) {
51411                 return k === tile.id;
51412               });
51413
51414               if (!wanted) {
51415                 abortRequest$7(source.inflight[k]);
51416                 delete source.inflight[k];
51417               }
51418             });
51419             tiles.forEach(function (tile) {
51420               loadTile(source, tile);
51421             });
51422           },
51423           cache: function cache() {
51424             return _vtCache;
51425           }
51426         };
51427
51428         var apibase$3 = 'https://www.wikidata.org/w/api.php?';
51429         var _wikidataCache = {};
51430         var serviceWikidata = {
51431           init: function init() {},
51432           reset: function reset() {
51433             _wikidataCache = {};
51434           },
51435           // Search for Wikidata items matching the query
51436           itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
51437             if (!query) {
51438               if (callback) callback('No query', {});
51439               return;
51440             }
51441
51442             var lang = this.languagesToQuery()[0];
51443             var url = apibase$3 + utilQsString({
51444               action: 'wbsearchentities',
51445               format: 'json',
51446               formatversion: 2,
51447               search: query,
51448               type: 'item',
51449               // the language to search
51450               language: lang,
51451               // the language for the label and description in the result
51452               uselang: lang,
51453               limit: 10,
51454               origin: '*'
51455             });
51456             d3_json(url).then(function (result) {
51457               if (result && result.error) {
51458                 throw new Error(result.error);
51459               }
51460
51461               if (callback) callback(null, result.search || {});
51462             })["catch"](function (err) {
51463               if (callback) callback(err.message, {});
51464             });
51465           },
51466           // Given a Wikipedia language and article title,
51467           // return an array of corresponding Wikidata entities.
51468           itemsByTitle: function itemsByTitle(lang, title, callback) {
51469             if (!title) {
51470               if (callback) callback('No title', {});
51471               return;
51472             }
51473
51474             lang = lang || 'en';
51475             var url = apibase$3 + utilQsString({
51476               action: 'wbgetentities',
51477               format: 'json',
51478               formatversion: 2,
51479               sites: lang.replace(/-/g, '_') + 'wiki',
51480               titles: title,
51481               languages: 'en',
51482               // shrink response by filtering to one language
51483               origin: '*'
51484             });
51485             d3_json(url).then(function (result) {
51486               if (result && result.error) {
51487                 throw new Error(result.error);
51488               }
51489
51490               if (callback) callback(null, result.entities || {});
51491             })["catch"](function (err) {
51492               if (callback) callback(err.message, {});
51493             });
51494           },
51495           languagesToQuery: function languagesToQuery() {
51496             return _mainLocalizer.localeCodes().map(function (code) {
51497               return code.toLowerCase();
51498             }).filter(function (code) {
51499               // HACK: en-us isn't a wikidata language. We should really be filtering by
51500               // the languages known to be supported by wikidata.
51501               return code !== 'en-us';
51502             });
51503           },
51504           entityByQID: function entityByQID(qid, callback) {
51505             if (!qid) {
51506               callback('No qid', {});
51507               return;
51508             }
51509
51510             if (_wikidataCache[qid]) {
51511               if (callback) callback(null, _wikidataCache[qid]);
51512               return;
51513             }
51514
51515             var langs = this.languagesToQuery();
51516             var url = apibase$3 + utilQsString({
51517               action: 'wbgetentities',
51518               format: 'json',
51519               formatversion: 2,
51520               ids: qid,
51521               props: 'labels|descriptions|claims|sitelinks',
51522               sitefilter: langs.map(function (d) {
51523                 return d + 'wiki';
51524               }).join('|'),
51525               languages: langs.join('|'),
51526               languagefallback: 1,
51527               origin: '*'
51528             });
51529             d3_json(url).then(function (result) {
51530               if (result && result.error) {
51531                 throw new Error(result.error);
51532               }
51533
51534               if (callback) callback(null, result.entities[qid] || {});
51535             })["catch"](function (err) {
51536               if (callback) callback(err.message, {});
51537             });
51538           },
51539           // Pass `params` object of the form:
51540           // {
51541           //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
51542           // }
51543           //
51544           // Get an result object used to display tag documentation
51545           // {
51546           //   title:        'string',
51547           //   description:  'string',
51548           //   editURL:      'string',
51549           //   imageURL:     'string',
51550           //   wiki:         { title: 'string', text: 'string', url: 'string' }
51551           // }
51552           //
51553           getDocs: function getDocs(params, callback) {
51554             var langs = this.languagesToQuery();
51555             this.entityByQID(params.qid, function (err, entity) {
51556               if (err || !entity) {
51557                 callback(err || 'No entity');
51558                 return;
51559               }
51560
51561               var i;
51562               var description;
51563
51564               for (i in langs) {
51565                 var code = langs[i];
51566
51567                 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
51568                   description = entity.descriptions[code];
51569                   break;
51570                 }
51571               }
51572
51573               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
51574
51575               var result = {
51576                 title: entity.id,
51577                 description: description ? description.value : '',
51578                 descriptionLocaleCode: description ? description.language : '',
51579                 editURL: 'https://www.wikidata.org/wiki/' + entity.id
51580               }; // add image
51581
51582               if (entity.claims) {
51583                 var imageroot = 'https://commons.wikimedia.org/w/index.php';
51584                 var props = ['P154', 'P18']; // logo image, image
51585
51586                 var prop, image;
51587
51588                 for (i = 0; i < props.length; i++) {
51589                   prop = entity.claims[props[i]];
51590
51591                   if (prop && Object.keys(prop).length > 0) {
51592                     image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
51593
51594                     if (image) {
51595                       result.imageURL = imageroot + '?' + utilQsString({
51596                         title: 'Special:Redirect/file/' + image,
51597                         width: 400
51598                       });
51599                       break;
51600                     }
51601                   }
51602                 }
51603               }
51604
51605               if (entity.sitelinks) {
51606                 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
51607
51608                 for (i = 0; i < langs.length; i++) {
51609                   // check each, in order of preference
51610                   var w = langs[i] + 'wiki';
51611
51612                   if (entity.sitelinks[w]) {
51613                     var title = entity.sitelinks[w].title;
51614                     var tKey = 'inspector.wiki_reference';
51615
51616                     if (!englishLocale && langs[i] === 'en') {
51617                       // user's locale isn't English but
51618                       tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
51619                     }
51620
51621                     result.wiki = {
51622                       title: title,
51623                       text: tKey,
51624                       url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
51625                     };
51626                     break;
51627                   }
51628                 }
51629               }
51630
51631               callback(null, result);
51632             });
51633           }
51634         };
51635
51636         var endpoint = 'https://en.wikipedia.org/w/api.php?';
51637         var serviceWikipedia = {
51638           init: function init() {},
51639           reset: function reset() {},
51640           search: function search(lang, query, callback) {
51641             if (!query) {
51642               if (callback) callback('No Query', []);
51643               return;
51644             }
51645
51646             lang = lang || 'en';
51647             var url = endpoint.replace('en', lang) + utilQsString({
51648               action: 'query',
51649               list: 'search',
51650               srlimit: '10',
51651               srinfo: 'suggestion',
51652               format: 'json',
51653               origin: '*',
51654               srsearch: query
51655             });
51656             d3_json(url).then(function (result) {
51657               if (result && result.error) {
51658                 throw new Error(result.error);
51659               } else if (!result || !result.query || !result.query.search) {
51660                 throw new Error('No Results');
51661               }
51662
51663               if (callback) {
51664                 var titles = result.query.search.map(function (d) {
51665                   return d.title;
51666                 });
51667                 callback(null, titles);
51668               }
51669             })["catch"](function (err) {
51670               if (callback) callback(err, []);
51671             });
51672           },
51673           suggestions: function suggestions(lang, query, callback) {
51674             if (!query) {
51675               if (callback) callback('', []);
51676               return;
51677             }
51678
51679             lang = lang || 'en';
51680             var url = endpoint.replace('en', lang) + utilQsString({
51681               action: 'opensearch',
51682               namespace: 0,
51683               suggest: '',
51684               format: 'json',
51685               origin: '*',
51686               search: query
51687             });
51688             d3_json(url).then(function (result) {
51689               if (result && result.error) {
51690                 throw new Error(result.error);
51691               } else if (!result || result.length < 2) {
51692                 throw new Error('No Results');
51693               }
51694
51695               if (callback) callback(null, result[1] || []);
51696             })["catch"](function (err) {
51697               if (callback) callback(err.message, []);
51698             });
51699           },
51700           translations: function translations(lang, title, callback) {
51701             if (!title) {
51702               if (callback) callback('No Title');
51703               return;
51704             }
51705
51706             var url = endpoint.replace('en', lang) + utilQsString({
51707               action: 'query',
51708               prop: 'langlinks',
51709               format: 'json',
51710               origin: '*',
51711               lllimit: 500,
51712               titles: title
51713             });
51714             d3_json(url).then(function (result) {
51715               if (result && result.error) {
51716                 throw new Error(result.error);
51717               } else if (!result || !result.query || !result.query.pages) {
51718                 throw new Error('No Results');
51719               }
51720
51721               if (callback) {
51722                 var list = result.query.pages[Object.keys(result.query.pages)[0]];
51723                 var translations = {};
51724
51725                 if (list && list.langlinks) {
51726                   list.langlinks.forEach(function (d) {
51727                     translations[d.lang] = d['*'];
51728                   });
51729                 }
51730
51731                 callback(null, translations);
51732               }
51733             })["catch"](function (err) {
51734               if (callback) callback(err.message);
51735             });
51736           }
51737         };
51738
51739         var services = {
51740           geocoder: serviceNominatim,
51741           keepRight: serviceKeepRight,
51742           improveOSM: serviceImproveOSM,
51743           osmose: serviceOsmose,
51744           mapillary: serviceMapillary,
51745           openstreetcam: serviceOpenstreetcam,
51746           osm: serviceOsm,
51747           osmWikibase: serviceOsmWikibase,
51748           maprules: serviceMapRules,
51749           streetside: serviceStreetside,
51750           taginfo: serviceTaginfo,
51751           vectorTile: serviceVectorTile,
51752           wikidata: serviceWikidata,
51753           wikipedia: serviceWikipedia
51754         };
51755
51756         function svgIcon(name, svgklass, useklass) {
51757           return function drawIcon(selection) {
51758             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);
51759           };
51760         }
51761
51762         function uiNoteComments() {
51763           var _note;
51764
51765           function noteComments(selection) {
51766             if (_note.isNew()) return; // don't draw .comments-container
51767
51768             var comments = selection.selectAll('.comments-container').data([0]);
51769             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
51770             var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
51771             commentEnter.append('div').attr('class', function (d) {
51772               return 'comment-avatar user-' + d.uid;
51773             }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
51774             var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
51775             var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
51776             metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
51777               var selection = select(this);
51778               var osm = services.osm;
51779
51780               if (osm && d.user) {
51781                 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
51782               }
51783
51784               selection.html(function (d) {
51785                 return d.user || _t.html('note.anonymous');
51786               });
51787             });
51788             metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
51789               return _t('note.status.' + d.action, {
51790                 when: localeDateString(d.date)
51791               });
51792             });
51793             mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
51794               return d.html;
51795             }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
51796             comments.call(replaceAvatars);
51797           }
51798
51799           function replaceAvatars(selection) {
51800             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
51801             var osm = services.osm;
51802             if (showThirdPartyIcons !== 'true' || !osm) return;
51803             var uids = {}; // gather uids in the comment thread
51804
51805             _note.comments.forEach(function (d) {
51806               if (d.uid) uids[d.uid] = true;
51807             });
51808
51809             Object.keys(uids).forEach(function (uid) {
51810               osm.loadUser(uid, function (err, user) {
51811                 if (!user || !user.image_url) return;
51812                 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);
51813               });
51814             });
51815           }
51816
51817           function localeDateString(s) {
51818             if (!s) return null;
51819             var options = {
51820               day: 'numeric',
51821               month: 'short',
51822               year: 'numeric'
51823             };
51824             s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
51825
51826             var d = new Date(s);
51827             if (isNaN(d.getTime())) return null;
51828             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
51829           }
51830
51831           noteComments.note = function (val) {
51832             if (!arguments.length) return _note;
51833             _note = val;
51834             return noteComments;
51835           };
51836
51837           return noteComments;
51838         }
51839
51840         function uiNoteHeader() {
51841           var _note;
51842
51843           function noteHeader(selection) {
51844             var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
51845               return d.status + d.id;
51846             });
51847             header.exit().remove();
51848             var headerEnter = header.enter().append('div').attr('class', 'note-header');
51849             var iconEnter = headerEnter.append('div').attr('class', function (d) {
51850               return 'note-header-icon ' + d.status;
51851             }).classed('new', function (d) {
51852               return d.id < 0;
51853             });
51854             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
51855             iconEnter.each(function (d) {
51856               var statusIcon = '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
51857               iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
51858             });
51859             headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
51860               if (_note.isNew()) {
51861                 return _t('note.new');
51862               }
51863
51864               return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
51865             });
51866           }
51867
51868           noteHeader.note = function (val) {
51869             if (!arguments.length) return _note;
51870             _note = val;
51871             return noteHeader;
51872           };
51873
51874           return noteHeader;
51875         }
51876
51877         function uiNoteReport() {
51878           var _note;
51879
51880           function noteReport(selection) {
51881             var url;
51882
51883             if (services.osm && _note instanceof osmNote && !_note.isNew()) {
51884               url = services.osm.noteReportURL(_note);
51885             }
51886
51887             var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
51888
51889             link.exit().remove(); // enter
51890
51891             var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
51892               return d;
51893             }).call(svgIcon('#iD-icon-out-link', 'inline'));
51894             linkEnter.append('span').html(_t.html('note.report'));
51895           }
51896
51897           noteReport.note = function (val) {
51898             if (!arguments.length) return _note;
51899             _note = val;
51900             return noteReport;
51901           };
51902
51903           return noteReport;
51904         }
51905
51906         function uiViewOnOSM(context) {
51907           var _what; // an osmEntity or osmNote
51908
51909
51910           function viewOnOSM(selection) {
51911             var url;
51912
51913             if (_what instanceof osmEntity) {
51914               url = context.connection().entityURL(_what);
51915             } else if (_what instanceof osmNote) {
51916               url = context.connection().noteURL(_what);
51917             }
51918
51919             var data = !_what || _what.isNew() ? [] : [_what];
51920             var link = selection.selectAll('.view-on-osm').data(data, function (d) {
51921               return d.id;
51922             }); // exit
51923
51924             link.exit().remove(); // enter
51925
51926             var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
51927             linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
51928           }
51929
51930           viewOnOSM.what = function (_) {
51931             if (!arguments.length) return _what;
51932             _what = _;
51933             return viewOnOSM;
51934           };
51935
51936           return viewOnOSM;
51937         }
51938
51939         function uiNoteEditor(context) {
51940           var dispatch$1 = dispatch('change');
51941           var noteComments = uiNoteComments();
51942           var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
51943
51944           var _note;
51945
51946           var _newNote; // var _fieldsArr;
51947
51948
51949           function noteEditor(selection) {
51950             var header = selection.selectAll('.header').data([0]);
51951             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
51952             headerEnter.append('button').attr('class', 'close').on('click', function () {
51953               context.enter(modeBrowse(context));
51954             }).call(svgIcon('#iD-icon-close'));
51955             headerEnter.append('h3').html(_t.html('note.title'));
51956             var body = selection.selectAll('.body').data([0]);
51957             body = body.enter().append('div').attr('class', 'body').merge(body);
51958             var editor = body.selectAll('.note-editor').data([0]);
51959             editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
51960             var footer = selection.selectAll('.footer').data([0]);
51961             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
51962
51963             var osm = services.osm;
51964
51965             if (osm) {
51966               osm.on('change.note-save', function () {
51967                 selection.call(noteEditor);
51968               });
51969             }
51970           }
51971
51972           function noteSaveSection(selection) {
51973             var isSelected = _note && _note.id === context.selectedNoteID();
51974
51975             var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
51976               return d.status + d.id;
51977             }); // exit
51978
51979             noteSave.exit().remove(); // enter
51980
51981             var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
51982             // if (_note.isNew()) {
51983             //     var presets = presetManager;
51984             //     // NOTE: this key isn't a age and therefore there is no documentation (yet)
51985             //     _fieldsArr = [
51986             //         uiField(context, presets.field('category'), null, { show: true, revert: false }),
51987             //     ];
51988             //     _fieldsArr.forEach(function(field) {
51989             //         field
51990             //             .on('change', changeCategory);
51991             //     });
51992             //     noteSaveEnter
51993             //         .append('div')
51994             //         .attr('class', 'note-category')
51995             //         .call(formFields.fieldsArr(_fieldsArr));
51996             // }
51997             // function changeCategory() {
51998             //     // NOTE: perhaps there is a better way to get value
51999             //     var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
52000             //     // store the unsaved category with the note itself
52001             //     _note = _note.update({ newCategory: val });
52002             //     var osm = services.osm;
52003             //     if (osm) {
52004             //         osm.replaceNote(_note);  // update note cache
52005             //     }
52006             //     noteSave
52007             //         .call(noteSaveButtons);
52008             // }
52009
52010             noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
52011               return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
52012             });
52013             var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
52014               return d.newComment;
52015             }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
52016
52017             if (!commentTextarea.empty() && _newNote) {
52018               // autofocus the comment field for new notes
52019               commentTextarea.node().focus();
52020             } // update
52021
52022
52023             noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
52024
52025             function keydown(d3_event) {
52026               if (!(d3_event.keyCode === 13 && // ↩ Return
52027               d3_event.metaKey)) return;
52028               var osm = services.osm;
52029               if (!osm) return;
52030               var hasAuth = osm.authenticated();
52031               if (!hasAuth) return;
52032               if (!_note.newComment) return;
52033               d3_event.preventDefault();
52034               select(this).on('keydown.note-input', null); // focus on button and submit
52035
52036               window.setTimeout(function () {
52037                 if (_note.isNew()) {
52038                   noteSave.selectAll('.save-button').node().focus();
52039                   clickSave();
52040                 } else {
52041                   noteSave.selectAll('.comment-button').node().focus();
52042                   clickComment();
52043                 }
52044               }, 10);
52045             }
52046
52047             function changeInput() {
52048               var input = select(this);
52049               var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
52050
52051               _note = _note.update({
52052                 newComment: val
52053               });
52054               var osm = services.osm;
52055
52056               if (osm) {
52057                 osm.replaceNote(_note); // update note cache
52058               }
52059
52060               noteSave.call(noteSaveButtons);
52061             }
52062           }
52063
52064           function userDetails(selection) {
52065             var detailSection = selection.selectAll('.detail-section').data([0]);
52066             detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
52067             var osm = services.osm;
52068             if (!osm) return; // Add warning if user is not logged in
52069
52070             var hasAuth = osm.authenticated();
52071             var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
52072             authWarning.exit().transition().duration(200).style('opacity', 0).remove();
52073             var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
52074             authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
52075             authEnter.append('span').html(_t.html('note.login'));
52076             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) {
52077               d3_event.preventDefault();
52078               osm.authenticate();
52079             });
52080             authEnter.transition().duration(200).style('opacity', 1);
52081             var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
52082             prose.exit().remove();
52083             prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
52084             osm.userDetails(function (err, user) {
52085               if (err) return;
52086               var userLink = select(document.createElement('div'));
52087
52088               if (user.image_url) {
52089                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
52090               }
52091
52092               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
52093               prose.html(_t.html('note.upload_explanation_with_user', {
52094                 user: userLink.html()
52095               }));
52096             });
52097           }
52098
52099           function noteSaveButtons(selection) {
52100             var osm = services.osm;
52101             var hasAuth = osm && osm.authenticated();
52102
52103             var isSelected = _note && _note.id === context.selectedNoteID();
52104
52105             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
52106               return d.status + d.id;
52107             }); // exit
52108
52109             buttonSection.exit().remove(); // enter
52110
52111             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
52112
52113             if (_note.isNew()) {
52114               buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
52115               buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
52116             } else {
52117               buttonEnter.append('button').attr('class', 'button status-button action');
52118               buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
52119             } // update
52120
52121
52122             buttonSection = buttonSection.merge(buttonEnter);
52123             buttonSection.select('.cancel-button') // select and propagate data
52124             .on('click.cancel', clickCancel);
52125             buttonSection.select('.save-button') // select and propagate data
52126             .attr('disabled', isSaveDisabled).on('click.save', clickSave);
52127             buttonSection.select('.status-button') // select and propagate data
52128             .attr('disabled', hasAuth ? null : true).html(function (d) {
52129               var action = d.status === 'open' ? 'close' : 'open';
52130               var andComment = d.newComment ? '_comment' : '';
52131               return _t('note.' + action + andComment);
52132             }).on('click.status', clickStatus);
52133             buttonSection.select('.comment-button') // select and propagate data
52134             .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
52135
52136             function isSaveDisabled(d) {
52137               return hasAuth && d.status === 'open' && d.newComment ? null : true;
52138             }
52139           }
52140
52141           function clickCancel(d3_event, d) {
52142             this.blur(); // avoid keeping focus on the button - #4641
52143
52144             var osm = services.osm;
52145
52146             if (osm) {
52147               osm.removeNote(d);
52148             }
52149
52150             context.enter(modeBrowse(context));
52151             dispatch$1.call('change');
52152           }
52153
52154           function clickSave(d3_event, d) {
52155             this.blur(); // avoid keeping focus on the button - #4641
52156
52157             var osm = services.osm;
52158
52159             if (osm) {
52160               osm.postNoteCreate(d, function (err, note) {
52161                 dispatch$1.call('change', note);
52162               });
52163             }
52164           }
52165
52166           function clickStatus(d3_event, d) {
52167             this.blur(); // avoid keeping focus on the button - #4641
52168
52169             var osm = services.osm;
52170
52171             if (osm) {
52172               var setStatus = d.status === 'open' ? 'closed' : 'open';
52173               osm.postNoteUpdate(d, setStatus, function (err, note) {
52174                 dispatch$1.call('change', note);
52175               });
52176             }
52177           }
52178
52179           function clickComment(d3_event, d) {
52180             this.blur(); // avoid keeping focus on the button - #4641
52181
52182             var osm = services.osm;
52183
52184             if (osm) {
52185               osm.postNoteUpdate(d, d.status, function (err, note) {
52186                 dispatch$1.call('change', note);
52187               });
52188             }
52189           }
52190
52191           noteEditor.note = function (val) {
52192             if (!arguments.length) return _note;
52193             _note = val;
52194             return noteEditor;
52195           };
52196
52197           noteEditor.newNote = function (val) {
52198             if (!arguments.length) return _newNote;
52199             _newNote = val;
52200             return noteEditor;
52201           };
52202
52203           return utilRebind(noteEditor, dispatch$1, 'on');
52204         }
52205
52206         function modeSelectNote(context, selectedNoteID) {
52207           var mode = {
52208             id: 'select-note',
52209             button: 'browse'
52210           };
52211
52212           var _keybinding = utilKeybinding('select-note');
52213
52214           var _noteEditor = uiNoteEditor(context).on('change', function () {
52215             context.map().pan([0, 0]); // trigger a redraw
52216
52217             var note = checkSelectedID();
52218             if (!note) return;
52219             context.ui().sidebar.show(_noteEditor.note(note));
52220           });
52221
52222           var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
52223           var _newFeature = false;
52224
52225           function checkSelectedID() {
52226             if (!services.osm) return;
52227             var note = services.osm.getNote(selectedNoteID);
52228
52229             if (!note) {
52230               context.enter(modeBrowse(context));
52231             }
52232
52233             return note;
52234           } // class the note as selected, or return to browse mode if the note is gone
52235
52236
52237           function selectNote(d3_event, drawn) {
52238             if (!checkSelectedID()) return;
52239             var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
52240
52241             if (selection.empty()) {
52242               // Return to browse mode if selected DOM elements have
52243               // disappeared because the user moved them out of view..
52244               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
52245
52246               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
52247                 context.enter(modeBrowse(context));
52248               }
52249             } else {
52250               selection.classed('selected', true);
52251               context.selectedNoteID(selectedNoteID);
52252             }
52253           }
52254
52255           function esc() {
52256             if (context.container().select('.combobox').size()) return;
52257             context.enter(modeBrowse(context));
52258           }
52259
52260           mode.zoomToSelected = function () {
52261             if (!services.osm) return;
52262             var note = services.osm.getNote(selectedNoteID);
52263
52264             if (note) {
52265               context.map().centerZoomEase(note.loc, 20);
52266             }
52267           };
52268
52269           mode.newFeature = function (val) {
52270             if (!arguments.length) return _newFeature;
52271             _newFeature = val;
52272             return mode;
52273           };
52274
52275           mode.enter = function () {
52276             var note = checkSelectedID();
52277             if (!note) return;
52278
52279             _behaviors.forEach(context.install);
52280
52281             _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
52282
52283             select(document).call(_keybinding);
52284             selectNote();
52285             var sidebar = context.ui().sidebar;
52286             sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
52287
52288             sidebar.expand(sidebar.intersects(note.extent()));
52289             context.map().on('drawn.select', selectNote);
52290           };
52291
52292           mode.exit = function () {
52293             _behaviors.forEach(context.uninstall);
52294
52295             select(document).call(_keybinding.unbind);
52296             context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
52297             context.map().on('drawn.select', null);
52298             context.ui().sidebar.hide();
52299             context.selectedNoteID(null);
52300           };
52301
52302           return mode;
52303         }
52304
52305         function modeDragNote(context) {
52306           var mode = {
52307             id: 'drag-note',
52308             button: 'browse'
52309           };
52310           var edit = behaviorEdit(context);
52311
52312           var _nudgeInterval;
52313
52314           var _lastLoc;
52315
52316           var _note; // most current note.. dragged note may have stale datum.
52317
52318
52319           function startNudge(d3_event, nudge) {
52320             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
52321             _nudgeInterval = window.setInterval(function () {
52322               context.map().pan(nudge);
52323               doMove(d3_event, nudge);
52324             }, 50);
52325           }
52326
52327           function stopNudge() {
52328             if (_nudgeInterval) {
52329               window.clearInterval(_nudgeInterval);
52330               _nudgeInterval = null;
52331             }
52332           }
52333
52334           function origin(note) {
52335             return context.projection(note.loc);
52336           }
52337
52338           function start(d3_event, note) {
52339             _note = note;
52340             var osm = services.osm;
52341
52342             if (osm) {
52343               // Get latest note from cache.. The marker may have a stale datum bound to it
52344               // and dragging it around can sometimes delete the users note comment.
52345               _note = osm.getNote(_note.id);
52346             }
52347
52348             context.surface().selectAll('.note-' + _note.id).classed('active', true);
52349             context.perform(actionNoop());
52350             context.enter(mode);
52351             context.selectedNoteID(_note.id);
52352           }
52353
52354           function move(d3_event, entity, point) {
52355             d3_event.stopPropagation();
52356             _lastLoc = context.projection.invert(point);
52357             doMove(d3_event);
52358             var nudge = geoViewportEdge(point, context.map().dimensions());
52359
52360             if (nudge) {
52361               startNudge(d3_event, nudge);
52362             } else {
52363               stopNudge();
52364             }
52365           }
52366
52367           function doMove(d3_event, nudge) {
52368             nudge = nudge || [0, 0];
52369             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
52370             var currMouse = geoVecSubtract(currPoint, nudge);
52371             var loc = context.projection.invert(currMouse);
52372             _note = _note.move(loc);
52373             var osm = services.osm;
52374
52375             if (osm) {
52376               osm.replaceNote(_note); // update note cache
52377             }
52378
52379             context.replace(actionNoop()); // trigger redraw
52380           }
52381
52382           function end() {
52383             context.replace(actionNoop()); // trigger redraw
52384
52385             context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
52386           }
52387
52388           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);
52389
52390           mode.enter = function () {
52391             context.install(edit);
52392           };
52393
52394           mode.exit = function () {
52395             context.ui().sidebar.hover.cancel();
52396             context.uninstall(edit);
52397             context.surface().selectAll('.active').classed('active', false);
52398             stopNudge();
52399           };
52400
52401           mode.behavior = drag;
52402           return mode;
52403         }
52404
52405         function uiDataHeader() {
52406           var _datum;
52407
52408           function dataHeader(selection) {
52409             var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
52410               return d.__featurehash__;
52411             });
52412             header.exit().remove();
52413             var headerEnter = header.enter().append('div').attr('class', 'data-header');
52414             var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
52415             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
52416             headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
52417           }
52418
52419           dataHeader.datum = function (val) {
52420             if (!arguments.length) return _datum;
52421             _datum = val;
52422             return this;
52423           };
52424
52425           return dataHeader;
52426         }
52427
52428         // It is keyed on the `value` of the entry. Data should be an array of objects like:
52429         //   [{
52430         //       value:   'string value',  // required
52431         //       display: 'label html'     // optional
52432         //       title:   'hover text'     // optional
52433         //       terms:   ['search terms'] // optional
52434         //   }, ...]
52435
52436         var _comboHideTimerID;
52437
52438         function uiCombobox(context, klass) {
52439           var dispatch$1 = dispatch('accept', 'cancel');
52440           var container = context.container();
52441           var _suggestions = [];
52442           var _data = [];
52443           var _fetched = {};
52444           var _selected = null;
52445           var _canAutocomplete = true;
52446           var _caseSensitive = false;
52447           var _cancelFetch = false;
52448           var _minItems = 2;
52449           var _tDown = 0;
52450
52451           var _mouseEnterHandler, _mouseLeaveHandler;
52452
52453           var _fetcher = function _fetcher(val, cb) {
52454             cb(_data.filter(function (d) {
52455               var terms = d.terms || [];
52456               terms.push(d.value);
52457               return terms.some(function (term) {
52458                 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
52459               });
52460             }));
52461           };
52462
52463           var combobox = function combobox(input, attachTo) {
52464             if (!input || input.empty()) return;
52465             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 () {
52466               var parent = this.parentNode;
52467               var sibling = this.nextSibling;
52468               select(parent).selectAll('.combobox-caret').filter(function (d) {
52469                 return d === input.node();
52470               }).data([input.node()]).enter().insert('div', function () {
52471                 return sibling;
52472               }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
52473                 d3_event.preventDefault(); // don't steal focus from input
52474
52475                 input.node().focus(); // focus the input as if it was clicked
52476
52477                 mousedown(d3_event);
52478               }).on('mouseup.combo-caret', function (d3_event) {
52479                 d3_event.preventDefault(); // don't steal focus from input
52480
52481                 mouseup(d3_event);
52482               });
52483             });
52484
52485             function mousedown(d3_event) {
52486               if (d3_event.button !== 0) return; // left click only
52487
52488               _tDown = +new Date(); // clear selection
52489
52490               var start = input.property('selectionStart');
52491               var end = input.property('selectionEnd');
52492
52493               if (start !== end) {
52494                 var val = utilGetSetValue(input);
52495                 input.node().setSelectionRange(val.length, val.length);
52496                 return;
52497               }
52498
52499               input.on('mouseup.combo-input', mouseup);
52500             }
52501
52502             function mouseup(d3_event) {
52503               input.on('mouseup.combo-input', null);
52504               if (d3_event.button !== 0) return; // left click only
52505
52506               if (input.node() !== document.activeElement) return; // exit if this input is not focused
52507
52508               var start = input.property('selectionStart');
52509               var end = input.property('selectionEnd');
52510               if (start !== end) return; // exit if user is selecting
52511               // not showing or showing for a different field - try to show it.
52512
52513               var combo = container.selectAll('.combobox');
52514
52515               if (combo.empty() || combo.datum() !== input.node()) {
52516                 var tOrig = _tDown;
52517                 window.setTimeout(function () {
52518                   if (tOrig !== _tDown) return; // exit if user double clicked
52519
52520                   fetchComboData('', function () {
52521                     show();
52522                     render();
52523                   });
52524                 }, 250);
52525               } else {
52526                 hide();
52527               }
52528             }
52529
52530             function focus() {
52531               fetchComboData(''); // prefetch values (may warm taginfo cache)
52532             }
52533
52534             function blur() {
52535               _comboHideTimerID = window.setTimeout(hide, 75);
52536             }
52537
52538             function show() {
52539               hide(); // remove any existing
52540
52541               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) {
52542                 // prevent moving focus out of the input field
52543                 d3_event.preventDefault();
52544               });
52545               container.on('scroll.combo-scroll', render, true);
52546             }
52547
52548             function hide() {
52549               if (_comboHideTimerID) {
52550                 window.clearTimeout(_comboHideTimerID);
52551                 _comboHideTimerID = undefined;
52552               }
52553
52554               container.selectAll('.combobox').remove();
52555               container.on('scroll.combo-scroll', null);
52556             }
52557
52558             function keydown(d3_event) {
52559               var shown = !container.selectAll('.combobox').empty();
52560               var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
52561
52562               switch (d3_event.keyCode) {
52563                 case 8: // ⌫ Backspace
52564
52565                 case 46:
52566                   // ⌦ Delete
52567                   d3_event.stopPropagation();
52568                   _selected = null;
52569                   render();
52570                   input.on('input.combo-input', function () {
52571                     var start = input.property('selectionStart');
52572                     input.node().setSelectionRange(start, start);
52573                     input.on('input.combo-input', change);
52574                   });
52575                   break;
52576
52577                 case 9:
52578                   // ⇥ Tab
52579                   accept();
52580                   break;
52581
52582                 case 13:
52583                   // ↩ Return
52584                   d3_event.preventDefault();
52585                   d3_event.stopPropagation();
52586                   break;
52587
52588                 case 38:
52589                   // ↑ Up arrow
52590                   if (tagName === 'textarea' && !shown) return;
52591                   d3_event.preventDefault();
52592
52593                   if (tagName === 'input' && !shown) {
52594                     show();
52595                   }
52596
52597                   nav(-1);
52598                   break;
52599
52600                 case 40:
52601                   // ↓ Down arrow
52602                   if (tagName === 'textarea' && !shown) return;
52603                   d3_event.preventDefault();
52604
52605                   if (tagName === 'input' && !shown) {
52606                     show();
52607                   }
52608
52609                   nav(+1);
52610                   break;
52611               }
52612             }
52613
52614             function keyup(d3_event) {
52615               switch (d3_event.keyCode) {
52616                 case 27:
52617                   // ⎋ Escape
52618                   cancel();
52619                   break;
52620
52621                 case 13:
52622                   // ↩ Return
52623                   accept();
52624                   break;
52625               }
52626             } // Called whenever the input value is changed (e.g. on typing)
52627
52628
52629             function change() {
52630               fetchComboData(value(), function () {
52631                 _selected = null;
52632                 var val = input.property('value');
52633
52634                 if (_suggestions.length) {
52635                   if (input.property('selectionEnd') === val.length) {
52636                     _selected = tryAutocomplete();
52637                   }
52638
52639                   if (!_selected) {
52640                     _selected = val;
52641                   }
52642                 }
52643
52644                 if (val.length) {
52645                   var combo = container.selectAll('.combobox');
52646
52647                   if (combo.empty()) {
52648                     show();
52649                   }
52650                 } else {
52651                   hide();
52652                 }
52653
52654                 render();
52655               });
52656             } // Called when the user presses up/down arrows to navigate the list
52657
52658
52659             function nav(dir) {
52660               if (_suggestions.length) {
52661                 // try to determine previously selected index..
52662                 var index = -1;
52663
52664                 for (var i = 0; i < _suggestions.length; i++) {
52665                   if (_selected && _suggestions[i].value === _selected) {
52666                     index = i;
52667                     break;
52668                   }
52669                 } // pick new _selected
52670
52671
52672                 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
52673                 _selected = _suggestions[index].value;
52674                 input.property('value', _selected);
52675               }
52676
52677               render();
52678               ensureVisible();
52679             }
52680
52681             function ensureVisible() {
52682               var combo = container.selectAll('.combobox');
52683               if (combo.empty()) return;
52684               var containerRect = container.node().getBoundingClientRect();
52685               var comboRect = combo.node().getBoundingClientRect();
52686
52687               if (comboRect.bottom > containerRect.bottom) {
52688                 var node = attachTo ? attachTo.node() : input.node();
52689                 node.scrollIntoView({
52690                   behavior: 'instant',
52691                   block: 'center'
52692                 });
52693                 render();
52694               } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
52695
52696
52697               var selected = combo.selectAll('.combobox-option.selected').node();
52698
52699               if (selected) {
52700                 selected.scrollIntoView({
52701                   behavior: 'smooth',
52702                   block: 'nearest'
52703                 });
52704               }
52705             }
52706
52707             function value() {
52708               var value = input.property('value');
52709               var start = input.property('selectionStart');
52710               var end = input.property('selectionEnd');
52711
52712               if (start && end) {
52713                 value = value.substring(0, start);
52714               }
52715
52716               return value;
52717             }
52718
52719             function fetchComboData(v, cb) {
52720               _cancelFetch = false;
52721
52722               _fetcher.call(input, v, function (results) {
52723                 // already chose a value, don't overwrite or autocomplete it
52724                 if (_cancelFetch) return;
52725                 _suggestions = results;
52726                 results.forEach(function (d) {
52727                   _fetched[d.value] = d;
52728                 });
52729
52730                 if (cb) {
52731                   cb();
52732                 }
52733               });
52734             }
52735
52736             function tryAutocomplete() {
52737               if (!_canAutocomplete) return;
52738               var val = _caseSensitive ? value() : value().toLowerCase();
52739               if (!val) return; // Don't autocomplete if user is typing a number - #4935
52740
52741               if (!isNaN(parseFloat(val)) && isFinite(val)) return;
52742               var bestIndex = -1;
52743
52744               for (var i = 0; i < _suggestions.length; i++) {
52745                 var suggestion = _suggestions[i].value;
52746                 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
52747
52748                 if (compare === val) {
52749                   bestIndex = i;
52750                   break; // otherwise lock in the first result that starts with the search string..
52751                 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
52752                   bestIndex = i;
52753                 }
52754               }
52755
52756               if (bestIndex !== -1) {
52757                 var bestVal = _suggestions[bestIndex].value;
52758                 input.property('value', bestVal);
52759                 input.node().setSelectionRange(val.length, bestVal.length);
52760                 return bestVal;
52761               }
52762             }
52763
52764             function render() {
52765               if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
52766                 hide();
52767                 return;
52768               }
52769
52770               var shown = !container.selectAll('.combobox').empty();
52771               if (!shown) return;
52772               var combo = container.selectAll('.combobox');
52773               var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
52774                 return d.value;
52775               });
52776               options.exit().remove(); // enter/update
52777
52778               options.enter().append('a').attr('class', 'combobox-option').attr('title', function (d) {
52779                 return d.title;
52780               }).html(function (d) {
52781                 return d.display || d.value;
52782               }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
52783                 return d.value === _selected;
52784               }).on('click.combo-option', accept).order();
52785               var node = attachTo ? attachTo.node() : input.node();
52786               var containerRect = container.node().getBoundingClientRect();
52787               var rect = node.getBoundingClientRect();
52788               combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
52789             } // Dispatches an 'accept' event
52790             // Then hides the combobox.
52791
52792
52793             function accept(d3_event, d) {
52794               _cancelFetch = true;
52795               var thiz = input.node();
52796
52797               if (d) {
52798                 // user clicked on a suggestion
52799                 utilGetSetValue(input, d.value); // replace field contents
52800
52801                 utilTriggerEvent(input, 'change');
52802               } // clear (and keep) selection
52803
52804
52805               var val = utilGetSetValue(input);
52806               thiz.setSelectionRange(val.length, val.length);
52807               d = _fetched[val];
52808               dispatch$1.call('accept', thiz, d, val);
52809               hide();
52810             } // Dispatches an 'cancel' event
52811             // Then hides the combobox.
52812
52813
52814             function cancel() {
52815               _cancelFetch = true;
52816               var thiz = input.node(); // clear (and remove) selection, and replace field contents
52817
52818               var val = utilGetSetValue(input);
52819               var start = input.property('selectionStart');
52820               var end = input.property('selectionEnd');
52821               val = val.slice(0, start) + val.slice(end);
52822               utilGetSetValue(input, val);
52823               thiz.setSelectionRange(val.length, val.length);
52824               dispatch$1.call('cancel', thiz);
52825               hide();
52826             }
52827           };
52828
52829           combobox.canAutocomplete = function (val) {
52830             if (!arguments.length) return _canAutocomplete;
52831             _canAutocomplete = val;
52832             return combobox;
52833           };
52834
52835           combobox.caseSensitive = function (val) {
52836             if (!arguments.length) return _caseSensitive;
52837             _caseSensitive = val;
52838             return combobox;
52839           };
52840
52841           combobox.data = function (val) {
52842             if (!arguments.length) return _data;
52843             _data = val;
52844             return combobox;
52845           };
52846
52847           combobox.fetcher = function (val) {
52848             if (!arguments.length) return _fetcher;
52849             _fetcher = val;
52850             return combobox;
52851           };
52852
52853           combobox.minItems = function (val) {
52854             if (!arguments.length) return _minItems;
52855             _minItems = val;
52856             return combobox;
52857           };
52858
52859           combobox.itemsMouseEnter = function (val) {
52860             if (!arguments.length) return _mouseEnterHandler;
52861             _mouseEnterHandler = val;
52862             return combobox;
52863           };
52864
52865           combobox.itemsMouseLeave = function (val) {
52866             if (!arguments.length) return _mouseLeaveHandler;
52867             _mouseLeaveHandler = val;
52868             return combobox;
52869           };
52870
52871           return utilRebind(combobox, dispatch$1, 'on');
52872         }
52873
52874         uiCombobox.off = function (input, context) {
52875           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);
52876           context.container().on('scroll.combo-scroll', null);
52877         };
52878
52879         // hide class, which sets display=none, and a d3 transition for opacity.
52880         // this will cause blinking when called repeatedly, so check that the
52881         // value actually changes between calls.
52882
52883         function uiToggle(show, callback) {
52884           return function (selection) {
52885             selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
52886               select(this).classed('hide', !show).style('opacity', null);
52887               if (callback) callback.apply(this);
52888             });
52889           };
52890         }
52891
52892         function uiDisclosure(context, key, expandedDefault) {
52893           var dispatch$1 = dispatch('toggled');
52894
52895           var _expanded;
52896
52897           var _label = utilFunctor('');
52898
52899           var _updatePreference = true;
52900
52901           var _content = function _content() {};
52902
52903           var disclosure = function disclosure(selection) {
52904             if (_expanded === undefined || _expanded === null) {
52905               // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
52906               var preference = corePreferences('disclosure.' + key + '.expanded');
52907               _expanded = preference === null ? !!expandedDefault : preference === 'true';
52908             }
52909
52910             var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
52911
52912             var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
52913             hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
52914
52915             hideToggle = hideToggleEnter.merge(hideToggle);
52916             hideToggle.on('click', toggle).classed('expanded', _expanded);
52917             hideToggle.selectAll('.hide-toggle-text').html(_label());
52918             hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
52919             var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
52920
52921             wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
52922
52923             if (_expanded) {
52924               wrap.call(_content);
52925             }
52926
52927             function toggle(d3_event) {
52928               d3_event.preventDefault();
52929               _expanded = !_expanded;
52930
52931               if (_updatePreference) {
52932                 corePreferences('disclosure.' + key + '.expanded', _expanded);
52933               }
52934
52935               hideToggle.classed('expanded', _expanded);
52936               hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
52937               wrap.call(uiToggle(_expanded));
52938
52939               if (_expanded) {
52940                 wrap.call(_content);
52941               }
52942
52943               dispatch$1.call('toggled', this, _expanded);
52944             }
52945           };
52946
52947           disclosure.label = function (val) {
52948             if (!arguments.length) return _label;
52949             _label = utilFunctor(val);
52950             return disclosure;
52951           };
52952
52953           disclosure.expanded = function (val) {
52954             if (!arguments.length) return _expanded;
52955             _expanded = val;
52956             return disclosure;
52957           };
52958
52959           disclosure.updatePreference = function (val) {
52960             if (!arguments.length) return _updatePreference;
52961             _updatePreference = val;
52962             return disclosure;
52963           };
52964
52965           disclosure.content = function (val) {
52966             if (!arguments.length) return _content;
52967             _content = val;
52968             return disclosure;
52969           };
52970
52971           return utilRebind(disclosure, dispatch$1, 'on');
52972         }
52973
52974         // Can be labeled and collapsible.
52975
52976         function uiSection(id, context) {
52977           var _classes = utilFunctor('');
52978
52979           var _shouldDisplay;
52980
52981           var _content;
52982
52983           var _disclosure;
52984
52985           var _label;
52986
52987           var _expandedByDefault = utilFunctor(true);
52988
52989           var _disclosureContent;
52990
52991           var _disclosureExpanded;
52992
52993           var _containerSelection = select(null);
52994
52995           var section = {
52996             id: id
52997           };
52998
52999           section.classes = function (val) {
53000             if (!arguments.length) return _classes;
53001             _classes = utilFunctor(val);
53002             return section;
53003           };
53004
53005           section.label = function (val) {
53006             if (!arguments.length) return _label;
53007             _label = utilFunctor(val);
53008             return section;
53009           };
53010
53011           section.expandedByDefault = function (val) {
53012             if (!arguments.length) return _expandedByDefault;
53013             _expandedByDefault = utilFunctor(val);
53014             return section;
53015           };
53016
53017           section.shouldDisplay = function (val) {
53018             if (!arguments.length) return _shouldDisplay;
53019             _shouldDisplay = utilFunctor(val);
53020             return section;
53021           };
53022
53023           section.content = function (val) {
53024             if (!arguments.length) return _content;
53025             _content = val;
53026             return section;
53027           };
53028
53029           section.disclosureContent = function (val) {
53030             if (!arguments.length) return _disclosureContent;
53031             _disclosureContent = val;
53032             return section;
53033           };
53034
53035           section.disclosureExpanded = function (val) {
53036             if (!arguments.length) return _disclosureExpanded;
53037             _disclosureExpanded = val;
53038             return section;
53039           }; // may be called multiple times
53040
53041
53042           section.render = function (selection) {
53043             _containerSelection = selection.selectAll('.section-' + id).data([0]);
53044
53045             var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
53046
53047             _containerSelection = sectionEnter.merge(_containerSelection);
53048
53049             _containerSelection.call(renderContent);
53050           };
53051
53052           section.reRender = function () {
53053             _containerSelection.call(renderContent);
53054           };
53055
53056           section.selection = function () {
53057             return _containerSelection;
53058           };
53059
53060           section.disclosure = function () {
53061             return _disclosure;
53062           }; // may be called multiple times
53063
53064
53065           function renderContent(selection) {
53066             if (_shouldDisplay) {
53067               var shouldDisplay = _shouldDisplay();
53068
53069               selection.classed('hide', !shouldDisplay);
53070
53071               if (!shouldDisplay) {
53072                 selection.html('');
53073                 return;
53074               }
53075             }
53076
53077             if (_disclosureContent) {
53078               if (!_disclosure) {
53079                 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
53080                 /*.on('toggled', function(expanded) {
53081                     if (expanded) { selection.node().parentNode.scrollTop += 200; }
53082                 })*/
53083                 .content(_disclosureContent);
53084               }
53085
53086               if (_disclosureExpanded !== undefined) {
53087                 _disclosure.expanded(_disclosureExpanded);
53088
53089                 _disclosureExpanded = undefined;
53090               }
53091
53092               selection.call(_disclosure);
53093               return;
53094             }
53095
53096             if (_content) {
53097               selection.call(_content);
53098             }
53099           }
53100
53101           return section;
53102         }
53103
53104         // {
53105         //   key: 'string',     // required
53106         //   value: 'string'    // optional
53107         // }
53108         //   -or-
53109         // {
53110         //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
53111         // }
53112         //
53113
53114         function uiTagReference(what) {
53115           var wikibase = what.qid ? services.wikidata : services.osmWikibase;
53116           var tagReference = {};
53117
53118           var _button = select(null);
53119
53120           var _body = select(null);
53121
53122           var _loaded;
53123
53124           var _showing;
53125
53126           function load() {
53127             if (!wikibase) return;
53128
53129             _button.classed('tag-reference-loading', true);
53130
53131             wikibase.getDocs(what, gotDocs);
53132           }
53133
53134           function gotDocs(err, docs) {
53135             _body.html('');
53136
53137             if (!docs || !docs.title) {
53138               _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
53139
53140               done();
53141               return;
53142             }
53143
53144             if (docs.imageURL) {
53145               _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
53146                 done();
53147               }).on('error', function () {
53148                 select(this).remove();
53149                 done();
53150               });
53151             } else {
53152               done();
53153             }
53154
53155             _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'));
53156
53157             if (docs.wiki) {
53158               _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));
53159             } // Add link to info about "good changeset comments" - #2923
53160
53161
53162             if (what.key === 'comment') {
53163               _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'));
53164             }
53165           }
53166
53167           function done() {
53168             _loaded = true;
53169
53170             _button.classed('tag-reference-loading', false);
53171
53172             _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
53173
53174             _showing = true;
53175
53176             _button.selectAll('svg.icon use').each(function () {
53177               var iconUse = select(this);
53178
53179               if (iconUse.attr('href') === '#iD-icon-info') {
53180                 iconUse.attr('href', '#iD-icon-info-filled');
53181               }
53182             });
53183           }
53184
53185           function hide() {
53186             _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
53187               _body.classed('expanded', false);
53188             });
53189
53190             _showing = false;
53191
53192             _button.selectAll('svg.icon use').each(function () {
53193               var iconUse = select(this);
53194
53195               if (iconUse.attr('href') === '#iD-icon-info-filled') {
53196                 iconUse.attr('href', '#iD-icon-info');
53197               }
53198             });
53199           }
53200
53201           tagReference.button = function (selection, klass, iconName) {
53202             _button = selection.selectAll('.tag-reference-button').data([0]);
53203             _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
53204
53205             _button.on('click', function (d3_event) {
53206               d3_event.stopPropagation();
53207               d3_event.preventDefault();
53208               this.blur(); // avoid keeping focus on the button - #4641
53209
53210               if (_showing) {
53211                 hide();
53212               } else if (_loaded) {
53213                 done();
53214               } else {
53215                 load();
53216               }
53217             });
53218           };
53219
53220           tagReference.body = function (selection) {
53221             var itemID = what.qid || what.key + '-' + (what.value || '');
53222             _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
53223               return d;
53224             });
53225
53226             _body.exit().remove();
53227
53228             _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
53229
53230             if (_showing === false) {
53231               hide();
53232             }
53233           };
53234
53235           tagReference.showing = function (val) {
53236             if (!arguments.length) return _showing;
53237             _showing = val;
53238             return tagReference;
53239           };
53240
53241           return tagReference;
53242         }
53243
53244         function uiSectionRawTagEditor(id, context) {
53245           var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
53246             var count = Object.keys(_tags).filter(function (d) {
53247               return d;
53248             }).length;
53249             return _t('inspector.title_count', {
53250               title: _t.html('inspector.tags'),
53251               count: count
53252             });
53253           }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
53254           var taginfo = services.taginfo;
53255           var dispatch$1 = dispatch('change');
53256           var availableViews = [{
53257             id: 'list',
53258             icon: '#fas-th-list'
53259           }, {
53260             id: 'text',
53261             icon: '#fas-i-cursor'
53262           }];
53263
53264           var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
53265
53266
53267           var _readOnlyTags = []; // the keys in the order we want them to display
53268
53269           var _orderedKeys = [];
53270           var _showBlank = false;
53271           var _pendingChange = null;
53272
53273           var _state;
53274
53275           var _presets;
53276
53277           var _tags;
53278
53279           var _entityIDs;
53280
53281           var _didInteract = false;
53282
53283           function interacted() {
53284             _didInteract = true;
53285           }
53286
53287           function renderDisclosureContent(wrap) {
53288             // remove deleted keys
53289             _orderedKeys = _orderedKeys.filter(function (key) {
53290               return _tags[key] !== undefined;
53291             }); // When switching to a different entity or changing the state (hover/select)
53292             // reorder the keys alphabetically.
53293             // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
53294             // Otherwise leave their order alone - #5857, #5927
53295
53296             var all = Object.keys(_tags).sort();
53297             var missingKeys = utilArrayDifference(all, _orderedKeys);
53298
53299             for (var i in missingKeys) {
53300               _orderedKeys.push(missingKeys[i]);
53301             } // assemble row data
53302
53303
53304             var rowData = _orderedKeys.map(function (key, i) {
53305               return {
53306                 index: i,
53307                 key: key,
53308                 value: _tags[key]
53309               };
53310             }); // append blank row last, if necessary
53311
53312
53313             if (!rowData.length || _showBlank) {
53314               _showBlank = false;
53315               rowData.push({
53316                 index: rowData.length,
53317                 key: '',
53318                 value: ''
53319               });
53320             } // View Options
53321
53322
53323             var options = wrap.selectAll('.raw-tag-options').data([0]);
53324             options.exit().remove();
53325             var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
53326             var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
53327               return d.id;
53328             }).enter();
53329             optionEnter.append('button').attr('class', function (d) {
53330               return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
53331             }).attr('title', function (d) {
53332               return _t('icons.' + d.id);
53333             }).on('click', function (d3_event, d) {
53334               _tagView = d.id;
53335               corePreferences('raw-tag-editor-view', d.id);
53336               wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
53337                 return datum === d;
53338               });
53339               wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
53340               wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
53341             }).each(function (d) {
53342               select(this).call(svgIcon(d.icon));
53343             }); // View as Text
53344
53345             var textData = rowsToText(rowData);
53346             var textarea = wrap.selectAll('.tag-text').data([0]);
53347             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);
53348             textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
53349
53350             var list = wrap.selectAll('.tag-list').data([0]);
53351             list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
53352
53353             var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
53354             addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
53355             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
53356
53357             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
53358             // Tag list items
53359
53360             var items = list.selectAll('.tag-row').data(rowData, function (d) {
53361               return d.key;
53362             });
53363             items.exit().each(unbind).remove(); // Enter
53364
53365             var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
53366             var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
53367             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);
53368             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);
53369             innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
53370
53371             items = items.merge(itemsEnter).sort(function (a, b) {
53372               return a.index - b.index;
53373             });
53374             items.each(function (d) {
53375               var row = select(this);
53376               var key = row.select('input.key'); // propagate bound data
53377
53378               var value = row.select('input.value'); // propagate bound data
53379
53380               if (_entityIDs && taginfo && _state !== 'hover') {
53381                 bindTypeahead(key, value);
53382               }
53383
53384               var referenceOptions = {
53385                 key: d.key
53386               };
53387
53388               if (typeof d.value === 'string') {
53389                 referenceOptions.value = d.value;
53390               }
53391
53392               var reference = uiTagReference(referenceOptions);
53393
53394               if (_state === 'hover') {
53395                 reference.showing(false);
53396               }
53397
53398               row.select('.inner-wrap') // propagate bound data
53399               .call(reference.button);
53400               row.call(reference.body);
53401               row.select('button.remove'); // propagate bound data
53402             });
53403             items.selectAll('input.key').attr('title', function (d) {
53404               return d.key;
53405             }).call(utilGetSetValue, function (d) {
53406               return d.key;
53407             }).attr('readonly', function (d) {
53408               return isReadOnly(d) || typeof d.value !== 'string' || null;
53409             });
53410             items.selectAll('input.value').attr('title', function (d) {
53411               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
53412             }).classed('mixed', function (d) {
53413               return Array.isArray(d.value);
53414             }).attr('placeholder', function (d) {
53415               return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
53416             }).call(utilGetSetValue, function (d) {
53417               return typeof d.value === 'string' ? d.value : '';
53418             }).attr('readonly', function (d) {
53419               return isReadOnly(d) || null;
53420             });
53421             items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
53422           }
53423
53424           function isReadOnly(d) {
53425             for (var i = 0; i < _readOnlyTags.length; i++) {
53426               if (d.key.match(_readOnlyTags[i]) !== null) {
53427                 return true;
53428               }
53429             }
53430
53431             return false;
53432           }
53433
53434           function setTextareaHeight() {
53435             if (_tagView !== 'text') return;
53436             var selection = select(this);
53437             var matches = selection.node().value.match(/\n/g);
53438             var lineCount = 2 + Number(matches && matches.length);
53439             var lineHeight = 20;
53440             selection.style('height', lineCount * lineHeight + 'px');
53441           }
53442
53443           function stringify(s) {
53444             return JSON.stringify(s).slice(1, -1); // without leading/trailing "
53445           }
53446
53447           function unstringify(s) {
53448             var leading = '';
53449             var trailing = '';
53450
53451             if (s.length < 1 || s.charAt(0) !== '"') {
53452               leading = '"';
53453             }
53454
53455             if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
53456               trailing = '"';
53457             }
53458
53459             return JSON.parse(leading + s + trailing);
53460           }
53461
53462           function rowsToText(rows) {
53463             var str = rows.filter(function (row) {
53464               return row.key && row.key.trim() !== '';
53465             }).map(function (row) {
53466               var rawVal = row.value;
53467               if (typeof rawVal !== 'string') rawVal = '*';
53468               var val = rawVal ? stringify(rawVal) : '';
53469               return stringify(row.key) + '=' + val;
53470             }).join('\n');
53471
53472             if (_state !== 'hover' && str.length) {
53473               return str + '\n';
53474             }
53475
53476             return str;
53477           }
53478
53479           function textChanged() {
53480             var newText = this.value.trim();
53481             var newTags = {};
53482             newText.split('\n').forEach(function (row) {
53483               var m = row.match(/^\s*([^=]+)=(.*)$/);
53484
53485               if (m !== null) {
53486                 var k = context.cleanTagKey(unstringify(m[1].trim()));
53487                 var v = context.cleanTagValue(unstringify(m[2].trim()));
53488                 newTags[k] = v;
53489               }
53490             });
53491             var tagDiff = utilTagDiff(_tags, newTags);
53492             if (!tagDiff.length) return;
53493             _pendingChange = _pendingChange || {};
53494             tagDiff.forEach(function (change) {
53495               if (isReadOnly({
53496                 key: change.key
53497               })) return; // skip unchanged multiselection placeholders
53498
53499               if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
53500
53501               if (change.type === '-') {
53502                 _pendingChange[change.key] = undefined;
53503               } else if (change.type === '+') {
53504                 _pendingChange[change.key] = change.newVal || '';
53505               }
53506             });
53507
53508             if (Object.keys(_pendingChange).length === 0) {
53509               _pendingChange = null;
53510               return;
53511             }
53512
53513             scheduleChange();
53514           }
53515
53516           function pushMore(d3_event) {
53517             // if pressing Tab on the last value field with content, add a blank row
53518             if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
53519               addTag();
53520             }
53521           }
53522
53523           function bindTypeahead(key, value) {
53524             if (isReadOnly(key.datum())) return;
53525
53526             if (Array.isArray(value.datum().value)) {
53527               value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
53528                 var keyString = utilGetSetValue(key);
53529                 if (!_tags[keyString]) return;
53530
53531                 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
53532                   return {
53533                     value: tagValue,
53534                     title: tagValue
53535                   };
53536                 });
53537
53538                 callback(data);
53539               }));
53540               return;
53541             }
53542
53543             var geometry = context.graph().geometry(_entityIDs[0]);
53544             key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
53545               taginfo.keys({
53546                 debounce: true,
53547                 geometry: geometry,
53548                 query: value
53549               }, function (err, data) {
53550                 if (!err) {
53551                   var filtered = data.filter(function (d) {
53552                     return _tags[d.value] === undefined;
53553                   });
53554                   callback(sort(value, filtered));
53555                 }
53556               });
53557             }));
53558             value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
53559               taginfo.values({
53560                 debounce: true,
53561                 key: utilGetSetValue(key),
53562                 geometry: geometry,
53563                 query: value
53564               }, function (err, data) {
53565                 if (!err) callback(sort(value, data));
53566               });
53567             }));
53568
53569             function sort(value, data) {
53570               var sameletter = [];
53571               var other = [];
53572
53573               for (var i = 0; i < data.length; i++) {
53574                 if (data[i].value.substring(0, value.length) === value) {
53575                   sameletter.push(data[i]);
53576                 } else {
53577                   other.push(data[i]);
53578                 }
53579               }
53580
53581               return sameletter.concat(other);
53582             }
53583           }
53584
53585           function unbind() {
53586             var row = select(this);
53587             row.selectAll('input.key').call(uiCombobox.off, context);
53588             row.selectAll('input.value').call(uiCombobox.off, context);
53589           }
53590
53591           function keyChange(d3_event, d) {
53592             if (select(this).attr('readonly')) return;
53593             var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
53594
53595             if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
53596             var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
53597
53598             if (isReadOnly({
53599               key: kNew
53600             })) {
53601               this.value = kOld;
53602               return;
53603             }
53604
53605             if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
53606               // new key is already in use, switch focus to the existing row
53607               this.value = kOld; // reset the key
53608
53609               section.selection().selectAll('.tag-list input.value').each(function (d) {
53610                 if (d.key === kNew) {
53611                   // send focus to that other value combo instead
53612                   var input = select(this).node();
53613                   input.focus();
53614                   input.select();
53615                 }
53616               });
53617               return;
53618             }
53619
53620             var row = this.parentNode.parentNode;
53621             var inputVal = select(row).selectAll('input.value');
53622             var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
53623             _pendingChange = _pendingChange || {};
53624
53625             if (kOld) {
53626               _pendingChange[kOld] = undefined;
53627             }
53628
53629             _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
53630
53631             var existingKeyIndex = _orderedKeys.indexOf(kOld);
53632
53633             if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
53634             d.key = kNew; // update datum to avoid exit/enter on tag update
53635
53636             d.value = vNew;
53637             this.value = kNew;
53638             utilGetSetValue(inputVal, vNew);
53639             scheduleChange();
53640           }
53641
53642           function valueChange(d3_event, d) {
53643             if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
53644
53645             if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
53646
53647             if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
53648             _pendingChange = _pendingChange || {};
53649             _pendingChange[d.key] = context.cleanTagValue(this.value);
53650             scheduleChange();
53651           }
53652
53653           function removeTag(d3_event, d) {
53654             if (isReadOnly(d)) return;
53655
53656             if (d.key === '') {
53657               // removing the blank row
53658               _showBlank = false;
53659               section.reRender();
53660             } else {
53661               // remove the key from the ordered key index
53662               _orderedKeys = _orderedKeys.filter(function (key) {
53663                 return key !== d.key;
53664               });
53665               _pendingChange = _pendingChange || {};
53666               _pendingChange[d.key] = undefined;
53667               scheduleChange();
53668             }
53669           }
53670
53671           function addTag() {
53672             // Delay render in case this click is blurring an edited combo.
53673             // Without the setTimeout, the `content` render would wipe out the pending tag change.
53674             window.setTimeout(function () {
53675               _showBlank = true;
53676               section.reRender();
53677               section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
53678             }, 20);
53679           }
53680
53681           function scheduleChange() {
53682             // Cache IDs in case the editor is reloaded before the change event is called. - #6028
53683             var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
53684
53685             window.setTimeout(function () {
53686               if (!_pendingChange) return;
53687               dispatch$1.call('change', this, entityIDs, _pendingChange);
53688               _pendingChange = null;
53689             }, 10);
53690           }
53691
53692           section.state = function (val) {
53693             if (!arguments.length) return _state;
53694
53695             if (_state !== val) {
53696               _orderedKeys = [];
53697               _state = val;
53698             }
53699
53700             return section;
53701           };
53702
53703           section.presets = function (val) {
53704             if (!arguments.length) return _presets;
53705             _presets = val;
53706
53707             if (_presets && _presets.length && _presets[0].isFallback()) {
53708               section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
53709             } else if (!_didInteract) {
53710               section.disclosureExpanded(null);
53711             }
53712
53713             return section;
53714           };
53715
53716           section.tags = function (val) {
53717             if (!arguments.length) return _tags;
53718             _tags = val;
53719             return section;
53720           };
53721
53722           section.entityIDs = function (val) {
53723             if (!arguments.length) return _entityIDs;
53724
53725             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
53726               _entityIDs = val;
53727               _orderedKeys = [];
53728             }
53729
53730             return section;
53731           }; // pass an array of regular expressions to test against the tag key
53732
53733
53734           section.readOnlyTags = function (val) {
53735             if (!arguments.length) return _readOnlyTags;
53736             _readOnlyTags = val;
53737             return section;
53738           };
53739
53740           return utilRebind(section, dispatch$1, 'on');
53741         }
53742
53743         function uiDataEditor(context) {
53744           var dataHeader = uiDataHeader();
53745           var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
53746
53747           var _datum;
53748
53749           function dataEditor(selection) {
53750             var header = selection.selectAll('.header').data([0]);
53751             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
53752             headerEnter.append('button').attr('class', 'close').on('click', function () {
53753               context.enter(modeBrowse(context));
53754             }).call(svgIcon('#iD-icon-close'));
53755             headerEnter.append('h3').html(_t.html('map_data.title'));
53756             var body = selection.selectAll('.body').data([0]);
53757             body = body.enter().append('div').attr('class', 'body').merge(body);
53758             var editor = body.selectAll('.data-editor').data([0]); // enter/update
53759
53760             editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
53761             var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
53762
53763             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);
53764           }
53765
53766           dataEditor.datum = function (val) {
53767             if (!arguments.length) return _datum;
53768             _datum = val;
53769             return this;
53770           };
53771
53772           return dataEditor;
53773         }
53774
53775         function modeSelectData(context, selectedDatum) {
53776           var mode = {
53777             id: 'select-data',
53778             button: 'browse'
53779           };
53780           var keybinding = utilKeybinding('select-data');
53781           var dataEditor = uiDataEditor(context);
53782           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
53783
53784           function selectData(d3_event, drawn) {
53785             var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
53786
53787             if (selection.empty()) {
53788               // Return to browse mode if selected DOM elements have
53789               // disappeared because the user moved them out of view..
53790               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
53791
53792               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
53793                 context.enter(modeBrowse(context));
53794               }
53795             } else {
53796               selection.classed('selected', true);
53797             }
53798           }
53799
53800           function esc() {
53801             if (context.container().select('.combobox').size()) return;
53802             context.enter(modeBrowse(context));
53803           }
53804
53805           mode.zoomToSelected = function () {
53806             var extent = geoExtent(d3_geoBounds(selectedDatum));
53807             context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
53808           };
53809
53810           mode.enter = function () {
53811             behaviors.forEach(context.install);
53812             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
53813             select(document).call(keybinding);
53814             selectData();
53815             var sidebar = context.ui().sidebar;
53816             sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
53817
53818             var extent = geoExtent(d3_geoBounds(selectedDatum));
53819             sidebar.expand(sidebar.intersects(extent));
53820             context.map().on('drawn.select-data', selectData);
53821           };
53822
53823           mode.exit = function () {
53824             behaviors.forEach(context.uninstall);
53825             select(document).call(keybinding.unbind);
53826             context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
53827             context.map().on('drawn.select-data', null);
53828             context.ui().sidebar.hide();
53829           };
53830
53831           return mode;
53832         }
53833
53834         function uiImproveOsmComments() {
53835           var _qaItem;
53836
53837           function issueComments(selection) {
53838             // make the div immediately so it appears above the buttons
53839             var comments = selection.selectAll('.comments-container').data([0]);
53840             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
53841
53842             services.improveOSM.getComments(_qaItem).then(function (d) {
53843               if (!d.comments) return; // nothing to do here
53844
53845               var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
53846               commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
53847               var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
53848               var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
53849               metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
53850                 var osm = services.osm;
53851                 var selection = select(this);
53852
53853                 if (osm && d.username) {
53854                   selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
53855                 }
53856
53857                 selection.html(function (d) {
53858                   return d.username;
53859                 });
53860               });
53861               metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
53862                 return _t.html('note.status.commented', {
53863                   when: localeDateString(d.timestamp)
53864                 });
53865               });
53866               mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
53867                 return d.text;
53868               });
53869             })["catch"](function (err) {
53870               console.log(err); // eslint-disable-line no-console
53871             });
53872           }
53873
53874           function localeDateString(s) {
53875             if (!s) return null;
53876             var options = {
53877               day: 'numeric',
53878               month: 'short',
53879               year: 'numeric'
53880             };
53881             var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
53882
53883             if (isNaN(d.getTime())) return null;
53884             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
53885           }
53886
53887           issueComments.issue = function (val) {
53888             if (!arguments.length) return _qaItem;
53889             _qaItem = val;
53890             return issueComments;
53891           };
53892
53893           return issueComments;
53894         }
53895
53896         function uiImproveOsmDetails(context) {
53897           var _qaItem;
53898
53899           function issueDetail(d) {
53900             if (d.desc) return d.desc;
53901             var issueKey = d.issueKey;
53902             d.replacements = d.replacements || {};
53903             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
53904
53905             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
53906           }
53907
53908           function improveOsmDetails(selection) {
53909             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
53910               return "".concat(d.id, "-").concat(d.status || 0);
53911             });
53912             details.exit().remove();
53913             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
53914
53915             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
53916             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
53917             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
53918
53919             var relatedEntities = [];
53920             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
53921               var link = select(this);
53922               var isObjectLink = link.classed('error_object_link');
53923               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
53924               var entity = context.hasEntity(entityID);
53925               relatedEntities.push(entityID); // Add click handler
53926
53927               link.on('mouseenter', function () {
53928                 utilHighlightEntities([entityID], true, context);
53929               }).on('mouseleave', function () {
53930                 utilHighlightEntities([entityID], false, context);
53931               }).on('click', function (d3_event) {
53932                 d3_event.preventDefault();
53933                 utilHighlightEntities([entityID], false, context);
53934                 var osmlayer = context.layers().layer('osm');
53935
53936                 if (!osmlayer.enabled()) {
53937                   osmlayer.enabled(true);
53938                 }
53939
53940                 context.map().centerZoom(_qaItem.loc, 20);
53941
53942                 if (entity) {
53943                   context.enter(modeSelect(context, [entityID]));
53944                 } else {
53945                   context.loadEntity(entityID, function () {
53946                     context.enter(modeSelect(context, [entityID]));
53947                   });
53948                 }
53949               }); // Replace with friendly name if possible
53950               // (The entity may not yet be loaded into the graph)
53951
53952               if (entity) {
53953                 var name = utilDisplayName(entity); // try to use common name
53954
53955                 if (!name && !isObjectLink) {
53956                   var preset = _mainPresetIndex.match(entity, context.graph());
53957                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
53958                 }
53959
53960                 if (name) {
53961                   this.innerText = name;
53962                 }
53963               }
53964             }); // Don't hide entities related to this error - #5880
53965
53966             context.features().forceVisible(relatedEntities);
53967             context.map().pan([0, 0]); // trigger a redraw
53968           }
53969
53970           improveOsmDetails.issue = function (val) {
53971             if (!arguments.length) return _qaItem;
53972             _qaItem = val;
53973             return improveOsmDetails;
53974           };
53975
53976           return improveOsmDetails;
53977         }
53978
53979         function uiImproveOsmHeader() {
53980           var _qaItem;
53981
53982           function issueTitle(d) {
53983             var issueKey = d.issueKey;
53984             d.replacements = d.replacements || {};
53985             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
53986
53987             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
53988           }
53989
53990           function improveOsmHeader(selection) {
53991             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
53992               return "".concat(d.id, "-").concat(d.status || 0);
53993             });
53994             header.exit().remove();
53995             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
53996             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
53997               return d.id < 0;
53998             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
53999               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
54000             });
54001             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');
54002             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
54003               var picon = d.icon;
54004
54005               if (!picon) {
54006                 return '';
54007               } else {
54008                 var isMaki = /^maki-/.test(picon);
54009                 return "#".concat(picon).concat(isMaki ? '-11' : '');
54010               }
54011             });
54012             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
54013           }
54014
54015           improveOsmHeader.issue = function (val) {
54016             if (!arguments.length) return _qaItem;
54017             _qaItem = val;
54018             return improveOsmHeader;
54019           };
54020
54021           return improveOsmHeader;
54022         }
54023
54024         function uiImproveOsmEditor(context) {
54025           var dispatch$1 = dispatch('change');
54026           var qaDetails = uiImproveOsmDetails(context);
54027           var qaComments = uiImproveOsmComments();
54028           var qaHeader = uiImproveOsmHeader();
54029
54030           var _qaItem;
54031
54032           function improveOsmEditor(selection) {
54033             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
54034             headerEnter.append('button').attr('class', 'close').on('click', function () {
54035               return context.enter(modeBrowse(context));
54036             }).call(svgIcon('#iD-icon-close'));
54037             headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
54038             var body = selection.selectAll('.body').data([0]);
54039             body = body.enter().append('div').attr('class', 'body').merge(body);
54040             var editor = body.selectAll('.qa-editor').data([0]);
54041             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);
54042           }
54043
54044           function improveOsmSaveSection(selection) {
54045             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54046
54047             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
54048             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
54049               return "".concat(d.id, "-").concat(d.status || 0);
54050             }); // exit
54051
54052             saveSection.exit().remove(); // enter
54053
54054             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
54055             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
54056             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
54057               return d.newComment;
54058             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
54059
54060             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
54061
54062             function changeInput() {
54063               var input = select(this);
54064               var val = input.property('value').trim();
54065
54066               if (val === '') {
54067                 val = undefined;
54068               } // store the unsaved comment with the issue itself
54069
54070
54071               _qaItem = _qaItem.update({
54072                 newComment: val
54073               });
54074               var qaService = services.improveOSM;
54075
54076               if (qaService) {
54077                 qaService.replaceItem(_qaItem);
54078               }
54079
54080               saveSection.call(qaSaveButtons);
54081             }
54082           }
54083
54084           function qaSaveButtons(selection) {
54085             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54086
54087             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
54088               return d.status + d.id;
54089             }); // exit
54090
54091             buttonSection.exit().remove(); // enter
54092
54093             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
54094             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
54095             buttonEnter.append('button').attr('class', 'button close-button action');
54096             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
54097
54098             buttonSection = buttonSection.merge(buttonEnter);
54099             buttonSection.select('.comment-button').attr('disabled', function (d) {
54100               return d.newComment ? null : true;
54101             }).on('click.comment', function (d3_event, d) {
54102               this.blur(); // avoid keeping focus on the button - #4641
54103
54104               var qaService = services.improveOSM;
54105
54106               if (qaService) {
54107                 qaService.postUpdate(d, function (err, item) {
54108                   return dispatch$1.call('change', item);
54109                 });
54110               }
54111             });
54112             buttonSection.select('.close-button').html(function (d) {
54113               var andComment = d.newComment ? '_comment' : '';
54114               return _t.html("QA.keepRight.close".concat(andComment));
54115             }).on('click.close', function (d3_event, d) {
54116               this.blur(); // avoid keeping focus on the button - #4641
54117
54118               var qaService = services.improveOSM;
54119
54120               if (qaService) {
54121                 d.newStatus = 'SOLVED';
54122                 qaService.postUpdate(d, function (err, item) {
54123                   return dispatch$1.call('change', item);
54124                 });
54125               }
54126             });
54127             buttonSection.select('.ignore-button').html(function (d) {
54128               var andComment = d.newComment ? '_comment' : '';
54129               return _t.html("QA.keepRight.ignore".concat(andComment));
54130             }).on('click.ignore', function (d3_event, d) {
54131               this.blur(); // avoid keeping focus on the button - #4641
54132
54133               var qaService = services.improveOSM;
54134
54135               if (qaService) {
54136                 d.newStatus = 'INVALID';
54137                 qaService.postUpdate(d, function (err, item) {
54138                   return dispatch$1.call('change', item);
54139                 });
54140               }
54141             });
54142           } // NOTE: Don't change method name until UI v3 is merged
54143
54144
54145           improveOsmEditor.error = function (val) {
54146             if (!arguments.length) return _qaItem;
54147             _qaItem = val;
54148             return improveOsmEditor;
54149           };
54150
54151           return utilRebind(improveOsmEditor, dispatch$1, 'on');
54152         }
54153
54154         function uiKeepRightDetails(context) {
54155           var _qaItem;
54156
54157           function issueDetail(d) {
54158             var itemType = d.itemType,
54159                 parentIssueType = d.parentIssueType;
54160             var unknown = _t.html('inspector.unknown');
54161             var replacements = d.replacements || {};
54162             replacements["default"] = unknown; // special key `default` works as a fallback string
54163
54164             var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
54165
54166             if (detail === unknown) {
54167               detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
54168             }
54169
54170             return detail;
54171           }
54172
54173           function keepRightDetails(selection) {
54174             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
54175               return "".concat(d.id, "-").concat(d.status || 0);
54176             });
54177             details.exit().remove();
54178             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
54179
54180             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54181             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
54182             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
54183
54184             var relatedEntities = [];
54185             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
54186               var link = select(this);
54187               var isObjectLink = link.classed('error_object_link');
54188               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
54189               var entity = context.hasEntity(entityID);
54190               relatedEntities.push(entityID); // Add click handler
54191
54192               link.on('mouseenter', function () {
54193                 utilHighlightEntities([entityID], true, context);
54194               }).on('mouseleave', function () {
54195                 utilHighlightEntities([entityID], false, context);
54196               }).on('click', function (d3_event) {
54197                 d3_event.preventDefault();
54198                 utilHighlightEntities([entityID], false, context);
54199                 var osmlayer = context.layers().layer('osm');
54200
54201                 if (!osmlayer.enabled()) {
54202                   osmlayer.enabled(true);
54203                 }
54204
54205                 context.map().centerZoomEase(_qaItem.loc, 20);
54206
54207                 if (entity) {
54208                   context.enter(modeSelect(context, [entityID]));
54209                 } else {
54210                   context.loadEntity(entityID, function () {
54211                     context.enter(modeSelect(context, [entityID]));
54212                   });
54213                 }
54214               }); // Replace with friendly name if possible
54215               // (The entity may not yet be loaded into the graph)
54216
54217               if (entity) {
54218                 var name = utilDisplayName(entity); // try to use common name
54219
54220                 if (!name && !isObjectLink) {
54221                   var preset = _mainPresetIndex.match(entity, context.graph());
54222                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
54223                 }
54224
54225                 if (name) {
54226                   this.innerText = name;
54227                 }
54228               }
54229             }); // Don't hide entities related to this issue - #5880
54230
54231             context.features().forceVisible(relatedEntities);
54232             context.map().pan([0, 0]); // trigger a redraw
54233           }
54234
54235           keepRightDetails.issue = function (val) {
54236             if (!arguments.length) return _qaItem;
54237             _qaItem = val;
54238             return keepRightDetails;
54239           };
54240
54241           return keepRightDetails;
54242         }
54243
54244         function uiKeepRightHeader() {
54245           var _qaItem;
54246
54247           function issueTitle(d) {
54248             var itemType = d.itemType,
54249                 parentIssueType = d.parentIssueType;
54250             var unknown = _t.html('inspector.unknown');
54251             var replacements = d.replacements || {};
54252             replacements["default"] = unknown; // special key `default` works as a fallback string
54253
54254             var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
54255
54256             if (title === unknown) {
54257               title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
54258             }
54259
54260             return title;
54261           }
54262
54263           function keepRightHeader(selection) {
54264             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
54265               return "".concat(d.id, "-").concat(d.status || 0);
54266             });
54267             header.exit().remove();
54268             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
54269             var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
54270               return d.id < 0;
54271             });
54272             iconEnter.append('div').attr('class', function (d) {
54273               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
54274             }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
54275             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
54276           }
54277
54278           keepRightHeader.issue = function (val) {
54279             if (!arguments.length) return _qaItem;
54280             _qaItem = val;
54281             return keepRightHeader;
54282           };
54283
54284           return keepRightHeader;
54285         }
54286
54287         function uiViewOnKeepRight() {
54288           var _qaItem;
54289
54290           function viewOnKeepRight(selection) {
54291             var url;
54292
54293             if (services.keepRight && _qaItem instanceof QAItem) {
54294               url = services.keepRight.issueURL(_qaItem);
54295             }
54296
54297             var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
54298
54299             link.exit().remove(); // enter
54300
54301             var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
54302             .attr('href', function (d) {
54303               return d;
54304             }).call(svgIcon('#iD-icon-out-link', 'inline'));
54305             linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
54306           }
54307
54308           viewOnKeepRight.what = function (val) {
54309             if (!arguments.length) return _qaItem;
54310             _qaItem = val;
54311             return viewOnKeepRight;
54312           };
54313
54314           return viewOnKeepRight;
54315         }
54316
54317         function uiKeepRightEditor(context) {
54318           var dispatch$1 = dispatch('change');
54319           var qaDetails = uiKeepRightDetails(context);
54320           var qaHeader = uiKeepRightHeader();
54321
54322           var _qaItem;
54323
54324           function keepRightEditor(selection) {
54325             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
54326             headerEnter.append('button').attr('class', 'close').on('click', function () {
54327               return context.enter(modeBrowse(context));
54328             }).call(svgIcon('#iD-icon-close'));
54329             headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
54330             var body = selection.selectAll('.body').data([0]);
54331             body = body.enter().append('div').attr('class', 'body').merge(body);
54332             var editor = body.selectAll('.qa-editor').data([0]);
54333             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
54334             var footer = selection.selectAll('.footer').data([0]);
54335             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
54336           }
54337
54338           function keepRightSaveSection(selection) {
54339             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54340
54341             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
54342             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
54343               return "".concat(d.id, "-").concat(d.status || 0);
54344             }); // exit
54345
54346             saveSection.exit().remove(); // enter
54347
54348             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
54349             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
54350             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
54351               return d.newComment || d.comment;
54352             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
54353
54354             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
54355
54356             function changeInput() {
54357               var input = select(this);
54358               var val = input.property('value').trim();
54359
54360               if (val === _qaItem.comment) {
54361                 val = undefined;
54362               } // store the unsaved comment with the issue itself
54363
54364
54365               _qaItem = _qaItem.update({
54366                 newComment: val
54367               });
54368               var qaService = services.keepRight;
54369
54370               if (qaService) {
54371                 qaService.replaceItem(_qaItem); // update keepright cache
54372               }
54373
54374               saveSection.call(qaSaveButtons);
54375             }
54376           }
54377
54378           function qaSaveButtons(selection) {
54379             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54380
54381             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
54382               return d.status + d.id;
54383             }); // exit
54384
54385             buttonSection.exit().remove(); // enter
54386
54387             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
54388             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
54389             buttonEnter.append('button').attr('class', 'button close-button action');
54390             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
54391
54392             buttonSection = buttonSection.merge(buttonEnter);
54393             buttonSection.select('.comment-button') // select and propagate data
54394             .attr('disabled', function (d) {
54395               return d.newComment ? null : true;
54396             }).on('click.comment', function (d3_event, d) {
54397               this.blur(); // avoid keeping focus on the button - #4641
54398
54399               var qaService = services.keepRight;
54400
54401               if (qaService) {
54402                 qaService.postUpdate(d, function (err, item) {
54403                   return dispatch$1.call('change', item);
54404                 });
54405               }
54406             });
54407             buttonSection.select('.close-button') // select and propagate data
54408             .html(function (d) {
54409               var andComment = d.newComment ? '_comment' : '';
54410               return _t.html("QA.keepRight.close".concat(andComment));
54411             }).on('click.close', function (d3_event, d) {
54412               this.blur(); // avoid keeping focus on the button - #4641
54413
54414               var qaService = services.keepRight;
54415
54416               if (qaService) {
54417                 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
54418
54419                 qaService.postUpdate(d, function (err, item) {
54420                   return dispatch$1.call('change', item);
54421                 });
54422               }
54423             });
54424             buttonSection.select('.ignore-button') // select and propagate data
54425             .html(function (d) {
54426               var andComment = d.newComment ? '_comment' : '';
54427               return _t.html("QA.keepRight.ignore".concat(andComment));
54428             }).on('click.ignore', function (d3_event, d) {
54429               this.blur(); // avoid keeping focus on the button - #4641
54430
54431               var qaService = services.keepRight;
54432
54433               if (qaService) {
54434                 d.newStatus = 'ignore'; // ignore permanently (false positive)
54435
54436                 qaService.postUpdate(d, function (err, item) {
54437                   return dispatch$1.call('change', item);
54438                 });
54439               }
54440             });
54441           } // NOTE: Don't change method name until UI v3 is merged
54442
54443
54444           keepRightEditor.error = function (val) {
54445             if (!arguments.length) return _qaItem;
54446             _qaItem = val;
54447             return keepRightEditor;
54448           };
54449
54450           return utilRebind(keepRightEditor, dispatch$1, 'on');
54451         }
54452
54453         function uiOsmoseDetails(context) {
54454           var _qaItem;
54455
54456           function issueString(d, type) {
54457             if (!d) return ''; // Issue strings are cached from Osmose API
54458
54459             var s = services.osmose.getStrings(d.itemType);
54460             return type in s ? s[type] : '';
54461           }
54462
54463           function osmoseDetails(selection) {
54464             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
54465               return "".concat(d.id, "-").concat(d.status || 0);
54466             });
54467             details.exit().remove();
54468             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
54469
54470             if (issueString(_qaItem, 'detail')) {
54471               var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54472               div.append('h4').html(_t.html('QA.keepRight.detail_description'));
54473               div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
54474                 return issueString(d, 'detail');
54475               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
54476             } // Elements (populated later as data is requested)
54477
54478
54479             var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54480             var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
54481
54482             if (issueString(_qaItem, 'fix')) {
54483               var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54484
54485               _div.append('h4').html(_t.html('QA.osmose.fix_title'));
54486
54487               _div.append('p').html(function (d) {
54488                 return issueString(d, 'fix');
54489               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
54490             } // Common Pitfalls (mustn't exist for every issue type)
54491
54492
54493             if (issueString(_qaItem, 'trap')) {
54494               var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54495
54496               _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
54497
54498               _div2.append('p').html(function (d) {
54499                 return issueString(d, 'trap');
54500               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
54501             } // Save current item to check if UI changed by time request resolves
54502
54503
54504             var thisItem = _qaItem;
54505             services.osmose.loadIssueDetail(_qaItem).then(function (d) {
54506               // No details to add if there are no associated issue elements
54507               if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
54508
54509               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
54510
54511               if (d.detail) {
54512                 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
54513                 detailsDiv.append('p').html(function (d) {
54514                   return d.detail;
54515                 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
54516               } // Create list of linked issue elements
54517
54518
54519               elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
54520               elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
54521                 return d;
54522               }).each(function () {
54523                 var link = select(this);
54524                 var entityID = this.textContent;
54525                 var entity = context.hasEntity(entityID); // Add click handler
54526
54527                 link.on('mouseenter', function () {
54528                   utilHighlightEntities([entityID], true, context);
54529                 }).on('mouseleave', function () {
54530                   utilHighlightEntities([entityID], false, context);
54531                 }).on('click', function (d3_event) {
54532                   d3_event.preventDefault();
54533                   utilHighlightEntities([entityID], false, context);
54534                   var osmlayer = context.layers().layer('osm');
54535
54536                   if (!osmlayer.enabled()) {
54537                     osmlayer.enabled(true);
54538                   }
54539
54540                   context.map().centerZoom(d.loc, 20);
54541
54542                   if (entity) {
54543                     context.enter(modeSelect(context, [entityID]));
54544                   } else {
54545                     context.loadEntity(entityID, function () {
54546                       context.enter(modeSelect(context, [entityID]));
54547                     });
54548                   }
54549                 }); // Replace with friendly name if possible
54550                 // (The entity may not yet be loaded into the graph)
54551
54552                 if (entity) {
54553                   var name = utilDisplayName(entity); // try to use common name
54554
54555                   if (!name) {
54556                     var preset = _mainPresetIndex.match(entity, context.graph());
54557                     name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
54558                   }
54559
54560                   if (name) {
54561                     this.innerText = name;
54562                   }
54563                 }
54564               }); // Don't hide entities related to this issue - #5880
54565
54566               context.features().forceVisible(d.elems);
54567               context.map().pan([0, 0]); // trigger a redraw
54568             })["catch"](function (err) {
54569               console.log(err); // eslint-disable-line no-console
54570             });
54571           }
54572
54573           osmoseDetails.issue = function (val) {
54574             if (!arguments.length) return _qaItem;
54575             _qaItem = val;
54576             return osmoseDetails;
54577           };
54578
54579           return osmoseDetails;
54580         }
54581
54582         function uiOsmoseHeader() {
54583           var _qaItem;
54584
54585           function issueTitle(d) {
54586             var unknown = _t('inspector.unknown');
54587             if (!d) return unknown; // Issue titles supplied by Osmose
54588
54589             var s = services.osmose.getStrings(d.itemType);
54590             return 'title' in s ? s.title : unknown;
54591           }
54592
54593           function osmoseHeader(selection) {
54594             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
54595               return "".concat(d.id, "-").concat(d.status || 0);
54596             });
54597             header.exit().remove();
54598             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
54599             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
54600               return d.id < 0;
54601             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
54602               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
54603             });
54604             svgEnter.append('polygon').attr('fill', function (d) {
54605               return services.osmose.getColor(d.item);
54606             }).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');
54607             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
54608               var picon = d.icon;
54609
54610               if (!picon) {
54611                 return '';
54612               } else {
54613                 var isMaki = /^maki-/.test(picon);
54614                 return "#".concat(picon).concat(isMaki ? '-11' : '');
54615               }
54616             });
54617             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
54618           }
54619
54620           osmoseHeader.issue = function (val) {
54621             if (!arguments.length) return _qaItem;
54622             _qaItem = val;
54623             return osmoseHeader;
54624           };
54625
54626           return osmoseHeader;
54627         }
54628
54629         function uiViewOnOsmose() {
54630           var _qaItem;
54631
54632           function viewOnOsmose(selection) {
54633             var url;
54634
54635             if (services.osmose && _qaItem instanceof QAItem) {
54636               url = services.osmose.itemURL(_qaItem);
54637             }
54638
54639             var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
54640
54641             link.exit().remove(); // enter
54642
54643             var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
54644             .attr('href', function (d) {
54645               return d;
54646             }).call(svgIcon('#iD-icon-out-link', 'inline'));
54647             linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
54648           }
54649
54650           viewOnOsmose.what = function (val) {
54651             if (!arguments.length) return _qaItem;
54652             _qaItem = val;
54653             return viewOnOsmose;
54654           };
54655
54656           return viewOnOsmose;
54657         }
54658
54659         function uiOsmoseEditor(context) {
54660           var dispatch$1 = dispatch('change');
54661           var qaDetails = uiOsmoseDetails(context);
54662           var qaHeader = uiOsmoseHeader();
54663
54664           var _qaItem;
54665
54666           function osmoseEditor(selection) {
54667             var header = selection.selectAll('.header').data([0]);
54668             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
54669             headerEnter.append('button').attr('class', 'close').on('click', function () {
54670               return context.enter(modeBrowse(context));
54671             }).call(svgIcon('#iD-icon-close'));
54672             headerEnter.append('h3').html(_t.html('QA.osmose.title'));
54673             var body = selection.selectAll('.body').data([0]);
54674             body = body.enter().append('div').attr('class', 'body').merge(body);
54675             var editor = body.selectAll('.qa-editor').data([0]);
54676             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
54677             var footer = selection.selectAll('.footer').data([0]);
54678             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
54679           }
54680
54681           function osmoseSaveSection(selection) {
54682             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54683
54684             var isShown = _qaItem && isSelected;
54685             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
54686               return "".concat(d.id, "-").concat(d.status || 0);
54687             }); // exit
54688
54689             saveSection.exit().remove(); // enter
54690
54691             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
54692
54693             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
54694           }
54695
54696           function qaSaveButtons(selection) {
54697             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
54698
54699             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
54700               return d.status + d.id;
54701             }); // exit
54702
54703             buttonSection.exit().remove(); // enter
54704
54705             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
54706             buttonEnter.append('button').attr('class', 'button close-button action');
54707             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
54708
54709             buttonSection = buttonSection.merge(buttonEnter);
54710             buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
54711               this.blur(); // avoid keeping focus on the button - #4641
54712
54713               var qaService = services.osmose;
54714
54715               if (qaService) {
54716                 d.newStatus = 'done';
54717                 qaService.postUpdate(d, function (err, item) {
54718                   return dispatch$1.call('change', item);
54719                 });
54720               }
54721             });
54722             buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
54723               this.blur(); // avoid keeping focus on the button - #4641
54724
54725               var qaService = services.osmose;
54726
54727               if (qaService) {
54728                 d.newStatus = 'false';
54729                 qaService.postUpdate(d, function (err, item) {
54730                   return dispatch$1.call('change', item);
54731                 });
54732               }
54733             });
54734           } // NOTE: Don't change method name until UI v3 is merged
54735
54736
54737           osmoseEditor.error = function (val) {
54738             if (!arguments.length) return _qaItem;
54739             _qaItem = val;
54740             return osmoseEditor;
54741           };
54742
54743           return utilRebind(osmoseEditor, dispatch$1, 'on');
54744         }
54745
54746         function modeSelectError(context, selectedErrorID, selectedErrorService) {
54747           var mode = {
54748             id: 'select-error',
54749             button: 'browse'
54750           };
54751           var keybinding = utilKeybinding('select-error');
54752           var errorService = services[selectedErrorService];
54753           var errorEditor;
54754
54755           switch (selectedErrorService) {
54756             case 'improveOSM':
54757               errorEditor = uiImproveOsmEditor(context).on('change', function () {
54758                 context.map().pan([0, 0]); // trigger a redraw
54759
54760                 var error = checkSelectedID();
54761                 if (!error) return;
54762                 context.ui().sidebar.show(errorEditor.error(error));
54763               });
54764               break;
54765
54766             case 'keepRight':
54767               errorEditor = uiKeepRightEditor(context).on('change', function () {
54768                 context.map().pan([0, 0]); // trigger a redraw
54769
54770                 var error = checkSelectedID();
54771                 if (!error) return;
54772                 context.ui().sidebar.show(errorEditor.error(error));
54773               });
54774               break;
54775
54776             case 'osmose':
54777               errorEditor = uiOsmoseEditor(context).on('change', function () {
54778                 context.map().pan([0, 0]); // trigger a redraw
54779
54780                 var error = checkSelectedID();
54781                 if (!error) return;
54782                 context.ui().sidebar.show(errorEditor.error(error));
54783               });
54784               break;
54785           }
54786
54787           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
54788
54789           function checkSelectedID() {
54790             if (!errorService) return;
54791             var error = errorService.getError(selectedErrorID);
54792
54793             if (!error) {
54794               context.enter(modeBrowse(context));
54795             }
54796
54797             return error;
54798           }
54799
54800           mode.zoomToSelected = function () {
54801             if (!errorService) return;
54802             var error = errorService.getError(selectedErrorID);
54803
54804             if (error) {
54805               context.map().centerZoomEase(error.loc, 20);
54806             }
54807           };
54808
54809           mode.enter = function () {
54810             var error = checkSelectedID();
54811             if (!error) return;
54812             behaviors.forEach(context.install);
54813             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
54814             select(document).call(keybinding);
54815             selectError();
54816             var sidebar = context.ui().sidebar;
54817             sidebar.show(errorEditor.error(error));
54818             context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
54819
54820             function selectError(d3_event, drawn) {
54821               if (!checkSelectedID()) return;
54822               var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
54823
54824               if (selection.empty()) {
54825                 // Return to browse mode if selected DOM elements have
54826                 // disappeared because the user moved them out of view..
54827                 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
54828
54829                 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
54830                   context.enter(modeBrowse(context));
54831                 }
54832               } else {
54833                 selection.classed('selected', true);
54834                 context.selectedErrorID(selectedErrorID);
54835               }
54836             }
54837
54838             function esc() {
54839               if (context.container().select('.combobox').size()) return;
54840               context.enter(modeBrowse(context));
54841             }
54842           };
54843
54844           mode.exit = function () {
54845             behaviors.forEach(context.uninstall);
54846             select(document).call(keybinding.unbind);
54847             context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
54848             context.map().on('drawn.select-error', null);
54849             context.ui().sidebar.hide();
54850             context.selectedErrorID(null);
54851             context.features().forceVisible([]);
54852           };
54853
54854           return mode;
54855         }
54856
54857         function behaviorSelect(context) {
54858           var _tolerancePx = 4; // see also behaviorDrag
54859
54860           var _lastMouseEvent = null;
54861           var _showMenu = false;
54862           var _downPointers = {};
54863           var _longPressTimeout = null;
54864           var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
54865
54866           var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
54867
54868           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
54869
54870           function keydown(d3_event) {
54871             if (d3_event.keyCode === 32) {
54872               // don't react to spacebar events during text input
54873               var activeNode = document.activeElement;
54874               if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
54875             }
54876
54877             if (d3_event.keyCode === 93 || // context menu key
54878             d3_event.keyCode === 32) {
54879               // spacebar
54880               d3_event.preventDefault();
54881             }
54882
54883             if (d3_event.repeat) return; // ignore repeated events for held keys
54884             // if any key is pressed the user is probably doing something other than long-pressing
54885
54886             cancelLongPress();
54887
54888             if (d3_event.shiftKey) {
54889               context.surface().classed('behavior-multiselect', true);
54890             }
54891
54892             if (d3_event.keyCode === 32) {
54893               // spacebar
54894               if (!_downPointers.spacebar && _lastMouseEvent) {
54895                 cancelLongPress();
54896                 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
54897                 _downPointers.spacebar = {
54898                   firstEvent: _lastMouseEvent,
54899                   lastEvent: _lastMouseEvent
54900                 };
54901               }
54902             }
54903           }
54904
54905           function keyup(d3_event) {
54906             cancelLongPress();
54907
54908             if (!d3_event.shiftKey) {
54909               context.surface().classed('behavior-multiselect', false);
54910             }
54911
54912             if (d3_event.keyCode === 93) {
54913               // context menu key
54914               d3_event.preventDefault();
54915               _lastInteractionType = 'menukey';
54916               contextmenu(d3_event);
54917             } else if (d3_event.keyCode === 32) {
54918               // spacebar
54919               var pointer = _downPointers.spacebar;
54920
54921               if (pointer) {
54922                 delete _downPointers.spacebar;
54923                 if (pointer.done) return;
54924                 d3_event.preventDefault();
54925                 _lastInteractionType = 'spacebar';
54926                 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
54927               }
54928             }
54929           }
54930
54931           function pointerdown(d3_event) {
54932             var id = (d3_event.pointerId || 'mouse').toString();
54933             cancelLongPress();
54934             if (d3_event.buttons && d3_event.buttons !== 1) return;
54935             context.ui().closeEditMenu();
54936             _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
54937             _downPointers[id] = {
54938               firstEvent: d3_event,
54939               lastEvent: d3_event
54940             };
54941           }
54942
54943           function didLongPress(id, interactionType) {
54944             var pointer = _downPointers[id];
54945             if (!pointer) return;
54946
54947             for (var i in _downPointers) {
54948               // don't allow this or any currently down pointer to trigger another click
54949               _downPointers[i].done = true;
54950             } // treat long presses like right-clicks
54951
54952
54953             _longPressTimeout = null;
54954             _lastInteractionType = interactionType;
54955             _showMenu = true;
54956             click(pointer.firstEvent, pointer.lastEvent, id);
54957           }
54958
54959           function pointermove(d3_event) {
54960             var id = (d3_event.pointerId || 'mouse').toString();
54961
54962             if (_downPointers[id]) {
54963               _downPointers[id].lastEvent = d3_event;
54964             }
54965
54966             if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
54967               _lastMouseEvent = d3_event;
54968
54969               if (_downPointers.spacebar) {
54970                 _downPointers.spacebar.lastEvent = d3_event;
54971               }
54972             }
54973           }
54974
54975           function pointerup(d3_event) {
54976             var id = (d3_event.pointerId || 'mouse').toString();
54977             var pointer = _downPointers[id];
54978             if (!pointer) return;
54979             delete _downPointers[id];
54980
54981             if (_multiselectionPointerId === id) {
54982               _multiselectionPointerId = null;
54983             }
54984
54985             if (pointer.done) return;
54986             click(pointer.firstEvent, d3_event, id);
54987           }
54988
54989           function pointercancel(d3_event) {
54990             var id = (d3_event.pointerId || 'mouse').toString();
54991             if (!_downPointers[id]) return;
54992             delete _downPointers[id];
54993
54994             if (_multiselectionPointerId === id) {
54995               _multiselectionPointerId = null;
54996             }
54997           }
54998
54999           function contextmenu(d3_event) {
55000             d3_event.preventDefault();
55001
55002             if (!+d3_event.clientX && !+d3_event.clientY) {
55003               if (_lastMouseEvent) {
55004                 d3_event.sourceEvent = _lastMouseEvent;
55005               } else {
55006                 return;
55007               }
55008             } else {
55009               _lastMouseEvent = d3_event;
55010               _lastInteractionType = 'rightclick';
55011             }
55012
55013             _showMenu = true;
55014             click(d3_event, d3_event);
55015           }
55016
55017           function click(firstEvent, lastEvent, pointerId) {
55018             cancelLongPress();
55019             var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
55020             // are transformed when drag-panning.
55021
55022             var pointGetter = utilFastMouse(mapNode);
55023             var p1 = pointGetter(firstEvent);
55024             var p2 = pointGetter(lastEvent);
55025             var dist = geoVecLength(p1, p2);
55026
55027             if (dist > _tolerancePx || !mapContains(lastEvent)) {
55028               resetProperties();
55029               return;
55030             }
55031
55032             var targetDatum = lastEvent.target.__data__;
55033             var multiselectEntityId;
55034
55035             if (!_multiselectionPointerId) {
55036               // If a different pointer than the one triggering this click is down on a
55037               // feature, treat this and all future clicks as multiselection until that
55038               // pointer is raised.
55039               var selectPointerInfo = pointerDownOnSelection(pointerId);
55040
55041               if (selectPointerInfo) {
55042                 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
55043
55044                 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
55045                 _downPointers[selectPointerInfo.pointerId].done = true;
55046               }
55047             } // support multiselect if data is already selected
55048
55049
55050             var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
55051             lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
55052             context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
55053             _multiselectionPointerId && !multiselectEntityId);
55054
55055             processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
55056
55057             function mapContains(event) {
55058               var rect = mapNode.getBoundingClientRect();
55059               return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
55060             }
55061
55062             function pointerDownOnSelection(skipPointerId) {
55063               var mode = context.mode();
55064               var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
55065
55066               for (var pointerId in _downPointers) {
55067                 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
55068                 var pointerInfo = _downPointers[pointerId];
55069                 var p1 = pointGetter(pointerInfo.firstEvent);
55070                 var p2 = pointGetter(pointerInfo.lastEvent);
55071                 if (geoVecLength(p1, p2) > _tolerancePx) continue;
55072                 var datum = pointerInfo.firstEvent.target.__data__;
55073                 var entity = datum && datum.properties && datum.properties.entity || datum;
55074                 if (context.graph().hasEntity(entity.id)) return {
55075                   pointerId: pointerId,
55076                   entityId: entity.id,
55077                   selected: selectedIDs.indexOf(entity.id) !== -1
55078                 };
55079               }
55080
55081               return null;
55082             }
55083           }
55084
55085           function processClick(datum, isMultiselect, point, alsoSelectId) {
55086             var mode = context.mode();
55087             var showMenu = _showMenu;
55088             var interactionType = _lastInteractionType;
55089             var entity = datum && datum.properties && datum.properties.entity;
55090             if (entity) datum = entity;
55091
55092             if (datum && datum.type === 'midpoint') {
55093               // treat targeting midpoints as if targeting the parent way
55094               datum = datum.parents[0];
55095             }
55096
55097             var newMode;
55098
55099             if (datum instanceof osmEntity) {
55100               // targeting an entity
55101               var selectedIDs = context.selectedIDs();
55102               context.selectedNoteID(null);
55103               context.selectedErrorID(null);
55104
55105               if (!isMultiselect) {
55106                 // don't change the selection if we're toggling the menu atop a multiselection
55107                 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
55108                   if (alsoSelectId === datum.id) alsoSelectId = null;
55109                   selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
55110                   // selected since listeners may expect `context.enter` events,
55111                   // e.g. in the walkthrough
55112
55113                   newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
55114                   context.enter(newMode);
55115                 }
55116               } else {
55117                 if (selectedIDs.indexOf(datum.id) !== -1) {
55118                   // clicked entity is already in the selectedIDs list..
55119                   if (!showMenu) {
55120                     // deselect clicked entity, then reenter select mode or return to browse mode..
55121                     selectedIDs = selectedIDs.filter(function (id) {
55122                       return id !== datum.id;
55123                     });
55124                     newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
55125                     context.enter(newMode);
55126                   }
55127                 } else {
55128                   // clicked entity is not in the selected list, add it..
55129                   selectedIDs = selectedIDs.concat([datum.id]);
55130                   newMode = mode.selectedIDs(selectedIDs);
55131                   context.enter(newMode);
55132                 }
55133               }
55134             } else if (datum && datum.__featurehash__ && !isMultiselect) {
55135               // targeting custom data
55136               context.selectedNoteID(null).enter(modeSelectData(context, datum));
55137             } else if (datum instanceof osmNote && !isMultiselect) {
55138               // targeting a note
55139               context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
55140             } else if (datum instanceof QAItem & !isMultiselect) {
55141               // targeting an external QA issue
55142               context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
55143             } else {
55144               // targeting nothing
55145               context.selectedNoteID(null);
55146               context.selectedErrorID(null);
55147
55148               if (!isMultiselect && mode.id !== 'browse') {
55149                 context.enter(modeBrowse(context));
55150               }
55151             }
55152
55153             context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
55154
55155             if (showMenu) context.ui().showEditMenu(point, interactionType);
55156             resetProperties();
55157           }
55158
55159           function cancelLongPress() {
55160             if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
55161             _longPressTimeout = null;
55162           }
55163
55164           function resetProperties() {
55165             cancelLongPress();
55166             _showMenu = false;
55167             _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
55168           }
55169
55170           function behavior(selection) {
55171             resetProperties();
55172             _lastMouseEvent = context.map().lastPointerEvent();
55173             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) {
55174               // Edge and IE really like to show the contextmenu on the
55175               // menubar when user presses a keyboard menu button
55176               // even after we've already preventdefaulted the key event.
55177               var e = d3_event;
55178
55179               if (+e.clientX === 0 && +e.clientY === 0) {
55180                 d3_event.preventDefault();
55181               }
55182             });
55183             selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
55184             /*if (d3_event && d3_event.shiftKey) {
55185                 context.surface()
55186                     .classed('behavior-multiselect', true);
55187             }*/
55188           }
55189
55190           behavior.off = function (selection) {
55191             cancelLongPress();
55192             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);
55193             selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
55194             context.surface().classed('behavior-multiselect', false);
55195           };
55196
55197           return behavior;
55198         }
55199
55200         function behaviorDrawWay(context, wayID, mode, startGraph) {
55201           var dispatch$1 = dispatch('rejectedSelfIntersection');
55202           var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
55203
55204           var _nodeIndex;
55205
55206           var _origWay;
55207
55208           var _wayGeometry;
55209
55210           var _headNodeID;
55211
55212           var _annotation;
55213
55214           var _pointerHasMoved = false; // The osmNode to be placed.
55215           // This is temporary and just follows the mouse cursor until an "add" event occurs.
55216
55217           var _drawNode;
55218
55219           var _didResolveTempEdit = false;
55220
55221           function createDrawNode(loc) {
55222             // don't make the draw node until we actually need it
55223             _drawNode = osmNode({
55224               loc: loc
55225             });
55226             context.pauseChangeDispatch();
55227             context.replace(function actionAddDrawNode(graph) {
55228               // add the draw node to the graph and insert it into the way
55229               var way = graph.entity(wayID);
55230               return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
55231             }, _annotation);
55232             context.resumeChangeDispatch();
55233             setActiveElements();
55234           }
55235
55236           function removeDrawNode() {
55237             context.pauseChangeDispatch();
55238             context.replace(function actionDeleteDrawNode(graph) {
55239               var way = graph.entity(wayID);
55240               return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
55241             }, _annotation);
55242             _drawNode = undefined;
55243             context.resumeChangeDispatch();
55244           }
55245
55246           function keydown(d3_event) {
55247             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
55248               if (context.surface().classed('nope')) {
55249                 context.surface().classed('nope-suppressed', true);
55250               }
55251
55252               context.surface().classed('nope', false).classed('nope-disabled', true);
55253             }
55254           }
55255
55256           function keyup(d3_event) {
55257             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
55258               if (context.surface().classed('nope-suppressed')) {
55259                 context.surface().classed('nope', true);
55260               }
55261
55262               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
55263             }
55264           }
55265
55266           function allowsVertex(d) {
55267             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
55268           } // related code
55269           // - `mode/drag_node.js`     `doMove()`
55270           // - `behavior/draw.js`      `click()`
55271           // - `behavior/draw_way.js`  `move()`
55272
55273
55274           function move(d3_event, datum) {
55275             var loc = context.map().mouseCoordinates();
55276             if (!_drawNode) createDrawNode(loc);
55277             context.surface().classed('nope-disabled', d3_event.altKey);
55278             var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
55279             var targetNodes = datum && datum.properties && datum.properties.nodes;
55280
55281             if (targetLoc) {
55282               // snap to node/vertex - a point target with `.loc`
55283               loc = targetLoc;
55284             } else if (targetNodes) {
55285               // snap to way - a line target with `.nodes`
55286               var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
55287
55288               if (choice) {
55289                 loc = choice.loc;
55290               }
55291             }
55292
55293             context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
55294             _drawNode = context.entity(_drawNode.id);
55295             checkGeometry(true
55296             /* includeDrawNode */
55297             );
55298           } // Check whether this edit causes the geometry to break.
55299           // If so, class the surface with a nope cursor.
55300           // `includeDrawNode` - Only check the relevant line segments if finishing drawing
55301
55302
55303           function checkGeometry(includeDrawNode) {
55304             var nopeDisabled = context.surface().classed('nope-disabled');
55305             var isInvalid = isInvalidGeometry(includeDrawNode);
55306
55307             if (nopeDisabled) {
55308               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
55309             } else {
55310               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
55311             }
55312           }
55313
55314           function isInvalidGeometry(includeDrawNode) {
55315             var testNode = _drawNode; // we only need to test the single way we're drawing
55316
55317             var parentWay = context.graph().entity(wayID);
55318             var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
55319
55320             if (includeDrawNode) {
55321               if (parentWay.isClosed()) {
55322                 // don't test the last segment for closed ways - #4655
55323                 // (still test the first segment)
55324                 nodes.pop();
55325               }
55326             } else {
55327               // discount the draw node
55328               if (parentWay.isClosed()) {
55329                 if (nodes.length < 3) return false;
55330                 if (_drawNode) nodes.splice(-2, 1);
55331                 testNode = nodes[nodes.length - 2];
55332               } else {
55333                 // there's nothing we need to test if we ignore the draw node on open ways
55334                 return false;
55335               }
55336             }
55337
55338             return testNode && geoHasSelfIntersections(nodes, testNode.id);
55339           }
55340
55341           function undone() {
55342             // undoing removed the temp edit
55343             _didResolveTempEdit = true;
55344             context.pauseChangeDispatch();
55345             var nextMode;
55346
55347             if (context.graph() === startGraph) {
55348               // We've undone back to the initial state before we started drawing.
55349               // Just exit the draw mode without undoing whatever we did before
55350               // we entered the draw mode.
55351               nextMode = modeSelect(context, [wayID]);
55352             } else {
55353               // The `undo` only removed the temporary edit, so here we have to
55354               // manually undo to actually remove the last node we added. We can't
55355               // use the `undo` function since the initial "add" graph doesn't have
55356               // an annotation and so cannot be undone to.
55357               context.pop(1); // continue drawing
55358
55359               nextMode = mode;
55360             } // clear the redo stack by adding and removing a blank edit
55361
55362
55363             context.perform(actionNoop());
55364             context.pop(1);
55365             context.resumeChangeDispatch();
55366             context.enter(nextMode);
55367           }
55368
55369           function setActiveElements() {
55370             if (!_drawNode) return;
55371             context.surface().selectAll('.' + _drawNode.id).classed('active', true);
55372           }
55373
55374           function resetToStartGraph() {
55375             while (context.graph() !== startGraph) {
55376               context.pop();
55377             }
55378           }
55379
55380           var drawWay = function drawWay(surface) {
55381             _drawNode = undefined;
55382             _didResolveTempEdit = false;
55383             _origWay = context.entity(wayID);
55384             _headNodeID = typeof _nodeIndex === 'number' ? _origWay.nodes[_nodeIndex] : _origWay.isClosed() ? _origWay.nodes[_origWay.nodes.length - 2] : _origWay.nodes[_origWay.nodes.length - 1];
55385             _wayGeometry = _origWay.geometry(context.graph());
55386             _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
55387             _pointerHasMoved = false; // Push an annotated state for undo to return back to.
55388             // We must make sure to replace or remove it later.
55389
55390             context.pauseChangeDispatch();
55391             context.perform(actionNoop(), _annotation);
55392             context.resumeChangeDispatch();
55393             behavior.hover().initialNodeID(_headNodeID);
55394             behavior.on('move', function () {
55395               _pointerHasMoved = true;
55396               move.apply(this, arguments);
55397             }).on('down', function () {
55398               move.apply(this, arguments);
55399             }).on('downcancel', function () {
55400               if (_drawNode) removeDrawNode();
55401             }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
55402             select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
55403             context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
55404             setActiveElements();
55405             surface.call(behavior);
55406             context.history().on('undone.draw', undone);
55407           };
55408
55409           drawWay.off = function (surface) {
55410             if (!_didResolveTempEdit) {
55411               // Drawing was interrupted unexpectedly.
55412               // This can happen if the user changes modes,
55413               // clicks geolocate button, a hashchange event occurs, etc.
55414               context.pauseChangeDispatch();
55415               resetToStartGraph();
55416               context.resumeChangeDispatch();
55417             }
55418
55419             _drawNode = undefined;
55420             _nodeIndex = undefined;
55421             context.map().on('drawn.draw', null);
55422             surface.call(behavior.off).selectAll('.active').classed('active', false);
55423             surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
55424             select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
55425             context.history().on('undone.draw', null);
55426           };
55427
55428           function attemptAdd(d, loc, doAdd) {
55429             if (_drawNode) {
55430               // move the node to the final loc in case move wasn't called
55431               // consistently (e.g. on touch devices)
55432               context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
55433               _drawNode = context.entity(_drawNode.id);
55434             } else {
55435               createDrawNode(loc);
55436             }
55437
55438             checkGeometry(true
55439             /* includeDrawNode */
55440             );
55441
55442             if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
55443               if (!_pointerHasMoved) {
55444                 // prevent the temporary draw node from appearing on touch devices
55445                 removeDrawNode();
55446               }
55447
55448               dispatch$1.call('rejectedSelfIntersection', this);
55449               return; // can't click here
55450             }
55451
55452             context.pauseChangeDispatch();
55453             doAdd(); // we just replaced the temporary edit with the real one
55454
55455             _didResolveTempEdit = true;
55456             context.resumeChangeDispatch();
55457             context.enter(mode);
55458           } // Accept the current position of the drawing node
55459
55460
55461           drawWay.add = function (loc, d) {
55462             attemptAdd(d, loc, function () {// don't need to do anything extra
55463             });
55464           }; // Connect the way to an existing way
55465
55466
55467           drawWay.addWay = function (loc, edge, d) {
55468             attemptAdd(d, loc, function () {
55469               context.replace(actionAddMidpoint({
55470                 loc: loc,
55471                 edge: edge
55472               }, _drawNode), _annotation);
55473             });
55474           }; // Connect the way to an existing node
55475
55476
55477           drawWay.addNode = function (node, d) {
55478             // finish drawing if the mapper targets the prior node
55479             if (node.id === _headNodeID || // or the first node when drawing an area
55480             _origWay.isClosed() && node.id === _origWay.first()) {
55481               drawWay.finish();
55482               return;
55483             }
55484
55485             attemptAdd(d, node.loc, function () {
55486               context.replace(function actionReplaceDrawNode(graph) {
55487                 // remove the temporary draw node and insert the existing node
55488                 // at the same index
55489                 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
55490                 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
55491               }, _annotation);
55492             });
55493           }; // Finish the draw operation, removing the temporary edit.
55494           // If the way has enough nodes to be valid, it's selected.
55495           // Otherwise, delete everything and return to browse mode.
55496
55497
55498           drawWay.finish = function () {
55499             checkGeometry(false
55500             /* includeDrawNode */
55501             );
55502
55503             if (context.surface().classed('nope')) {
55504               dispatch$1.call('rejectedSelfIntersection', this);
55505               return; // can't click here
55506             }
55507
55508             context.pauseChangeDispatch(); // remove the temporary edit
55509
55510             context.pop(1);
55511             _didResolveTempEdit = true;
55512             context.resumeChangeDispatch();
55513             var way = context.hasEntity(wayID);
55514
55515             if (!way || way.isDegenerate()) {
55516               drawWay.cancel();
55517               return;
55518             }
55519
55520             window.setTimeout(function () {
55521               context.map().dblclickZoomEnable(true);
55522             }, 1000);
55523             var isNewFeature = !mode.isContinuing;
55524             context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
55525           }; // Cancel the draw operation, delete everything, and return to browse mode.
55526
55527
55528           drawWay.cancel = function () {
55529             context.pauseChangeDispatch();
55530             resetToStartGraph();
55531             context.resumeChangeDispatch();
55532             window.setTimeout(function () {
55533               context.map().dblclickZoomEnable(true);
55534             }, 1000);
55535             context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
55536             context.enter(modeBrowse(context));
55537           };
55538
55539           drawWay.nodeIndex = function (val) {
55540             if (!arguments.length) return _nodeIndex;
55541             _nodeIndex = val;
55542             return drawWay;
55543           };
55544
55545           drawWay.activeID = function () {
55546             if (!arguments.length) return _drawNode && _drawNode.id; // no assign
55547
55548             return drawWay;
55549           };
55550
55551           return utilRebind(drawWay, dispatch$1, 'on');
55552         }
55553
55554         function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
55555           var mode = {
55556             button: button,
55557             id: 'draw-line'
55558           };
55559           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
55560             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
55561           });
55562           mode.wayID = wayID;
55563           mode.isContinuing = continuing;
55564
55565           mode.enter = function () {
55566             behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
55567             context.install(behavior);
55568           };
55569
55570           mode.exit = function () {
55571             context.uninstall(behavior);
55572           };
55573
55574           mode.selectedIDs = function () {
55575             return [wayID];
55576           };
55577
55578           mode.activeID = function () {
55579             return behavior && behavior.activeID() || [];
55580           };
55581
55582           return mode;
55583         }
55584
55585         function operationContinue(context, selectedIDs) {
55586           var _entities = selectedIDs.map(function (id) {
55587             return context.graph().entity(id);
55588           });
55589
55590           var _geometries = Object.assign({
55591             line: [],
55592             vertex: []
55593           }, utilArrayGroupBy(_entities, function (entity) {
55594             return entity.geometry(context.graph());
55595           }));
55596
55597           var _vertex = _geometries.vertex.length && _geometries.vertex[0];
55598
55599           function candidateWays() {
55600             return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
55601               return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
55602             }) : [];
55603           }
55604
55605           var _candidates = candidateWays();
55606
55607           var operation = function operation() {
55608             var candidate = _candidates[0];
55609             context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
55610           };
55611
55612           operation.relatedEntityIds = function () {
55613             return _candidates.length ? [_candidates[0].id] : [];
55614           };
55615
55616           operation.available = function () {
55617             return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
55618           };
55619
55620           operation.disabled = function () {
55621             if (_candidates.length === 0) {
55622               return 'not_eligible';
55623             } else if (_candidates.length > 1) {
55624               return 'multiple';
55625             }
55626
55627             return false;
55628           };
55629
55630           operation.tooltip = function () {
55631             var disable = operation.disabled();
55632             return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
55633           };
55634
55635           operation.annotation = function () {
55636             return _t('operations.continue.annotation.line');
55637           };
55638
55639           operation.id = 'continue';
55640           operation.keys = [_t('operations.continue.key')];
55641           operation.title = _t('operations.continue.title');
55642           operation.behavior = behaviorOperation(context).which(operation);
55643           return operation;
55644         }
55645
55646         function operationCopy(context, selectedIDs) {
55647           function getFilteredIdsToCopy() {
55648             return selectedIDs.filter(function (selectedID) {
55649               var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
55650
55651               return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
55652             });
55653           }
55654
55655           var operation = function operation() {
55656             var graph = context.graph();
55657             var selected = groupEntities(getFilteredIdsToCopy(), graph);
55658             var canCopy = [];
55659             var skip = {};
55660             var entity;
55661             var i;
55662
55663             for (i = 0; i < selected.relation.length; i++) {
55664               entity = selected.relation[i];
55665
55666               if (!skip[entity.id] && entity.isComplete(graph)) {
55667                 canCopy.push(entity.id);
55668                 skip = getDescendants(entity.id, graph, skip);
55669               }
55670             }
55671
55672             for (i = 0; i < selected.way.length; i++) {
55673               entity = selected.way[i];
55674
55675               if (!skip[entity.id]) {
55676                 canCopy.push(entity.id);
55677                 skip = getDescendants(entity.id, graph, skip);
55678               }
55679             }
55680
55681             for (i = 0; i < selected.node.length; i++) {
55682               entity = selected.node[i];
55683
55684               if (!skip[entity.id]) {
55685                 canCopy.push(entity.id);
55686               }
55687             }
55688
55689             context.copyIDs(canCopy);
55690
55691             if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
55692               // store the anchor coordinates if copying more than a single node
55693               context.copyLonLat(context.projection.invert(_point));
55694             } else {
55695               context.copyLonLat(null);
55696             }
55697           };
55698
55699           function groupEntities(ids, graph) {
55700             var entities = ids.map(function (id) {
55701               return graph.entity(id);
55702             });
55703             return Object.assign({
55704               relation: [],
55705               way: [],
55706               node: []
55707             }, utilArrayGroupBy(entities, 'type'));
55708           }
55709
55710           function getDescendants(id, graph, descendants) {
55711             var entity = graph.entity(id);
55712             var children;
55713             descendants = descendants || {};
55714
55715             if (entity.type === 'relation') {
55716               children = entity.members.map(function (m) {
55717                 return m.id;
55718               });
55719             } else if (entity.type === 'way') {
55720               children = entity.nodes;
55721             } else {
55722               children = [];
55723             }
55724
55725             for (var i = 0; i < children.length; i++) {
55726               if (!descendants[children[i]]) {
55727                 descendants[children[i]] = true;
55728                 descendants = getDescendants(children[i], graph, descendants);
55729               }
55730             }
55731
55732             return descendants;
55733           }
55734
55735           operation.available = function () {
55736             return getFilteredIdsToCopy().length > 0;
55737           };
55738
55739           operation.disabled = function () {
55740             var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
55741
55742             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
55743               return 'too_large';
55744             }
55745
55746             return false;
55747           };
55748
55749           operation.availableForKeypress = function () {
55750             var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
55751
55752             return !selection || !selection.toString();
55753           };
55754
55755           operation.tooltip = function () {
55756             var disable = operation.disabled();
55757             return disable ? _t('operations.copy.' + disable, {
55758               n: selectedIDs.length
55759             }) : _t('operations.copy.description', {
55760               n: selectedIDs.length
55761             });
55762           };
55763
55764           operation.annotation = function () {
55765             return _t('operations.copy.annotation', {
55766               n: selectedIDs.length
55767             });
55768           };
55769
55770           var _point;
55771
55772           operation.point = function (val) {
55773             _point = val;
55774             return operation;
55775           };
55776
55777           operation.id = 'copy';
55778           operation.keys = [uiCmd('⌘C')];
55779           operation.title = _t('operations.copy.title');
55780           operation.behavior = behaviorOperation(context).which(operation);
55781           return operation;
55782         }
55783
55784         function operationDisconnect(context, selectedIDs) {
55785           var _vertexIDs = [];
55786           var _wayIDs = [];
55787           var _otherIDs = [];
55788           var _actions = [];
55789           selectedIDs.forEach(function (id) {
55790             var entity = context.entity(id);
55791
55792             if (entity.type === 'way') {
55793               _wayIDs.push(id);
55794             } else if (entity.geometry(context.graph()) === 'vertex') {
55795               _vertexIDs.push(id);
55796             } else {
55797               _otherIDs.push(id);
55798             }
55799           });
55800
55801           var _coords,
55802               _descriptionID = '',
55803               _annotationID = 'features';
55804
55805           var _disconnectingVertexIds = [];
55806           var _disconnectingWayIds = [];
55807
55808           if (_vertexIDs.length > 0) {
55809             // At the selected vertices, disconnect the selected ways, if any, else
55810             // disconnect all connected ways
55811             _disconnectingVertexIds = _vertexIDs;
55812
55813             _vertexIDs.forEach(function (vertexID) {
55814               var action = actionDisconnect(vertexID);
55815
55816               if (_wayIDs.length > 0) {
55817                 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
55818                   var way = context.entity(wayID);
55819                   return way.nodes.indexOf(vertexID) !== -1;
55820                 });
55821
55822                 action.limitWays(waysIDsForVertex);
55823               }
55824
55825               _actions.push(action);
55826
55827               _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
55828                 return d.id;
55829               }));
55830             });
55831
55832             _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
55833               return _wayIDs.indexOf(id) === -1;
55834             });
55835             _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
55836
55837             if (_wayIDs.length === 1) {
55838               _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
55839             } else {
55840               _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
55841             }
55842           } else if (_wayIDs.length > 0) {
55843             // Disconnect the selected ways from each other, if they're connected,
55844             // else disconnect them from all connected ways
55845             var ways = _wayIDs.map(function (id) {
55846               return context.entity(id);
55847             });
55848
55849             var nodes = utilGetAllNodes(_wayIDs, context.graph());
55850             _coords = nodes.map(function (n) {
55851               return n.loc;
55852             }); // actions for connected nodes shared by at least two selected ways
55853
55854             var sharedActions = [];
55855             var sharedNodes = []; // actions for connected nodes
55856
55857             var unsharedActions = [];
55858             var unsharedNodes = [];
55859             nodes.forEach(function (node) {
55860               var action = actionDisconnect(node.id).limitWays(_wayIDs);
55861
55862               if (action.disabled(context.graph()) !== 'not_connected') {
55863                 var count = 0;
55864
55865                 for (var i in ways) {
55866                   var way = ways[i];
55867
55868                   if (way.nodes.indexOf(node.id) !== -1) {
55869                     count += 1;
55870                   }
55871
55872                   if (count > 1) break;
55873                 }
55874
55875                 if (count > 1) {
55876                   sharedActions.push(action);
55877                   sharedNodes.push(node);
55878                 } else {
55879                   unsharedActions.push(action);
55880                   unsharedNodes.push(node);
55881                 }
55882               }
55883             });
55884             _descriptionID += 'no_points.';
55885             _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
55886
55887             if (sharedActions.length) {
55888               // if any nodes are shared, only disconnect the selected ways from each other
55889               _actions = sharedActions;
55890               _disconnectingVertexIds = sharedNodes.map(function (node) {
55891                 return node.id;
55892               });
55893               _descriptionID += 'conjoined';
55894               _annotationID = 'from_each_other';
55895             } else {
55896               // if no nodes are shared, disconnect the selected ways from all connected ways
55897               _actions = unsharedActions;
55898               _disconnectingVertexIds = unsharedNodes.map(function (node) {
55899                 return node.id;
55900               });
55901
55902               if (_wayIDs.length === 1) {
55903                 _descriptionID += context.graph().geometry(_wayIDs[0]);
55904               } else {
55905                 _descriptionID += 'separate';
55906               }
55907             }
55908           }
55909
55910           var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
55911
55912           var operation = function operation() {
55913             context.perform(function (graph) {
55914               return _actions.reduce(function (graph, action) {
55915                 return action(graph);
55916               }, graph);
55917             }, operation.annotation());
55918             context.validator().validate();
55919           };
55920
55921           operation.relatedEntityIds = function () {
55922             if (_vertexIDs.length) {
55923               return _disconnectingWayIds;
55924             }
55925
55926             return _disconnectingVertexIds;
55927           };
55928
55929           operation.available = function () {
55930             if (_actions.length === 0) return false;
55931             if (_otherIDs.length !== 0) return false;
55932             if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
55933               return _vertexIDs.some(function (vertexID) {
55934                 var way = context.entity(wayID);
55935                 return way.nodes.indexOf(vertexID) !== -1;
55936               });
55937             })) return false;
55938             return true;
55939           };
55940
55941           operation.disabled = function () {
55942             var reason;
55943
55944             for (var actionIndex in _actions) {
55945               reason = _actions[actionIndex].disabled(context.graph());
55946               if (reason) return reason;
55947             }
55948
55949             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
55950               return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
55951             } else if (_coords && someMissing()) {
55952               return 'not_downloaded';
55953             } else if (selectedIDs.some(context.hasHiddenConnections)) {
55954               return 'connected_to_hidden';
55955             }
55956
55957             return false;
55958
55959             function someMissing() {
55960               if (context.inIntro()) return false;
55961               var osm = context.connection();
55962
55963               if (osm) {
55964                 var missing = _coords.filter(function (loc) {
55965                   return !osm.isDataLoaded(loc);
55966                 });
55967
55968                 if (missing.length) {
55969                   missing.forEach(function (loc) {
55970                     context.loadTileAtLoc(loc);
55971                   });
55972                   return true;
55973                 }
55974               }
55975
55976               return false;
55977             }
55978           };
55979
55980           operation.tooltip = function () {
55981             var disable = operation.disabled();
55982
55983             if (disable) {
55984               return _t('operations.disconnect.' + disable);
55985             }
55986
55987             return _t('operations.disconnect.description.' + _descriptionID);
55988           };
55989
55990           operation.annotation = function () {
55991             return _t('operations.disconnect.annotation.' + _annotationID);
55992           };
55993
55994           operation.id = 'disconnect';
55995           operation.keys = [_t('operations.disconnect.key')];
55996           operation.title = _t('operations.disconnect.title');
55997           operation.behavior = behaviorOperation(context).which(operation);
55998           return operation;
55999         }
56000
56001         function operationDowngrade(context, selectedIDs) {
56002           var _affectedFeatureCount = 0;
56003
56004           var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
56005
56006           var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
56007
56008           function downgradeTypeForEntityIDs(entityIds) {
56009             var downgradeType;
56010             _affectedFeatureCount = 0;
56011
56012             for (var i in entityIds) {
56013               var entityID = entityIds[i];
56014               var type = downgradeTypeForEntityID(entityID);
56015
56016               if (type) {
56017                 _affectedFeatureCount += 1;
56018
56019                 if (downgradeType && type !== downgradeType) {
56020                   if (downgradeType !== 'generic' && type !== 'generic') {
56021                     downgradeType = 'building_address';
56022                   } else {
56023                     downgradeType = 'generic';
56024                   }
56025                 } else {
56026                   downgradeType = type;
56027                 }
56028               }
56029             }
56030
56031             return downgradeType;
56032           }
56033
56034           function downgradeTypeForEntityID(entityID) {
56035             var graph = context.graph();
56036             var entity = graph.entity(entityID);
56037             var preset = _mainPresetIndex.match(entity, graph);
56038             if (!preset || preset.isFallback()) return null;
56039
56040             if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
56041               return key.match(/^addr:.{1,}/);
56042             })) {
56043               return 'address';
56044             }
56045
56046             var geometry = entity.geometry(graph);
56047
56048             if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
56049               return 'building';
56050             }
56051
56052             if (geometry === 'vertex' && Object.keys(entity.tags).length) {
56053               return 'generic';
56054             }
56055
56056             return null;
56057           }
56058
56059           var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
56060           var addressKeysToKeep = ['source'];
56061
56062           var operation = function operation() {
56063             context.perform(function (graph) {
56064               for (var i in selectedIDs) {
56065                 var entityID = selectedIDs[i];
56066                 var type = downgradeTypeForEntityID(entityID);
56067                 if (!type) continue;
56068                 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
56069
56070                 for (var key in tags) {
56071                   if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
56072
56073                   if (type === 'building') {
56074                     if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
56075                   }
56076
56077                   if (type !== 'generic') {
56078                     if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
56079                   }
56080
56081                   delete tags[key];
56082                 }
56083
56084                 graph = actionChangeTags(entityID, tags)(graph);
56085               }
56086
56087               return graph;
56088             }, operation.annotation());
56089             context.validator().validate(); // refresh the select mode to enable the delete operation
56090
56091             context.enter(modeSelect(context, selectedIDs));
56092           };
56093
56094           operation.available = function () {
56095             return _downgradeType;
56096           };
56097
56098           operation.disabled = function () {
56099             if (selectedIDs.some(hasWikidataTag)) {
56100               return 'has_wikidata_tag';
56101             }
56102
56103             return false;
56104
56105             function hasWikidataTag(id) {
56106               var entity = context.entity(id);
56107               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
56108             }
56109           };
56110
56111           operation.tooltip = function () {
56112             var disable = operation.disabled();
56113             return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
56114           };
56115
56116           operation.annotation = function () {
56117             var suffix;
56118
56119             if (_downgradeType === 'building_address') {
56120               suffix = 'generic';
56121             } else {
56122               suffix = _downgradeType;
56123             }
56124
56125             return _t('operations.downgrade.annotation.' + suffix, {
56126               n: _affectedFeatureCount
56127             });
56128           };
56129
56130           operation.id = 'downgrade';
56131           operation.keys = [uiCmd('⌫')];
56132           operation.title = _t('operations.downgrade.title');
56133           operation.behavior = behaviorOperation(context).which(operation);
56134           return operation;
56135         }
56136
56137         function operationExtract(context, selectedIDs) {
56138           var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
56139
56140           var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
56141             return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
56142           }).filter(Boolean));
56143
56144           var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
56145
56146           var _extent;
56147
56148           var _actions = selectedIDs.map(function (entityID) {
56149             var graph = context.graph();
56150             var entity = graph.hasEntity(entityID);
56151             if (!entity || !entity.hasInterestingTags()) return null;
56152             if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
56153
56154             if (entity.type !== 'node') {
56155               var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
56156
56157               if (preset.geometry.indexOf('point') === -1) return null;
56158             }
56159
56160             _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
56161             return actionExtract(entityID);
56162           }).filter(Boolean);
56163
56164           var operation = function operation() {
56165             var combinedAction = function combinedAction(graph) {
56166               _actions.forEach(function (action) {
56167                 graph = action(graph);
56168               });
56169
56170               return graph;
56171             };
56172
56173             context.perform(combinedAction, operation.annotation()); // do the extract
56174
56175             var extractedNodeIDs = _actions.map(function (action) {
56176               return action.getExtractedNodeID();
56177             });
56178
56179             context.enter(modeSelect(context, extractedNodeIDs));
56180           };
56181
56182           operation.available = function () {
56183             return _actions.length && selectedIDs.length === _actions.length;
56184           };
56185
56186           operation.disabled = function () {
56187             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
56188               return 'too_large';
56189             } else if (selectedIDs.some(function (entityID) {
56190               return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
56191             })) {
56192               return 'connected_to_hidden';
56193             }
56194
56195             return false;
56196           };
56197
56198           operation.tooltip = function () {
56199             var disableReason = operation.disabled();
56200
56201             if (disableReason) {
56202               return _t('operations.extract.' + disableReason + '.' + _amount);
56203             } else {
56204               return _t('operations.extract.description.' + _geometryID + '.' + _amount);
56205             }
56206           };
56207
56208           operation.annotation = function () {
56209             return _t('operations.extract.annotation', {
56210               n: selectedIDs.length
56211             });
56212           };
56213
56214           operation.id = 'extract';
56215           operation.keys = [_t('operations.extract.key')];
56216           operation.title = _t('operations.extract.title');
56217           operation.behavior = behaviorOperation(context).which(operation);
56218           return operation;
56219         }
56220
56221         function operationMerge(context, selectedIDs) {
56222           var _action = getAction();
56223
56224           function getAction() {
56225             // prefer a non-disabled action first
56226             var join = actionJoin(selectedIDs);
56227             if (!join.disabled(context.graph())) return join;
56228             var merge = actionMerge(selectedIDs);
56229             if (!merge.disabled(context.graph())) return merge;
56230             var mergePolygon = actionMergePolygon(selectedIDs);
56231             if (!mergePolygon.disabled(context.graph())) return mergePolygon;
56232             var mergeNodes = actionMergeNodes(selectedIDs);
56233             if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
56234
56235             if (join.disabled(context.graph()) !== 'not_eligible') return join;
56236             if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
56237             if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
56238             return mergeNodes;
56239           }
56240
56241           var operation = function operation() {
56242             if (operation.disabled()) return;
56243             context.perform(_action, operation.annotation());
56244             context.validator().validate();
56245             var resultIDs = selectedIDs.filter(context.hasEntity);
56246
56247             if (resultIDs.length > 1) {
56248               var interestingIDs = resultIDs.filter(function (id) {
56249                 return context.entity(id).hasInterestingTags();
56250               });
56251               if (interestingIDs.length) resultIDs = interestingIDs;
56252             }
56253
56254             context.enter(modeSelect(context, resultIDs));
56255           };
56256
56257           operation.available = function () {
56258             return selectedIDs.length >= 2;
56259           };
56260
56261           operation.disabled = function () {
56262             var actionDisabled = _action.disabled(context.graph());
56263
56264             if (actionDisabled) return actionDisabled;
56265             var osm = context.connection();
56266
56267             if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
56268               return 'too_many_vertices';
56269             }
56270
56271             return false;
56272           };
56273
56274           operation.tooltip = function () {
56275             var disabled = operation.disabled();
56276
56277             if (disabled) {
56278               if (disabled === 'restriction') {
56279                 return _t('operations.merge.restriction', {
56280                   relation: _mainPresetIndex.item('type/restriction').name()
56281                 });
56282               }
56283
56284               return _t('operations.merge.' + disabled);
56285             }
56286
56287             return _t('operations.merge.description');
56288           };
56289
56290           operation.annotation = function () {
56291             return _t('operations.merge.annotation', {
56292               n: selectedIDs.length
56293             });
56294           };
56295
56296           operation.id = 'merge';
56297           operation.keys = [_t('operations.merge.key')];
56298           operation.title = _t('operations.merge.title');
56299           operation.behavior = behaviorOperation(context).which(operation);
56300           return operation;
56301         }
56302
56303         function operationPaste(context) {
56304           var _pastePoint;
56305
56306           var operation = function operation() {
56307             if (!_pastePoint) return;
56308             var oldIDs = context.copyIDs();
56309             if (!oldIDs.length) return;
56310             var projection = context.projection;
56311             var extent = geoExtent();
56312             var oldGraph = context.copyGraph();
56313             var newIDs = [];
56314             var action = actionCopyEntities(oldIDs, oldGraph);
56315             context.perform(action);
56316             var copies = action.copies();
56317             var originals = new Set();
56318             Object.values(copies).forEach(function (entity) {
56319               originals.add(entity.id);
56320             });
56321
56322             for (var id in copies) {
56323               var oldEntity = oldGraph.entity(id);
56324               var newEntity = copies[id];
56325
56326               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
56327
56328
56329               var parents = context.graph().parentWays(newEntity);
56330               var parentCopied = parents.some(function (parent) {
56331                 return originals.has(parent.id);
56332               });
56333
56334               if (!parentCopied) {
56335                 newIDs.push(newEntity.id);
56336               }
56337             } // Use the location of the copy operation to offset the paste location,
56338             // or else use the center of the pasted extent
56339
56340
56341             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
56342             var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
56343
56344             context.replace(actionMove(newIDs, delta, projection), operation.annotation());
56345             context.enter(modeSelect(context, newIDs));
56346           };
56347
56348           operation.point = function (val) {
56349             _pastePoint = val;
56350             return operation;
56351           };
56352
56353           operation.available = function () {
56354             return context.mode().id === 'browse';
56355           };
56356
56357           operation.disabled = function () {
56358             return !context.copyIDs().length;
56359           };
56360
56361           operation.tooltip = function () {
56362             var oldGraph = context.copyGraph();
56363             var ids = context.copyIDs();
56364
56365             if (!ids.length) {
56366               return _t('operations.paste.nothing_copied');
56367             }
56368
56369             return _t('operations.paste.description', {
56370               feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
56371               n: ids.length
56372             });
56373           };
56374
56375           operation.annotation = function () {
56376             var ids = context.copyIDs();
56377             return _t('operations.paste.annotation', {
56378               n: ids.length
56379             });
56380           };
56381
56382           operation.id = 'paste';
56383           operation.keys = [uiCmd('⌘V')];
56384           operation.title = _t('operations.paste.title');
56385           return operation;
56386         }
56387
56388         function operationReverse(context, selectedIDs) {
56389           var operation = function operation() {
56390             context.perform(function combinedReverseAction(graph) {
56391               actions().forEach(function (action) {
56392                 graph = action(graph);
56393               });
56394               return graph;
56395             }, operation.annotation());
56396             context.validator().validate();
56397           };
56398
56399           function actions(situation) {
56400             return selectedIDs.map(function (entityID) {
56401               var entity = context.hasEntity(entityID);
56402               if (!entity) return null;
56403
56404               if (situation === 'toolbar') {
56405                 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
56406               }
56407
56408               var geometry = entity.geometry(context.graph());
56409               if (entity.type !== 'node' && geometry !== 'line') return null;
56410               var action = actionReverse(entityID);
56411               if (action.disabled(context.graph())) return null;
56412               return action;
56413             }).filter(Boolean);
56414           }
56415
56416           function reverseTypeID() {
56417             var acts = actions();
56418             var nodeActionCount = acts.filter(function (act) {
56419               var entity = context.hasEntity(act.entityID());
56420               return entity && entity.type === 'node';
56421             }).length;
56422             if (nodeActionCount === 0) return 'line';
56423             if (nodeActionCount === acts.length) return 'point';
56424             return 'feature';
56425           }
56426
56427           operation.available = function (situation) {
56428             return actions(situation).length > 0;
56429           };
56430
56431           operation.disabled = function () {
56432             return false;
56433           };
56434
56435           operation.tooltip = function () {
56436             return _t('operations.reverse.description.' + reverseTypeID());
56437           };
56438
56439           operation.annotation = function () {
56440             var acts = actions();
56441             return _t('operations.reverse.annotation.' + reverseTypeID(), {
56442               n: acts.length
56443             });
56444           };
56445
56446           operation.id = 'reverse';
56447           operation.keys = [_t('operations.reverse.key')];
56448           operation.title = _t('operations.reverse.title');
56449           operation.behavior = behaviorOperation(context).which(operation);
56450           return operation;
56451         }
56452
56453         function operationSplit(context, selectedIDs) {
56454           var _vertexIds = selectedIDs.filter(function (id) {
56455             return context.graph().geometry(id) === 'vertex';
56456           });
56457
56458           var _selectedWayIds = selectedIDs.filter(function (id) {
56459             var entity = context.graph().hasEntity(id);
56460             return entity && entity.type === 'way';
56461           });
56462
56463           var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
56464
56465           var _action = actionSplit(_vertexIds);
56466
56467           var _ways = [];
56468           var _geometry = 'feature';
56469           var _waysAmount = 'single';
56470
56471           var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
56472
56473           if (_isAvailable) {
56474             if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
56475             _ways = _action.ways(context.graph());
56476             var geometries = {};
56477
56478             _ways.forEach(function (way) {
56479               geometries[way.geometry(context.graph())] = true;
56480             });
56481
56482             if (Object.keys(geometries).length === 1) {
56483               _geometry = Object.keys(geometries)[0];
56484             }
56485
56486             _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
56487           }
56488
56489           var operation = function operation() {
56490             var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
56491
56492             var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
56493               // filter out relations that may have had member additions
56494               return context.entity(id).type === 'way';
56495             }));
56496
56497             context.enter(modeSelect(context, idsToSelect));
56498           };
56499
56500           operation.relatedEntityIds = function () {
56501             return _selectedWayIds.length ? [] : _ways.map(function (way) {
56502               return way.id;
56503             });
56504           };
56505
56506           operation.available = function () {
56507             return _isAvailable;
56508           };
56509
56510           operation.disabled = function () {
56511             var reason = _action.disabled(context.graph());
56512
56513             if (reason) {
56514               return reason;
56515             } else if (selectedIDs.some(context.hasHiddenConnections)) {
56516               return 'connected_to_hidden';
56517             }
56518
56519             return false;
56520           };
56521
56522           operation.tooltip = function () {
56523             var disable = operation.disabled();
56524             if (disable) return _t('operations.split.' + disable);
56525             return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
56526           };
56527
56528           operation.annotation = function () {
56529             return _t('operations.split.annotation.' + _geometry, {
56530               n: _ways.length
56531             });
56532           };
56533
56534           operation.id = 'split';
56535           operation.keys = [_t('operations.split.key')];
56536           operation.title = _t('operations.split.title');
56537           operation.behavior = behaviorOperation(context).which(operation);
56538           return operation;
56539         }
56540
56541         function operationStraighten(context, selectedIDs) {
56542           var _wayIDs = selectedIDs.filter(function (id) {
56543             return id.charAt(0) === 'w';
56544           });
56545
56546           var _nodeIDs = selectedIDs.filter(function (id) {
56547             return id.charAt(0) === 'n';
56548           });
56549
56550           var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
56551
56552           var _nodes = utilGetAllNodes(selectedIDs, context.graph());
56553
56554           var _coords = _nodes.map(function (n) {
56555             return n.loc;
56556           });
56557
56558           var _extent = utilTotalExtent(selectedIDs, context.graph());
56559
56560           var _action = chooseAction();
56561
56562           var _geometry;
56563
56564           function chooseAction() {
56565             // straighten selected nodes
56566             if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
56567               _geometry = 'point';
56568               return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
56569             } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
56570               var startNodeIDs = [];
56571               var endNodeIDs = [];
56572
56573               for (var i = 0; i < selectedIDs.length; i++) {
56574                 var entity = context.entity(selectedIDs[i]);
56575
56576                 if (entity.type === 'node') {
56577                   continue;
56578                 } else if (entity.type !== 'way' || entity.isClosed()) {
56579                   return null; // exit early, can't straighten these
56580                 }
56581
56582                 startNodeIDs.push(entity.first());
56583                 endNodeIDs.push(entity.last());
56584               } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
56585
56586
56587               startNodeIDs = startNodeIDs.filter(function (n) {
56588                 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
56589               });
56590               endNodeIDs = endNodeIDs.filter(function (n) {
56591                 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
56592               }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
56593
56594               if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
56595
56596               var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
56597                 return node.id;
56598               });
56599               if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
56600
56601               if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
56602
56603               if (_nodeIDs.length) {
56604                 // If we're only straightenting between two points, we only need that extent visible
56605                 _extent = utilTotalExtent(_nodeIDs, context.graph());
56606               }
56607
56608               _geometry = 'line';
56609               return actionStraightenWay(selectedIDs, context.projection);
56610             }
56611
56612             return null;
56613           }
56614
56615           function operation() {
56616             if (!_action) return;
56617             context.perform(_action, operation.annotation());
56618             window.setTimeout(function () {
56619               context.validator().validate();
56620             }, 300); // after any transition
56621           }
56622
56623           operation.available = function () {
56624             return Boolean(_action);
56625           };
56626
56627           operation.disabled = function () {
56628             var reason = _action.disabled(context.graph());
56629
56630             if (reason) {
56631               return reason;
56632             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
56633               return 'too_large';
56634             } else if (someMissing()) {
56635               return 'not_downloaded';
56636             } else if (selectedIDs.some(context.hasHiddenConnections)) {
56637               return 'connected_to_hidden';
56638             }
56639
56640             return false;
56641
56642             function someMissing() {
56643               if (context.inIntro()) return false;
56644               var osm = context.connection();
56645
56646               if (osm) {
56647                 var missing = _coords.filter(function (loc) {
56648                   return !osm.isDataLoaded(loc);
56649                 });
56650
56651                 if (missing.length) {
56652                   missing.forEach(function (loc) {
56653                     context.loadTileAtLoc(loc);
56654                   });
56655                   return true;
56656                 }
56657               }
56658
56659               return false;
56660             }
56661           };
56662
56663           operation.tooltip = function () {
56664             var disable = operation.disabled();
56665             return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
56666           };
56667
56668           operation.annotation = function () {
56669             return _t('operations.straighten.annotation.' + _geometry, {
56670               n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
56671             });
56672           };
56673
56674           operation.id = 'straighten';
56675           operation.keys = [_t('operations.straighten.key')];
56676           operation.title = _t('operations.straighten.title');
56677           operation.behavior = behaviorOperation(context).which(operation);
56678           return operation;
56679         }
56680
56681         var Operations = /*#__PURE__*/Object.freeze({
56682                 __proto__: null,
56683                 operationCircularize: operationCircularize,
56684                 operationContinue: operationContinue,
56685                 operationCopy: operationCopy,
56686                 operationDelete: operationDelete,
56687                 operationDisconnect: operationDisconnect,
56688                 operationDowngrade: operationDowngrade,
56689                 operationExtract: operationExtract,
56690                 operationMerge: operationMerge,
56691                 operationMove: operationMove,
56692                 operationOrthogonalize: operationOrthogonalize,
56693                 operationPaste: operationPaste,
56694                 operationReflectShort: operationReflectShort,
56695                 operationReflectLong: operationReflectLong,
56696                 operationReverse: operationReverse,
56697                 operationRotate: operationRotate,
56698                 operationSplit: operationSplit,
56699                 operationStraighten: operationStraighten
56700         });
56701
56702         var _relatedParent;
56703
56704         function modeSelect(context, selectedIDs) {
56705           var mode = {
56706             id: 'select',
56707             button: 'browse'
56708           };
56709           var keybinding = utilKeybinding('select');
56710
56711           var _breatheBehavior = behaviorBreathe();
56712
56713           var _modeDragNode = modeDragNode(context);
56714
56715           var _selectBehavior;
56716
56717           var _behaviors = [];
56718           var _operations = [];
56719           var _newFeature = false;
56720           var _follow = false;
56721
56722           function singular() {
56723             if (selectedIDs && selectedIDs.length === 1) {
56724               return context.hasEntity(selectedIDs[0]);
56725             }
56726           }
56727
56728           function selectedEntities() {
56729             return selectedIDs.map(function (id) {
56730               return context.hasEntity(id);
56731             }).filter(Boolean);
56732           }
56733
56734           function checkSelectedIDs() {
56735             var ids = [];
56736
56737             if (Array.isArray(selectedIDs)) {
56738               ids = selectedIDs.filter(function (id) {
56739                 return context.hasEntity(id);
56740               });
56741             }
56742
56743             if (!ids.length) {
56744               context.enter(modeBrowse(context));
56745               return false;
56746             } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
56747               // switch between single- and multi-select UI
56748               context.enter(modeSelect(context, ids));
56749               return false;
56750             }
56751
56752             selectedIDs = ids;
56753             return true;
56754           } // find the common parent ways for nextVertex, previousVertex
56755
56756
56757           function commonParents() {
56758             var graph = context.graph();
56759             var commonParents = [];
56760
56761             for (var i = 0; i < selectedIDs.length; i++) {
56762               var entity = context.hasEntity(selectedIDs[i]);
56763
56764               if (!entity || entity.geometry(graph) !== 'vertex') {
56765                 return []; // selection includes some not vertices
56766               }
56767
56768               var currParents = graph.parentWays(entity).map(function (w) {
56769                 return w.id;
56770               });
56771
56772               if (!commonParents.length) {
56773                 commonParents = currParents;
56774                 continue;
56775               }
56776
56777               commonParents = utilArrayIntersection(commonParents, currParents);
56778
56779               if (!commonParents.length) {
56780                 return [];
56781               }
56782             }
56783
56784             return commonParents;
56785           }
56786
56787           function singularParent() {
56788             var parents = commonParents();
56789
56790             if (!parents || parents.length === 0) {
56791               _relatedParent = null;
56792               return null;
56793             } // relatedParent is used when we visit a vertex with multiple
56794             // parents, and we want to remember which parent line we started on.
56795
56796
56797             if (parents.length === 1) {
56798               _relatedParent = parents[0]; // remember this parent for later
56799
56800               return _relatedParent;
56801             }
56802
56803             if (parents.indexOf(_relatedParent) !== -1) {
56804               return _relatedParent; // prefer the previously seen parent
56805             }
56806
56807             return parents[0];
56808           }
56809
56810           mode.selectedIDs = function (val) {
56811             if (!arguments.length) return selectedIDs;
56812             selectedIDs = val;
56813             return mode;
56814           };
56815
56816           mode.zoomToSelected = function () {
56817             context.map().zoomToEase(selectedEntities());
56818           };
56819
56820           mode.newFeature = function (val) {
56821             if (!arguments.length) return _newFeature;
56822             _newFeature = val;
56823             return mode;
56824           };
56825
56826           mode.selectBehavior = function (val) {
56827             if (!arguments.length) return _selectBehavior;
56828             _selectBehavior = val;
56829             return mode;
56830           };
56831
56832           mode.follow = function (val) {
56833             if (!arguments.length) return _follow;
56834             _follow = val;
56835             return mode;
56836           };
56837
56838           function loadOperations() {
56839             _operations.forEach(function (operation) {
56840               if (operation.behavior) {
56841                 context.uninstall(operation.behavior);
56842               }
56843             });
56844
56845             _operations = Object.values(Operations).map(function (o) {
56846               return o(context, selectedIDs);
56847             }).filter(function (o) {
56848               return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
56849             }).concat([// group copy/downgrade/delete operation together at the end of the list
56850             operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
56851               return operation.available();
56852             });
56853
56854             _operations.forEach(function (operation) {
56855               if (operation.behavior) {
56856                 context.install(operation.behavior);
56857               }
56858             }); // remove any displayed menu
56859
56860
56861             context.ui().closeEditMenu();
56862           }
56863
56864           mode.operations = function () {
56865             return _operations;
56866           };
56867
56868           mode.enter = function () {
56869             if (!checkSelectedIDs()) return;
56870             context.features().forceVisible(selectedIDs);
56871
56872             _modeDragNode.restoreSelectedIDs(selectedIDs);
56873
56874             loadOperations();
56875
56876             if (!_behaviors.length) {
56877               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
56878               _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
56879             }
56880
56881             _behaviors.forEach(context.install);
56882
56883             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) {
56884               return uiCmd('⇧' + key);
56885             }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
56886               return uiCmd('⇧⌥' + key);
56887             }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
56888               return uiCmd('⇧' + key);
56889             }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
56890               return uiCmd('⇧⌥' + key);
56891             }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], nextParent).on('⎋', esc, true);
56892             select(document).call(keybinding);
56893             context.ui().sidebar.select(selectedIDs, _newFeature);
56894             context.history().on('change.select', function () {
56895               loadOperations(); // reselect after change in case relation members were removed or added
56896
56897               selectElements();
56898             }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
56899             context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
56900               selectElements();
56901
56902               _breatheBehavior.restartIfNeeded(context.surface());
56903             });
56904             context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
56905             selectElements();
56906
56907             if (_follow) {
56908               var extent = geoExtent();
56909               var graph = context.graph();
56910               selectedIDs.forEach(function (id) {
56911                 var entity = context.entity(id);
56912
56913                 extent._extend(entity.extent(graph));
56914               });
56915               var loc = extent.center();
56916               context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
56917
56918               _follow = false;
56919             }
56920
56921             function nudgeSelection(delta) {
56922               return function () {
56923                 // prevent nudging during low zoom selection
56924                 if (!context.map().withinEditableZoom()) return;
56925                 var moveOp = operationMove(context, selectedIDs);
56926
56927                 if (moveOp.disabled()) {
56928                   context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
56929                 } else {
56930                   context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
56931                   context.validator().validate();
56932                 }
56933               };
56934             }
56935
56936             function scaleSelection(factor) {
56937               return function () {
56938                 // prevent scaling during low zoom selection
56939                 if (!context.map().withinEditableZoom()) return;
56940                 var nodes = utilGetAllNodes(selectedIDs, context.graph());
56941                 var isUp = factor > 1; // can only scale if multiple nodes are selected
56942
56943                 if (nodes.length <= 1) return;
56944                 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
56945                 // object, but we don't want an actual scale operation at this point.
56946
56947                 function scalingDisabled() {
56948                   if (tooSmall()) {
56949                     return 'too_small';
56950                   } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
56951                     return 'too_large';
56952                   } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
56953                     return 'not_downloaded';
56954                   } else if (selectedIDs.some(context.hasHiddenConnections)) {
56955                     return 'connected_to_hidden';
56956                   }
56957
56958                   return false;
56959
56960                   function tooSmall() {
56961                     if (isUp) return false;
56962                     var dLon = Math.abs(extent[1][0] - extent[0][0]);
56963                     var dLat = Math.abs(extent[1][1] - extent[0][1]);
56964                     return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
56965                   }
56966
56967                   function someMissing() {
56968                     if (context.inIntro()) return false;
56969                     var osm = context.connection();
56970
56971                     if (osm) {
56972                       var missing = nodes.filter(function (n) {
56973                         return !osm.isDataLoaded(n.loc);
56974                       });
56975
56976                       if (missing.length) {
56977                         missing.forEach(function (loc) {
56978                           context.loadTileAtLoc(loc);
56979                         });
56980                         return true;
56981                       }
56982                     }
56983
56984                     return false;
56985                   }
56986
56987                   function incompleteRelation(id) {
56988                     var entity = context.entity(id);
56989                     return entity.type === 'relation' && !entity.isComplete(context.graph());
56990                   }
56991                 }
56992
56993                 var disabled = scalingDisabled();
56994
56995                 if (disabled) {
56996                   var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
56997                   context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
56998                 } else {
56999                   var pivot = context.projection(extent.center());
57000                   var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
57001                     n: selectedIDs.length
57002                   });
57003                   context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
57004                   context.validator().validate();
57005                 }
57006               };
57007             }
57008
57009             function didDoubleUp(d3_event, loc) {
57010               if (!context.map().withinEditableZoom()) return;
57011               var target = select(d3_event.target);
57012               var datum = target.datum();
57013               var entity = datum && datum.properties && datum.properties.entity;
57014               if (!entity) return;
57015
57016               if (entity instanceof osmWay && target.classed('target')) {
57017                 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
57018                 var prev = entity.nodes[choice.index - 1];
57019                 var next = entity.nodes[choice.index];
57020                 context.perform(actionAddMidpoint({
57021                   loc: choice.loc,
57022                   edge: [prev, next]
57023                 }, osmNode()), _t('operations.add.annotation.vertex'));
57024               } else if (entity.type === 'midpoint') {
57025                 context.perform(actionAddMidpoint({
57026                   loc: entity.loc,
57027                   edge: entity.edge
57028                 }, osmNode()), _t('operations.add.annotation.vertex'));
57029               }
57030             }
57031
57032             function selectElements() {
57033               if (!checkSelectedIDs()) return;
57034               var surface = context.surface();
57035               surface.selectAll('.selected-member').classed('selected-member', false);
57036               surface.selectAll('.selected').classed('selected', false);
57037               surface.selectAll('.related').classed('related', false);
57038               singularParent();
57039
57040               if (_relatedParent) {
57041                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
57042               }
57043
57044               if (context.map().withinEditableZoom()) {
57045                 // Apply selection styling if not in wide selection
57046                 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
57047                 /* skipMultipolgonMembers */
57048                 )).classed('selected-member', true);
57049                 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
57050               }
57051             }
57052
57053             function esc() {
57054               if (context.container().select('.combobox').size()) return;
57055               context.enter(modeBrowse(context));
57056             }
57057
57058             function firstVertex(d3_event) {
57059               d3_event.preventDefault();
57060               var entity = singular();
57061               var parent = singularParent();
57062               var way;
57063
57064               if (entity && entity.type === 'way') {
57065                 way = entity;
57066               } else if (parent) {
57067                 way = context.entity(parent);
57068               }
57069
57070               if (way) {
57071                 context.enter(modeSelect(context, [way.first()]).follow(true));
57072               }
57073             }
57074
57075             function lastVertex(d3_event) {
57076               d3_event.preventDefault();
57077               var entity = singular();
57078               var parent = singularParent();
57079               var way;
57080
57081               if (entity && entity.type === 'way') {
57082                 way = entity;
57083               } else if (parent) {
57084                 way = context.entity(parent);
57085               }
57086
57087               if (way) {
57088                 context.enter(modeSelect(context, [way.last()]).follow(true));
57089               }
57090             }
57091
57092             function previousVertex(d3_event) {
57093               d3_event.preventDefault();
57094               var parent = singularParent();
57095               if (!parent) return;
57096               var way = context.entity(parent);
57097               var length = way.nodes.length;
57098               var curr = way.nodes.indexOf(selectedIDs[0]);
57099               var index = -1;
57100
57101               if (curr > 0) {
57102                 index = curr - 1;
57103               } else if (way.isClosed()) {
57104                 index = length - 2;
57105               }
57106
57107               if (index !== -1) {
57108                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
57109               }
57110             }
57111
57112             function nextVertex(d3_event) {
57113               d3_event.preventDefault();
57114               var parent = singularParent();
57115               if (!parent) return;
57116               var way = context.entity(parent);
57117               var length = way.nodes.length;
57118               var curr = way.nodes.indexOf(selectedIDs[0]);
57119               var index = -1;
57120
57121               if (curr < length - 1) {
57122                 index = curr + 1;
57123               } else if (way.isClosed()) {
57124                 index = 0;
57125               }
57126
57127               if (index !== -1) {
57128                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
57129               }
57130             }
57131
57132             function nextParent(d3_event) {
57133               d3_event.preventDefault();
57134               var parents = commonParents();
57135               if (!parents || parents.length < 2) return;
57136               var index = parents.indexOf(_relatedParent);
57137
57138               if (index < 0 || index > parents.length - 2) {
57139                 _relatedParent = parents[0];
57140               } else {
57141                 _relatedParent = parents[index + 1];
57142               }
57143
57144               var surface = context.surface();
57145               surface.selectAll('.related').classed('related', false);
57146
57147               if (_relatedParent) {
57148                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
57149               }
57150             }
57151           };
57152
57153           mode.exit = function () {
57154             _newFeature = false;
57155
57156             _operations.forEach(function (operation) {
57157               if (operation.behavior) {
57158                 context.uninstall(operation.behavior);
57159               }
57160             });
57161
57162             _operations = [];
57163
57164             _behaviors.forEach(context.uninstall);
57165
57166             select(document).call(keybinding.unbind);
57167             context.ui().closeEditMenu();
57168             context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
57169             var surface = context.surface();
57170             surface.selectAll('.selected-member').classed('selected-member', false);
57171             surface.selectAll('.selected').classed('selected', false);
57172             surface.selectAll('.highlighted').classed('highlighted', false);
57173             surface.selectAll('.related').classed('related', false);
57174             context.map().on('drawn.select', null);
57175             context.ui().sidebar.hide();
57176             context.features().forceVisible([]);
57177             var entity = singular();
57178
57179             if (_newFeature && entity && entity.type === 'relation' && // no tags
57180             Object.keys(entity.tags).length === 0 && // no parent relations
57181             context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
57182             entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
57183               // the user added this relation but didn't edit it at all, so just delete it
57184               var deleteAction = actionDeleteRelation(entity.id, true
57185               /* don't delete untagged members */
57186               );
57187               context.perform(deleteAction, _t('operations.delete.annotation.relation'));
57188             }
57189           };
57190
57191           return mode;
57192         }
57193
57194         function uiLasso(context) {
57195           var group, polygon;
57196           lasso.coordinates = [];
57197
57198           function lasso(selection) {
57199             context.container().classed('lasso', true);
57200             group = selection.append('g').attr('class', 'lasso hide');
57201             polygon = group.append('path').attr('class', 'lasso-path');
57202             group.call(uiToggle(true));
57203           }
57204
57205           function draw() {
57206             if (polygon) {
57207               polygon.data([lasso.coordinates]).attr('d', function (d) {
57208                 return 'M' + d.join(' L') + ' Z';
57209               });
57210             }
57211           }
57212
57213           lasso.extent = function () {
57214             return lasso.coordinates.reduce(function (extent, point) {
57215               return extent.extend(geoExtent(point));
57216             }, geoExtent());
57217           };
57218
57219           lasso.p = function (_) {
57220             if (!arguments.length) return lasso;
57221             lasso.coordinates.push(_);
57222             draw();
57223             return lasso;
57224           };
57225
57226           lasso.close = function () {
57227             if (group) {
57228               group.call(uiToggle(false, function () {
57229                 select(this).remove();
57230               }));
57231             }
57232
57233             context.container().classed('lasso', false);
57234           };
57235
57236           return lasso;
57237         }
57238
57239         function behaviorLasso(context) {
57240           // use pointer events on supported platforms; fallback to mouse events
57241           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
57242
57243           var behavior = function behavior(selection) {
57244             var lasso;
57245
57246             function pointerdown(d3_event) {
57247               var button = 0; // left
57248
57249               if (d3_event.button === button && d3_event.shiftKey === true) {
57250                 lasso = null;
57251                 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
57252                 d3_event.stopPropagation();
57253               }
57254             }
57255
57256             function pointermove() {
57257               if (!lasso) {
57258                 lasso = uiLasso(context);
57259                 context.surface().call(lasso);
57260               }
57261
57262               lasso.p(context.map().mouse());
57263             }
57264
57265             function normalize(a, b) {
57266               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])]];
57267             }
57268
57269             function lassoed() {
57270               if (!lasso) return [];
57271               var graph = context.graph();
57272               var limitToNodes;
57273
57274               if (context.map().editableDataEnabled(true
57275               /* skipZoomCheck */
57276               ) && context.map().isInWideSelection()) {
57277                 // only select from the visible nodes
57278                 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
57279               } else if (!context.map().editableDataEnabled()) {
57280                 return [];
57281               }
57282
57283               var bounds = lasso.extent().map(context.projection.invert);
57284               var extent = geoExtent(normalize(bounds[0], bounds[1]));
57285               var intersects = context.history().intersects(extent).filter(function (entity) {
57286                 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
57287               }); // sort the lassoed nodes as best we can
57288
57289               intersects.sort(function (node1, node2) {
57290                 var parents1 = graph.parentWays(node1);
57291                 var parents2 = graph.parentWays(node2);
57292
57293                 if (parents1.length && parents2.length) {
57294                   // both nodes are vertices
57295                   var sharedParents = utilArrayIntersection(parents1, parents2);
57296
57297                   if (sharedParents.length) {
57298                     var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
57299
57300                     return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
57301                   } else {
57302                     // vertices do not share a way; group them by their respective parent ways
57303                     return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
57304                   }
57305                 } else if (parents1.length || parents2.length) {
57306                   // only one node is a vertex; sort standalone points before vertices
57307                   return parents1.length - parents2.length;
57308                 } // both nodes are standalone points; sort left to right
57309
57310
57311                 return node1.loc[0] - node2.loc[0];
57312               });
57313               return intersects.map(function (entity) {
57314                 return entity.id;
57315               });
57316             }
57317
57318             function pointerup() {
57319               select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
57320               if (!lasso) return;
57321               var ids = lassoed();
57322               lasso.close();
57323
57324               if (ids.length) {
57325                 context.enter(modeSelect(context, ids));
57326               }
57327             }
57328
57329             selection.on(_pointerPrefix + 'down.lasso', pointerdown);
57330           };
57331
57332           behavior.off = function (selection) {
57333             selection.on(_pointerPrefix + 'down.lasso', null);
57334           };
57335
57336           return behavior;
57337         }
57338
57339         function modeBrowse(context) {
57340           var mode = {
57341             button: 'browse',
57342             id: 'browse',
57343             title: _t('modes.browse.title'),
57344             description: _t('modes.browse.description')
57345           };
57346           var sidebar;
57347
57348           var _selectBehavior;
57349
57350           var _behaviors = [];
57351
57352           mode.selectBehavior = function (val) {
57353             if (!arguments.length) return _selectBehavior;
57354             _selectBehavior = val;
57355             return mode;
57356           };
57357
57358           mode.enter = function () {
57359             if (!_behaviors.length) {
57360               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
57361               _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
57362             }
57363
57364             _behaviors.forEach(context.install); // Get focus on the body.
57365
57366
57367             if (document.activeElement && document.activeElement.blur) {
57368               document.activeElement.blur();
57369             }
57370
57371             if (sidebar) {
57372               context.ui().sidebar.show(sidebar);
57373             } else {
57374               context.ui().sidebar.select(null);
57375             }
57376           };
57377
57378           mode.exit = function () {
57379             context.ui().sidebar.hover.cancel();
57380
57381             _behaviors.forEach(context.uninstall);
57382
57383             if (sidebar) {
57384               context.ui().sidebar.hide();
57385             }
57386           };
57387
57388           mode.sidebar = function (_) {
57389             if (!arguments.length) return sidebar;
57390             sidebar = _;
57391             return mode;
57392           };
57393
57394           mode.operations = function () {
57395             return [operationPaste(context)];
57396           };
57397
57398           return mode;
57399         }
57400
57401         function behaviorAddWay(context) {
57402           var dispatch$1 = dispatch('start', 'startFromWay', 'startFromNode');
57403           var draw = behaviorDraw(context);
57404
57405           function behavior(surface) {
57406             draw.on('click', function () {
57407               dispatch$1.apply('start', this, arguments);
57408             }).on('clickWay', function () {
57409               dispatch$1.apply('startFromWay', this, arguments);
57410             }).on('clickNode', function () {
57411               dispatch$1.apply('startFromNode', this, arguments);
57412             }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
57413             context.map().dblclickZoomEnable(false);
57414             surface.call(draw);
57415           }
57416
57417           behavior.off = function (surface) {
57418             surface.call(draw.off);
57419           };
57420
57421           behavior.cancel = function () {
57422             window.setTimeout(function () {
57423               context.map().dblclickZoomEnable(true);
57424             }, 1000);
57425             context.enter(modeBrowse(context));
57426           };
57427
57428           return utilRebind(behavior, dispatch$1, 'on');
57429         }
57430
57431         function behaviorHash(context) {
57432           // cached window.location.hash
57433           var _cachedHash = null; // allowable latitude range
57434
57435           var _latitudeLimit = 90 - 1e-8;
57436
57437           function computedHashParameters() {
57438             var map = context.map();
57439             var center = map.center();
57440             var zoom = map.zoom();
57441             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
57442             var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
57443             var newParams = {};
57444             delete oldParams.id;
57445             var selected = context.selectedIDs().filter(function (id) {
57446               return context.hasEntity(id);
57447             });
57448
57449             if (selected.length) {
57450               newParams.id = selected.join(',');
57451             }
57452
57453             newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
57454             return Object.assign(oldParams, newParams);
57455           }
57456
57457           function computedHash() {
57458             return '#' + utilQsString(computedHashParameters(), true);
57459           }
57460
57461           function computedTitle(includeChangeCount) {
57462             var baseTitle = context.documentTitleBase() || 'iD';
57463             var contextual;
57464             var changeCount;
57465             var titleID;
57466             var selected = context.selectedIDs().filter(function (id) {
57467               return context.hasEntity(id);
57468             });
57469
57470             if (selected.length) {
57471               var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
57472
57473               if (selected.length > 1) {
57474                 contextual = _t('title.labeled_and_more', {
57475                   labeled: firstLabel,
57476                   count: selected.length - 1
57477                 });
57478               } else {
57479                 contextual = firstLabel;
57480               }
57481
57482               titleID = 'context';
57483             }
57484
57485             if (includeChangeCount) {
57486               changeCount = context.history().difference().summary().length;
57487
57488               if (changeCount > 0) {
57489                 titleID = contextual ? 'changes_context' : 'changes';
57490               }
57491             }
57492
57493             if (titleID) {
57494               return _t('title.format.' + titleID, {
57495                 changes: changeCount,
57496                 base: baseTitle,
57497                 context: contextual
57498               });
57499             }
57500
57501             return baseTitle;
57502           }
57503
57504           function updateTitle(includeChangeCount) {
57505             if (!context.setsDocumentTitle()) return;
57506             var newTitle = computedTitle(includeChangeCount);
57507
57508             if (document.title !== newTitle) {
57509               document.title = newTitle;
57510             }
57511           }
57512
57513           function updateHashIfNeeded() {
57514             if (context.inIntro()) return;
57515             var latestHash = computedHash();
57516
57517             if (_cachedHash !== latestHash) {
57518               _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
57519               // though unavoidably creating a browser history entry
57520
57521               window.history.replaceState(null, computedTitle(false
57522               /* includeChangeCount */
57523               ), latestHash); // set the title we want displayed for the browser tab/window
57524
57525               updateTitle(true
57526               /* includeChangeCount */
57527               );
57528             }
57529           }
57530
57531           var _throttledUpdate = throttle(updateHashIfNeeded, 500);
57532
57533           var _throttledUpdateTitle = throttle(function () {
57534             updateTitle(true
57535             /* includeChangeCount */
57536             );
57537           }, 500);
57538
57539           function hashchange() {
57540             // ignore spurious hashchange events
57541             if (window.location.hash === _cachedHash) return;
57542             _cachedHash = window.location.hash;
57543             var q = utilStringQs(_cachedHash);
57544             var mapArgs = (q.map || '').split('/').map(Number);
57545
57546             if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
57547               // replace bogus hash
57548               updateHashIfNeeded();
57549             } else {
57550               // don't update if the new hash already reflects the state of iD
57551               if (_cachedHash === computedHash()) return;
57552               var mode = context.mode();
57553               context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
57554
57555               if (q.id && mode) {
57556                 var ids = q.id.split(',').filter(function (id) {
57557                   return context.hasEntity(id);
57558                 });
57559
57560                 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
57561                   context.enter(modeSelect(context, ids));
57562                   return;
57563                 }
57564               }
57565
57566               var center = context.map().center();
57567               var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
57568               var maxdist = 500; // Don't allow the hash location to change too much while drawing
57569               // This can happen if the user accidentally hit the back button.  #3996
57570
57571               if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
57572                 context.enter(modeBrowse(context));
57573                 return;
57574               }
57575             }
57576           }
57577
57578           function behavior() {
57579             context.map().on('move.behaviorHash', _throttledUpdate);
57580             context.history().on('change.behaviorHash', _throttledUpdateTitle);
57581             context.on('enter.behaviorHash', _throttledUpdate);
57582             select(window).on('hashchange.behaviorHash', hashchange);
57583
57584             if (window.location.hash) {
57585               var q = utilStringQs(window.location.hash);
57586
57587               if (q.id) {
57588                 //if (!context.history().hasRestorableChanges()) {
57589                 // targeting specific features: download, select, and zoom to them
57590                 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
57591               }
57592
57593               if (q.walkthrough === 'true') {
57594                 behavior.startWalkthrough = true;
57595               }
57596
57597               if (q.map) {
57598                 behavior.hadHash = true;
57599               }
57600
57601               hashchange();
57602               updateTitle(false);
57603             }
57604           }
57605
57606           behavior.off = function () {
57607             _throttledUpdate.cancel();
57608
57609             _throttledUpdateTitle.cancel();
57610
57611             context.map().on('move.behaviorHash', null);
57612             context.on('enter.behaviorHash', null);
57613             select(window).on('hashchange.behaviorHash', null);
57614             window.location.hash = '';
57615           };
57616
57617           return behavior;
57618         }
57619
57620         /*
57621             iD.coreDifference represents the difference between two graphs.
57622             It knows how to calculate the set of entities that were
57623             created, modified, or deleted, and also contains the logic
57624             for recursively extending a difference to the complete set
57625             of entities that will require a redraw, taking into account
57626             child and parent relationships.
57627          */
57628
57629         function coreDifference(base, head) {
57630           var _changes = {};
57631           var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
57632
57633           var _diff = {};
57634
57635           function checkEntityID(id) {
57636             var h = head.entities[id];
57637             var b = base.entities[id];
57638             if (h === b) return;
57639             if (_changes[id]) return;
57640
57641             if (!h && b) {
57642               _changes[id] = {
57643                 base: b,
57644                 head: h
57645               };
57646               _didChange.deletion = true;
57647               return;
57648             }
57649
57650             if (h && !b) {
57651               _changes[id] = {
57652                 base: b,
57653                 head: h
57654               };
57655               _didChange.addition = true;
57656               return;
57657             }
57658
57659             if (h && b) {
57660               if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
57661                 _changes[id] = {
57662                   base: b,
57663                   head: h
57664                 };
57665                 _didChange.geometry = true;
57666                 _didChange.properties = true;
57667                 return;
57668               }
57669
57670               if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
57671                 _changes[id] = {
57672                   base: b,
57673                   head: h
57674                 };
57675                 _didChange.geometry = true;
57676               }
57677
57678               if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
57679                 _changes[id] = {
57680                   base: b,
57681                   head: h
57682                 };
57683                 _didChange.geometry = true;
57684               }
57685
57686               if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
57687                 _changes[id] = {
57688                   base: b,
57689                   head: h
57690                 };
57691                 _didChange.properties = true;
57692               }
57693             }
57694           }
57695
57696           function load() {
57697             // HOT CODE: there can be many thousands of downloaded entities, so looping
57698             // through them all can become a performance bottleneck. Optimize by
57699             // resolving duplicates and using a basic `for` loop
57700             var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
57701
57702             for (var i = 0; i < ids.length; i++) {
57703               checkEntityID(ids[i]);
57704             }
57705           }
57706
57707           load();
57708
57709           _diff.length = function length() {
57710             return Object.keys(_changes).length;
57711           };
57712
57713           _diff.changes = function changes() {
57714             return _changes;
57715           };
57716
57717           _diff.didChange = _didChange; // pass true to include affected relation members
57718
57719           _diff.extantIDs = function extantIDs(includeRelMembers) {
57720             var result = new Set();
57721             Object.keys(_changes).forEach(function (id) {
57722               if (_changes[id].head) {
57723                 result.add(id);
57724               }
57725
57726               var h = _changes[id].head;
57727               var b = _changes[id].base;
57728               var entity = h || b;
57729
57730               if (includeRelMembers && entity.type === 'relation') {
57731                 var mh = h ? h.members.map(function (m) {
57732                   return m.id;
57733                 }) : [];
57734                 var mb = b ? b.members.map(function (m) {
57735                   return m.id;
57736                 }) : [];
57737                 utilArrayUnion(mh, mb).forEach(function (memberID) {
57738                   if (head.hasEntity(memberID)) {
57739                     result.add(memberID);
57740                   }
57741                 });
57742               }
57743             });
57744             return Array.from(result);
57745           };
57746
57747           _diff.modified = function modified() {
57748             var result = [];
57749             Object.values(_changes).forEach(function (change) {
57750               if (change.base && change.head) {
57751                 result.push(change.head);
57752               }
57753             });
57754             return result;
57755           };
57756
57757           _diff.created = function created() {
57758             var result = [];
57759             Object.values(_changes).forEach(function (change) {
57760               if (!change.base && change.head) {
57761                 result.push(change.head);
57762               }
57763             });
57764             return result;
57765           };
57766
57767           _diff.deleted = function deleted() {
57768             var result = [];
57769             Object.values(_changes).forEach(function (change) {
57770               if (change.base && !change.head) {
57771                 result.push(change.base);
57772               }
57773             });
57774             return result;
57775           };
57776
57777           _diff.summary = function summary() {
57778             var relevant = {};
57779             var keys = Object.keys(_changes);
57780
57781             for (var i = 0; i < keys.length; i++) {
57782               var change = _changes[keys[i]];
57783
57784               if (change.head && change.head.geometry(head) !== 'vertex') {
57785                 addEntity(change.head, head, change.base ? 'modified' : 'created');
57786               } else if (change.base && change.base.geometry(base) !== 'vertex') {
57787                 addEntity(change.base, base, 'deleted');
57788               } else if (change.base && change.head) {
57789                 // modified vertex
57790                 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
57791                 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
57792
57793                 if (moved) {
57794                   addParents(change.head);
57795                 }
57796
57797                 if (retagged || moved && change.head.hasInterestingTags()) {
57798                   addEntity(change.head, head, 'modified');
57799                 }
57800               } else if (change.head && change.head.hasInterestingTags()) {
57801                 // created vertex
57802                 addEntity(change.head, head, 'created');
57803               } else if (change.base && change.base.hasInterestingTags()) {
57804                 // deleted vertex
57805                 addEntity(change.base, base, 'deleted');
57806               }
57807             }
57808
57809             return Object.values(relevant);
57810
57811             function addEntity(entity, graph, changeType) {
57812               relevant[entity.id] = {
57813                 entity: entity,
57814                 graph: graph,
57815                 changeType: changeType
57816               };
57817             }
57818
57819             function addParents(entity) {
57820               var parents = head.parentWays(entity);
57821
57822               for (var j = parents.length - 1; j >= 0; j--) {
57823                 var parent = parents[j];
57824
57825                 if (!(parent.id in relevant)) {
57826                   addEntity(parent, head, 'modified');
57827                 }
57828               }
57829             }
57830           }; // returns complete set of entities that require a redraw
57831           //  (optionally within given `extent`)
57832
57833
57834           _diff.complete = function complete(extent) {
57835             var result = {};
57836             var id, change;
57837
57838             for (id in _changes) {
57839               change = _changes[id];
57840               var h = change.head;
57841               var b = change.base;
57842               var entity = h || b;
57843               var i;
57844               if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) continue;
57845               result[id] = h;
57846
57847               if (entity.type === 'way') {
57848                 var nh = h ? h.nodes : [];
57849                 var nb = b ? b.nodes : [];
57850                 var diff;
57851                 diff = utilArrayDifference(nh, nb);
57852
57853                 for (i = 0; i < diff.length; i++) {
57854                   result[diff[i]] = head.hasEntity(diff[i]);
57855                 }
57856
57857                 diff = utilArrayDifference(nb, nh);
57858
57859                 for (i = 0; i < diff.length; i++) {
57860                   result[diff[i]] = head.hasEntity(diff[i]);
57861                 }
57862               }
57863
57864               if (entity.type === 'relation' && entity.isMultipolygon()) {
57865                 var mh = h ? h.members.map(function (m) {
57866                   return m.id;
57867                 }) : [];
57868                 var mb = b ? b.members.map(function (m) {
57869                   return m.id;
57870                 }) : [];
57871                 var ids = utilArrayUnion(mh, mb);
57872
57873                 for (i = 0; i < ids.length; i++) {
57874                   var member = head.hasEntity(ids[i]);
57875                   if (!member) continue; // not downloaded
57876
57877                   if (extent && !member.intersects(extent, head)) continue; // not visible
57878
57879                   result[ids[i]] = member;
57880                 }
57881               }
57882
57883               addParents(head.parentWays(entity), result);
57884               addParents(head.parentRelations(entity), result);
57885             }
57886
57887             return result;
57888
57889             function addParents(parents, result) {
57890               for (var i = 0; i < parents.length; i++) {
57891                 var parent = parents[i];
57892                 if (parent.id in result) continue;
57893                 result[parent.id] = parent;
57894                 addParents(head.parentRelations(parent), result);
57895               }
57896             }
57897           };
57898
57899           return _diff;
57900         }
57901
57902         function coreTree(head) {
57903           // tree for entities
57904           var _rtree = new RBush();
57905
57906           var _bboxes = {}; // maintain a separate tree for granular way segments
57907
57908           var _segmentsRTree = new RBush();
57909
57910           var _segmentsBBoxes = {};
57911           var _segmentsByWayId = {};
57912           var tree = {};
57913
57914           function entityBBox(entity) {
57915             var bbox = entity.extent(head).bbox();
57916             bbox.id = entity.id;
57917             _bboxes[entity.id] = bbox;
57918             return bbox;
57919           }
57920
57921           function segmentBBox(segment) {
57922             var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
57923
57924             if (!extent) return null;
57925             var bbox = extent.bbox();
57926             bbox.segment = segment;
57927             _segmentsBBoxes[segment.id] = bbox;
57928             return bbox;
57929           }
57930
57931           function removeEntity(entity) {
57932             _rtree.remove(_bboxes[entity.id]);
57933
57934             delete _bboxes[entity.id];
57935
57936             if (_segmentsByWayId[entity.id]) {
57937               _segmentsByWayId[entity.id].forEach(function (segment) {
57938                 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
57939
57940                 delete _segmentsBBoxes[segment.id];
57941               });
57942
57943               delete _segmentsByWayId[entity.id];
57944             }
57945           }
57946
57947           function loadEntities(entities) {
57948             _rtree.load(entities.map(entityBBox));
57949
57950             var segments = [];
57951             entities.forEach(function (entity) {
57952               if (entity.segments) {
57953                 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
57954
57955                 _segmentsByWayId[entity.id] = entitySegments;
57956                 segments = segments.concat(entitySegments);
57957               }
57958             });
57959             if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
57960           }
57961
57962           function updateParents(entity, insertions, memo) {
57963             head.parentWays(entity).forEach(function (way) {
57964               if (_bboxes[way.id]) {
57965                 removeEntity(way);
57966                 insertions[way.id] = way;
57967               }
57968
57969               updateParents(way, insertions, memo);
57970             });
57971             head.parentRelations(entity).forEach(function (relation) {
57972               if (memo[entity.id]) return;
57973               memo[entity.id] = true;
57974
57975               if (_bboxes[relation.id]) {
57976                 removeEntity(relation);
57977                 insertions[relation.id] = relation;
57978               }
57979
57980               updateParents(relation, insertions, memo);
57981             });
57982           }
57983
57984           tree.rebase = function (entities, force) {
57985             var insertions = {};
57986
57987             for (var i = 0; i < entities.length; i++) {
57988               var entity = entities[i];
57989               if (!entity.visible) continue;
57990
57991               if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
57992                 if (!force) {
57993                   continue;
57994                 } else if (_bboxes[entity.id]) {
57995                   removeEntity(entity);
57996                 }
57997               }
57998
57999               insertions[entity.id] = entity;
58000               updateParents(entity, insertions, {});
58001             }
58002
58003             loadEntities(Object.values(insertions));
58004             return tree;
58005           };
58006
58007           function updateToGraph(graph) {
58008             if (graph === head) return;
58009             var diff = coreDifference(head, graph);
58010             head = graph;
58011             var changed = diff.didChange;
58012             if (!changed.addition && !changed.deletion && !changed.geometry) return;
58013             var insertions = {};
58014
58015             if (changed.deletion) {
58016               diff.deleted().forEach(function (entity) {
58017                 removeEntity(entity);
58018               });
58019             }
58020
58021             if (changed.geometry) {
58022               diff.modified().forEach(function (entity) {
58023                 removeEntity(entity);
58024                 insertions[entity.id] = entity;
58025                 updateParents(entity, insertions, {});
58026               });
58027             }
58028
58029             if (changed.addition) {
58030               diff.created().forEach(function (entity) {
58031                 insertions[entity.id] = entity;
58032               });
58033             }
58034
58035             loadEntities(Object.values(insertions));
58036           } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
58037
58038
58039           tree.intersects = function (extent, graph) {
58040             updateToGraph(graph);
58041             return _rtree.search(extent.bbox()).map(function (bbox) {
58042               return graph.entity(bbox.id);
58043             });
58044           }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
58045
58046
58047           tree.waySegments = function (extent, graph) {
58048             updateToGraph(graph);
58049             return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
58050               return bbox.segment;
58051             });
58052           };
58053
58054           return tree;
58055         }
58056
58057         function uiModal(selection, blocking) {
58058           var _this = this;
58059
58060           var keybinding = utilKeybinding('modal');
58061           var previous = selection.select('div.modal');
58062           var animate = previous.empty();
58063           previous.transition().duration(200).style('opacity', 0).remove();
58064           var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
58065
58066           shaded.close = function () {
58067             shaded.transition().duration(200).style('opacity', 0).remove();
58068             modal.transition().duration(200).style('top', '0px');
58069             select(document).call(keybinding.unbind);
58070           };
58071
58072           var modal = shaded.append('div').attr('class', 'modal fillL');
58073           modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
58074
58075           if (!blocking) {
58076             shaded.on('click.remove-modal', function (d3_event) {
58077               if (d3_event.target === _this) {
58078                 shaded.close();
58079               }
58080             });
58081             modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
58082             keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
58083             select(document).call(keybinding);
58084           }
58085
58086           modal.append('div').attr('class', 'content');
58087           modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
58088
58089           if (animate) {
58090             shaded.transition().style('opacity', 1);
58091           } else {
58092             shaded.style('opacity', 1);
58093           }
58094
58095           return shaded;
58096
58097           function moveFocusToFirst() {
58098             var node = modal // there are additional rules about what's focusable, but this suits our purposes
58099             .select('a, button, input:not(.keytrap), select, textarea').node();
58100
58101             if (node) {
58102               node.focus();
58103             } else {
58104               select(this).node().blur();
58105             }
58106           }
58107
58108           function moveFocusToLast() {
58109             var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
58110
58111             if (nodes.length) {
58112               nodes[nodes.length - 1].focus();
58113             } else {
58114               select(this).node().blur();
58115             }
58116           }
58117         }
58118
58119         function uiLoading(context) {
58120           var _modalSelection = select(null);
58121
58122           var _message = '';
58123           var _blocking = false;
58124
58125           var loading = function loading(selection) {
58126             _modalSelection = uiModal(selection, _blocking);
58127
58128             var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
58129
58130             loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
58131             loadertext.append('h3').html(_message);
58132
58133             _modalSelection.select('button.close').attr('class', 'hide');
58134
58135             return loading;
58136           };
58137
58138           loading.message = function (val) {
58139             if (!arguments.length) return _message;
58140             _message = val;
58141             return loading;
58142           };
58143
58144           loading.blocking = function (val) {
58145             if (!arguments.length) return _blocking;
58146             _blocking = val;
58147             return loading;
58148           };
58149
58150           loading.close = function () {
58151             _modalSelection.remove();
58152           };
58153
58154           loading.isShown = function () {
58155             return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
58156           };
58157
58158           return loading;
58159         }
58160
58161         function coreHistory(context) {
58162           var dispatch$1 = dispatch('reset', 'change', 'merge', 'restore', 'undone', 'redone');
58163
58164           var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
58165
58166
58167           var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
58168
58169           var duration = 150;
58170           var _imageryUsed = [];
58171           var _photoOverlaysUsed = [];
58172           var _checkpoints = {};
58173
58174           var _pausedGraph;
58175
58176           var _stack;
58177
58178           var _index;
58179
58180           var _tree; // internal _act, accepts list of actions and eased time
58181
58182
58183           function _act(actions, t) {
58184             actions = Array.prototype.slice.call(actions);
58185             var annotation;
58186
58187             if (typeof actions[actions.length - 1] !== 'function') {
58188               annotation = actions.pop();
58189             }
58190
58191             var graph = _stack[_index].graph;
58192
58193             for (var i = 0; i < actions.length; i++) {
58194               graph = actions[i](graph, t);
58195             }
58196
58197             return {
58198               graph: graph,
58199               annotation: annotation,
58200               imageryUsed: _imageryUsed,
58201               photoOverlaysUsed: _photoOverlaysUsed,
58202               transform: context.projection.transform(),
58203               selectedIDs: context.selectedIDs()
58204             };
58205           } // internal _perform with eased time
58206
58207
58208           function _perform(args, t) {
58209             var previous = _stack[_index].graph;
58210             _stack = _stack.slice(0, _index + 1);
58211
58212             var actionResult = _act(args, t);
58213
58214             _stack.push(actionResult);
58215
58216             _index++;
58217             return change(previous);
58218           } // internal _replace with eased time
58219
58220
58221           function _replace(args, t) {
58222             var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
58223
58224             var actionResult = _act(args, t);
58225
58226             _stack[_index] = actionResult;
58227             return change(previous);
58228           } // internal _overwrite with eased time
58229
58230
58231           function _overwrite(args, t) {
58232             var previous = _stack[_index].graph;
58233
58234             if (_index > 0) {
58235               _index--;
58236
58237               _stack.pop();
58238             }
58239
58240             _stack = _stack.slice(0, _index + 1);
58241
58242             var actionResult = _act(args, t);
58243
58244             _stack.push(actionResult);
58245
58246             _index++;
58247             return change(previous);
58248           } // determine difference and dispatch a change event
58249
58250
58251           function change(previous) {
58252             var difference = coreDifference(previous, history.graph());
58253
58254             if (!_pausedGraph) {
58255               dispatch$1.call('change', this, difference);
58256             }
58257
58258             return difference;
58259           } // iD uses namespaced keys so multiple installations do not conflict
58260
58261
58262           function getKey(n) {
58263             return 'iD_' + window.location.origin + '_' + n;
58264           }
58265
58266           var history = {
58267             graph: function graph() {
58268               return _stack[_index].graph;
58269             },
58270             tree: function tree() {
58271               return _tree;
58272             },
58273             base: function base() {
58274               return _stack[0].graph;
58275             },
58276             merge: function merge(entities
58277             /*, extent*/
58278             ) {
58279               var stack = _stack.map(function (state) {
58280                 return state.graph;
58281               });
58282
58283               _stack[0].graph.rebase(entities, stack, false);
58284
58285               _tree.rebase(entities, false);
58286
58287               dispatch$1.call('merge', this, entities);
58288             },
58289             perform: function perform() {
58290               // complete any transition already in progress
58291               select(document).interrupt('history.perform');
58292               var transitionable = false;
58293               var action0 = arguments[0];
58294
58295               if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
58296                 transitionable = !!action0.transitionable;
58297               }
58298
58299               if (transitionable) {
58300                 var origArguments = arguments;
58301                 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
58302                   return function (t) {
58303                     if (t < 1) _overwrite([action0], t);
58304                   };
58305                 }).on('start', function () {
58306                   _perform([action0], 0);
58307                 }).on('end interrupt', function () {
58308                   _overwrite(origArguments, 1);
58309                 });
58310               } else {
58311                 return _perform(arguments);
58312               }
58313             },
58314             replace: function replace() {
58315               select(document).interrupt('history.perform');
58316               return _replace(arguments, 1);
58317             },
58318             // Same as calling pop and then perform
58319             overwrite: function overwrite() {
58320               select(document).interrupt('history.perform');
58321               return _overwrite(arguments, 1);
58322             },
58323             pop: function pop(n) {
58324               select(document).interrupt('history.perform');
58325               var previous = _stack[_index].graph;
58326
58327               if (isNaN(+n) || +n < 0) {
58328                 n = 1;
58329               }
58330
58331               while (n-- > 0 && _index > 0) {
58332                 _index--;
58333
58334                 _stack.pop();
58335               }
58336
58337               return change(previous);
58338             },
58339             // Back to the previous annotated state or _index = 0.
58340             undo: function undo() {
58341               select(document).interrupt('history.perform');
58342               var previousStack = _stack[_index];
58343               var previous = previousStack.graph;
58344
58345               while (_index > 0) {
58346                 _index--;
58347                 if (_stack[_index].annotation) break;
58348               }
58349
58350               dispatch$1.call('undone', this, _stack[_index], previousStack);
58351               return change(previous);
58352             },
58353             // Forward to the next annotated state.
58354             redo: function redo() {
58355               select(document).interrupt('history.perform');
58356               var previousStack = _stack[_index];
58357               var previous = previousStack.graph;
58358               var tryIndex = _index;
58359
58360               while (tryIndex < _stack.length - 1) {
58361                 tryIndex++;
58362
58363                 if (_stack[tryIndex].annotation) {
58364                   _index = tryIndex;
58365                   dispatch$1.call('redone', this, _stack[_index], previousStack);
58366                   break;
58367                 }
58368               }
58369
58370               return change(previous);
58371             },
58372             pauseChangeDispatch: function pauseChangeDispatch() {
58373               if (!_pausedGraph) {
58374                 _pausedGraph = _stack[_index].graph;
58375               }
58376             },
58377             resumeChangeDispatch: function resumeChangeDispatch() {
58378               if (_pausedGraph) {
58379                 var previous = _pausedGraph;
58380                 _pausedGraph = null;
58381                 return change(previous);
58382               }
58383             },
58384             undoAnnotation: function undoAnnotation() {
58385               var i = _index;
58386
58387               while (i >= 0) {
58388                 if (_stack[i].annotation) return _stack[i].annotation;
58389                 i--;
58390               }
58391             },
58392             redoAnnotation: function redoAnnotation() {
58393               var i = _index + 1;
58394
58395               while (i <= _stack.length - 1) {
58396                 if (_stack[i].annotation) return _stack[i].annotation;
58397                 i++;
58398               }
58399             },
58400             // Returns the entities from the active graph with bounding boxes
58401             // overlapping the given `extent`.
58402             intersects: function intersects(extent) {
58403               return _tree.intersects(extent, _stack[_index].graph);
58404             },
58405             difference: function difference() {
58406               var base = _stack[0].graph;
58407               var head = _stack[_index].graph;
58408               return coreDifference(base, head);
58409             },
58410             changes: function changes(action) {
58411               var base = _stack[0].graph;
58412               var head = _stack[_index].graph;
58413
58414               if (action) {
58415                 head = action(head);
58416               }
58417
58418               var difference = coreDifference(base, head);
58419               return {
58420                 modified: difference.modified(),
58421                 created: difference.created(),
58422                 deleted: difference.deleted()
58423               };
58424             },
58425             hasChanges: function hasChanges() {
58426               return this.difference().length() > 0;
58427             },
58428             imageryUsed: function imageryUsed(sources) {
58429               if (sources) {
58430                 _imageryUsed = sources;
58431                 return history;
58432               } else {
58433                 var s = new Set();
58434
58435                 _stack.slice(1, _index + 1).forEach(function (state) {
58436                   state.imageryUsed.forEach(function (source) {
58437                     if (source !== 'Custom') {
58438                       s.add(source);
58439                     }
58440                   });
58441                 });
58442
58443                 return Array.from(s);
58444               }
58445             },
58446             photoOverlaysUsed: function photoOverlaysUsed(sources) {
58447               if (sources) {
58448                 _photoOverlaysUsed = sources;
58449                 return history;
58450               } else {
58451                 var s = new Set();
58452
58453                 _stack.slice(1, _index + 1).forEach(function (state) {
58454                   if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
58455                     state.photoOverlaysUsed.forEach(function (photoOverlay) {
58456                       s.add(photoOverlay);
58457                     });
58458                   }
58459                 });
58460
58461                 return Array.from(s);
58462               }
58463             },
58464             // save the current history state
58465             checkpoint: function checkpoint(key) {
58466               _checkpoints[key] = {
58467                 stack: _stack,
58468                 index: _index
58469               };
58470               return history;
58471             },
58472             // restore history state to a given checkpoint or reset completely
58473             reset: function reset(key) {
58474               if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
58475                 _stack = _checkpoints[key].stack;
58476                 _index = _checkpoints[key].index;
58477               } else {
58478                 _stack = [{
58479                   graph: coreGraph()
58480                 }];
58481                 _index = 0;
58482                 _tree = coreTree(_stack[0].graph);
58483                 _checkpoints = {};
58484               }
58485
58486               dispatch$1.call('reset');
58487               dispatch$1.call('change');
58488               return history;
58489             },
58490             // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
58491             //
58492             // To use it:
58493             //  1. Start the walkthrough.
58494             //  2. Get to a "free editing" tutorial step
58495             //  3. Make your edits to the walkthrough map
58496             //  4. In your browser dev console run:
58497             //        `id.history().toIntroGraph()`
58498             //  5. This outputs stringified JSON to the browser console
58499             //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
58500             toIntroGraph: function toIntroGraph() {
58501               var nextID = {
58502                 n: 0,
58503                 r: 0,
58504                 w: 0
58505               };
58506               var permIDs = {};
58507               var graph = this.graph();
58508               var baseEntities = {}; // clone base entities..
58509
58510               Object.values(graph.base().entities).forEach(function (entity) {
58511                 var copy = copyIntroEntity(entity);
58512                 baseEntities[copy.id] = copy;
58513               }); // replace base entities with head entities..
58514
58515               Object.keys(graph.entities).forEach(function (id) {
58516                 var entity = graph.entities[id];
58517
58518                 if (entity) {
58519                   var copy = copyIntroEntity(entity);
58520                   baseEntities[copy.id] = copy;
58521                 } else {
58522                   delete baseEntities[id];
58523                 }
58524               }); // swap temporary for permanent ids..
58525
58526               Object.values(baseEntities).forEach(function (entity) {
58527                 if (Array.isArray(entity.nodes)) {
58528                   entity.nodes = entity.nodes.map(function (node) {
58529                     return permIDs[node] || node;
58530                   });
58531                 }
58532
58533                 if (Array.isArray(entity.members)) {
58534                   entity.members = entity.members.map(function (member) {
58535                     member.id = permIDs[member.id] || member.id;
58536                     return member;
58537                   });
58538                 }
58539               });
58540               return JSON.stringify({
58541                 dataIntroGraph: baseEntities
58542               });
58543
58544               function copyIntroEntity(source) {
58545                 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
58546
58547                 if (copy.tags && !Object.keys(copy.tags)) {
58548                   delete copy.tags;
58549                 }
58550
58551                 if (Array.isArray(copy.loc)) {
58552                   copy.loc[0] = +copy.loc[0].toFixed(6);
58553                   copy.loc[1] = +copy.loc[1].toFixed(6);
58554                 }
58555
58556                 var match = source.id.match(/([nrw])-\d*/); // temporary id
58557
58558                 if (match !== null) {
58559                   var nrw = match[1];
58560                   var permID;
58561
58562                   do {
58563                     permID = nrw + ++nextID[nrw];
58564                   } while (baseEntities.hasOwnProperty(permID));
58565
58566                   copy.id = permIDs[source.id] = permID;
58567                 }
58568
58569                 return copy;
58570               }
58571             },
58572             toJSON: function toJSON() {
58573               if (!this.hasChanges()) return;
58574               var allEntities = {};
58575               var baseEntities = {};
58576               var base = _stack[0];
58577
58578               var s = _stack.map(function (i) {
58579                 var modified = [];
58580                 var deleted = [];
58581                 Object.keys(i.graph.entities).forEach(function (id) {
58582                   var entity = i.graph.entities[id];
58583
58584                   if (entity) {
58585                     var key = osmEntity.key(entity);
58586                     allEntities[key] = entity;
58587                     modified.push(key);
58588                   } else {
58589                     deleted.push(id);
58590                   } // make sure that the originals of changed or deleted entities get merged
58591                   // into the base of the _stack after restoring the data from JSON.
58592
58593
58594                   if (id in base.graph.entities) {
58595                     baseEntities[id] = base.graph.entities[id];
58596                   }
58597
58598                   if (entity && entity.nodes) {
58599                     // get originals of pre-existing child nodes
58600                     entity.nodes.forEach(function (nodeID) {
58601                       if (nodeID in base.graph.entities) {
58602                         baseEntities[nodeID] = base.graph.entities[nodeID];
58603                       }
58604                     });
58605                   } // get originals of parent entities too
58606
58607
58608                   var baseParents = base.graph._parentWays[id];
58609
58610                   if (baseParents) {
58611                     baseParents.forEach(function (parentID) {
58612                       if (parentID in base.graph.entities) {
58613                         baseEntities[parentID] = base.graph.entities[parentID];
58614                       }
58615                     });
58616                   }
58617                 });
58618                 var x = {};
58619                 if (modified.length) x.modified = modified;
58620                 if (deleted.length) x.deleted = deleted;
58621                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
58622                 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
58623                 if (i.annotation) x.annotation = i.annotation;
58624                 if (i.transform) x.transform = i.transform;
58625                 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
58626                 return x;
58627               });
58628
58629               return JSON.stringify({
58630                 version: 3,
58631                 entities: Object.values(allEntities),
58632                 baseEntities: Object.values(baseEntities),
58633                 stack: s,
58634                 nextIDs: osmEntity.id.next,
58635                 index: _index,
58636                 // note the time the changes were saved
58637                 timestamp: new Date().getTime()
58638               });
58639             },
58640             fromJSON: function fromJSON(json, loadChildNodes) {
58641               var h = JSON.parse(json);
58642               var loadComplete = true;
58643               osmEntity.id.next = h.nextIDs;
58644               _index = h.index;
58645
58646               if (h.version === 2 || h.version === 3) {
58647                 var allEntities = {};
58648                 h.entities.forEach(function (entity) {
58649                   allEntities[osmEntity.key(entity)] = osmEntity(entity);
58650                 });
58651
58652                 if (h.version === 3) {
58653                   // This merges originals for changed entities into the base of
58654                   // the _stack even if the current _stack doesn't have them (for
58655                   // example when iD has been restarted in a different region)
58656                   var baseEntities = h.baseEntities.map(function (d) {
58657                     return osmEntity(d);
58658                   });
58659
58660                   var stack = _stack.map(function (state) {
58661                     return state.graph;
58662                   });
58663
58664                   _stack[0].graph.rebase(baseEntities, stack, true);
58665
58666                   _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
58667                   // childnodes that would normally have been downloaded with it.. #2142
58668
58669
58670                   if (loadChildNodes) {
58671                     var osm = context.connection();
58672                     var baseWays = baseEntities.filter(function (e) {
58673                       return e.type === 'way';
58674                     });
58675                     var nodeIDs = baseWays.reduce(function (acc, way) {
58676                       return utilArrayUnion(acc, way.nodes);
58677                     }, []);
58678                     var missing = nodeIDs.filter(function (n) {
58679                       return !_stack[0].graph.hasEntity(n);
58680                     });
58681
58682                     if (missing.length && osm) {
58683                       loadComplete = false;
58684                       context.map().redrawEnable(false);
58685                       var loading = uiLoading(context).blocking(true);
58686                       context.container().call(loading);
58687
58688                       var childNodesLoaded = function childNodesLoaded(err, result) {
58689                         if (!err) {
58690                           var visibleGroups = utilArrayGroupBy(result.data, 'visible');
58691                           var visibles = visibleGroups["true"] || []; // alive nodes
58692
58693                           var invisibles = visibleGroups["false"] || []; // deleted nodes
58694
58695                           if (visibles.length) {
58696                             var visibleIDs = visibles.map(function (entity) {
58697                               return entity.id;
58698                             });
58699
58700                             var stack = _stack.map(function (state) {
58701                               return state.graph;
58702                             });
58703
58704                             missing = utilArrayDifference(missing, visibleIDs);
58705
58706                             _stack[0].graph.rebase(visibles, stack, true);
58707
58708                             _tree.rebase(visibles, true);
58709                           } // fetch older versions of nodes that were deleted..
58710
58711
58712                           invisibles.forEach(function (entity) {
58713                             osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
58714                           });
58715                         }
58716
58717                         if (err || !missing.length) {
58718                           loading.close();
58719                           context.map().redrawEnable(true);
58720                           dispatch$1.call('change');
58721                           dispatch$1.call('restore', this);
58722                         }
58723                       };
58724
58725                       osm.loadMultiple(missing, childNodesLoaded);
58726                     }
58727                   }
58728                 }
58729
58730                 _stack = h.stack.map(function (d) {
58731                   var entities = {},
58732                       entity;
58733
58734                   if (d.modified) {
58735                     d.modified.forEach(function (key) {
58736                       entity = allEntities[key];
58737                       entities[entity.id] = entity;
58738                     });
58739                   }
58740
58741                   if (d.deleted) {
58742                     d.deleted.forEach(function (id) {
58743                       entities[id] = undefined;
58744                     });
58745                   }
58746
58747                   return {
58748                     graph: coreGraph(_stack[0].graph).load(entities),
58749                     annotation: d.annotation,
58750                     imageryUsed: d.imageryUsed,
58751                     photoOverlaysUsed: d.photoOverlaysUsed,
58752                     transform: d.transform,
58753                     selectedIDs: d.selectedIDs
58754                   };
58755                 });
58756               } else {
58757                 // original version
58758                 _stack = h.stack.map(function (d) {
58759                   var entities = {};
58760
58761                   for (var i in d.entities) {
58762                     var entity = d.entities[i];
58763                     entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
58764                   }
58765
58766                   d.graph = coreGraph(_stack[0].graph).load(entities);
58767                   return d;
58768                 });
58769               }
58770
58771               var transform = _stack[_index].transform;
58772
58773               if (transform) {
58774                 context.map().transformEase(transform, 0); // 0 = immediate, no easing
58775               }
58776
58777               if (loadComplete) {
58778                 dispatch$1.call('change');
58779                 dispatch$1.call('restore', this);
58780               }
58781
58782               return history;
58783             },
58784             lock: function lock() {
58785               return _lock.lock();
58786             },
58787             unlock: function unlock() {
58788               _lock.unlock();
58789             },
58790             save: function save() {
58791               if (_lock.locked() && // don't overwrite existing, unresolved changes
58792               !_hasUnresolvedRestorableChanges) {
58793                 corePreferences(getKey('saved_history'), history.toJSON() || null);
58794               }
58795
58796               return history;
58797             },
58798             // delete the history version saved in localStorage
58799             clearSaved: function clearSaved() {
58800               context.debouncedSave.cancel();
58801
58802               if (_lock.locked()) {
58803                 _hasUnresolvedRestorableChanges = false;
58804                 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
58805
58806                 corePreferences('comment', null);
58807                 corePreferences('hashtags', null);
58808                 corePreferences('source', null);
58809               }
58810
58811               return history;
58812             },
58813             savedHistoryJSON: function savedHistoryJSON() {
58814               return corePreferences(getKey('saved_history'));
58815             },
58816             hasRestorableChanges: function hasRestorableChanges() {
58817               return _hasUnresolvedRestorableChanges;
58818             },
58819             // load history from a version stored in localStorage
58820             restore: function restore() {
58821               if (_lock.locked()) {
58822                 _hasUnresolvedRestorableChanges = false;
58823                 var json = this.savedHistoryJSON();
58824                 if (json) history.fromJSON(json, true);
58825               }
58826             },
58827             _getKey: getKey
58828           };
58829           history.reset();
58830           return utilRebind(history, dispatch$1, 'on');
58831         }
58832
58833         /**
58834          * Look for roads that can be connected to other roads with a short extension
58835          */
58836
58837         function validationAlmostJunction(context) {
58838           var type = 'almost_junction';
58839           var EXTEND_TH_METERS = 5;
58840           var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
58841
58842           var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
58843
58844           var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
58845
58846           function isHighway(entity) {
58847             return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
58848           }
58849
58850           function isTaggedAsNotContinuing(node) {
58851             return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
58852           }
58853
58854           var validation = function checkAlmostJunction(entity, graph) {
58855             if (!isHighway(entity)) return [];
58856             if (entity.isDegenerate()) return [];
58857             var tree = context.history().tree();
58858             var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
58859             var issues = [];
58860             extendableNodeInfos.forEach(function (extendableNodeInfo) {
58861               issues.push(new validationIssue({
58862                 type: type,
58863                 subtype: 'highway-highway',
58864                 severity: 'warning',
58865                 message: function message(context) {
58866                   var entity1 = context.hasEntity(this.entityIds[0]);
58867
58868                   if (this.entityIds[0] === this.entityIds[2]) {
58869                     return entity1 ? _t.html('issues.almost_junction.self.message', {
58870                       feature: utilDisplayLabel(entity1, context.graph())
58871                     }) : '';
58872                   } else {
58873                     var entity2 = context.hasEntity(this.entityIds[2]);
58874                     return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
58875                       feature: utilDisplayLabel(entity1, context.graph()),
58876                       feature2: utilDisplayLabel(entity2, context.graph())
58877                     }) : '';
58878                   }
58879                 },
58880                 reference: showReference,
58881                 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
58882                 loc: extendableNodeInfo.node.loc,
58883                 hash: JSON.stringify(extendableNodeInfo.node.loc),
58884                 data: {
58885                   midId: extendableNodeInfo.mid.id,
58886                   edge: extendableNodeInfo.edge,
58887                   cross_loc: extendableNodeInfo.cross_loc
58888                 },
58889                 dynamicFixes: makeFixes
58890               }));
58891             });
58892             return issues;
58893
58894             function makeFixes(context) {
58895               var fixes = [new validationIssueFix({
58896                 icon: 'iD-icon-abutment',
58897                 title: _t.html('issues.fix.connect_features.title'),
58898                 onClick: function onClick(context) {
58899                   var annotation = _t('issues.fix.connect_almost_junction.annotation');
58900
58901                   var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
58902                       endNodeId = _this$issue$entityIds[1],
58903                       crossWayId = _this$issue$entityIds[2];
58904
58905                   var midNode = context.entity(this.issue.data.midId);
58906                   var endNode = context.entity(endNodeId);
58907                   var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
58908
58909                   var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
58910
58911                   if (nearEndNodes.length > 0) {
58912                     var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
58913
58914                     if (collinear) {
58915                       context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
58916                       return;
58917                     }
58918                   }
58919
58920                   var targetEdge = this.issue.data.edge;
58921                   var crossLoc = this.issue.data.cross_loc;
58922                   var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
58923                   var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
58924
58925                   if (closestNodeInfo.distance < WELD_TH_METERS) {
58926                     context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
58927                   } else {
58928                     context.perform(actionAddMidpoint({
58929                       loc: crossLoc,
58930                       edge: targetEdge
58931                     }, endNode), annotation);
58932                   }
58933                 }
58934               })];
58935               var node = context.hasEntity(this.entityIds[1]);
58936
58937               if (node && !node.hasInterestingTags()) {
58938                 // node has no descriptive tags, suggest noexit fix
58939                 fixes.push(new validationIssueFix({
58940                   icon: 'maki-barrier',
58941                   title: _t.html('issues.fix.tag_as_disconnected.title'),
58942                   onClick: function onClick(context) {
58943                     var nodeID = this.issue.entityIds[1];
58944                     var tags = Object.assign({}, context.entity(nodeID).tags);
58945                     tags.noexit = 'yes';
58946                     context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
58947                   }
58948                 }));
58949               }
58950
58951               return fixes;
58952             }
58953
58954             function showReference(selection) {
58955               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
58956             }
58957
58958             function isExtendableCandidate(node, way) {
58959               // can not accurately test vertices on tiles not downloaded from osm - #5938
58960               var osm = services.osm;
58961
58962               if (osm && !osm.isDataLoaded(node.loc)) {
58963                 return false;
58964               }
58965
58966               if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
58967                 return false;
58968               }
58969
58970               var occurrences = 0;
58971
58972               for (var index in way.nodes) {
58973                 if (way.nodes[index] === node.id) {
58974                   occurrences += 1;
58975
58976                   if (occurrences > 1) {
58977                     return false;
58978                   }
58979                 }
58980               }
58981
58982               return true;
58983             }
58984
58985             function findConnectableEndNodesByExtension(way) {
58986               var results = [];
58987               if (way.isClosed()) return results;
58988               var testNodes;
58989               var indices = [0, way.nodes.length - 1];
58990               indices.forEach(function (nodeIndex) {
58991                 var nodeID = way.nodes[nodeIndex];
58992                 var node = graph.entity(nodeID);
58993                 if (!isExtendableCandidate(node, way)) return;
58994                 var connectionInfo = canConnectByExtend(way, nodeIndex);
58995                 if (!connectionInfo) return;
58996                 testNodes = graph.childNodes(way).slice(); // shallow copy
58997
58998                 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
58999
59000                 if (geoHasSelfIntersections(testNodes, nodeID)) return;
59001                 results.push(connectionInfo);
59002               });
59003               return results;
59004             }
59005
59006             function findNearbyEndNodes(node, way) {
59007               return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
59008                 return graph.entity(d);
59009               }).filter(function (d) {
59010                 // Node cannot be near to itself, but other endnode of same way could be
59011                 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
59012               });
59013             }
59014
59015             function findSmallJoinAngle(midNode, tipNode, endNodes) {
59016               // Both nodes could be close, so want to join whichever is closest to collinear
59017               var joinTo;
59018               var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
59019
59020               endNodes.forEach(function (endNode) {
59021                 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
59022                 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
59023                 var diff = Math.max(a1, a2) - Math.min(a1, a2);
59024
59025                 if (diff < minAngle) {
59026                   joinTo = endNode;
59027                   minAngle = diff;
59028                 }
59029               });
59030               /* Threshold set by considering right angle triangle
59031               based on node joining threshold and extension distance */
59032
59033               if (minAngle <= SIG_ANGLE_TH) return joinTo;
59034               return null;
59035             }
59036
59037             function hasTag(tags, key) {
59038               return tags[key] !== undefined && tags[key] !== 'no';
59039             }
59040
59041             function canConnectWays(way, way2) {
59042               // allow self-connections
59043               if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
59044
59045               if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
59046               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
59047
59048               var layer1 = way.tags.layer || '0',
59049                   layer2 = way2.tags.layer || '0';
59050               if (layer1 !== layer2) return false;
59051               var level1 = way.tags.level || '0',
59052                   level2 = way2.tags.level || '0';
59053               if (level1 !== level2) return false;
59054               return true;
59055             }
59056
59057             function canConnectByExtend(way, endNodeIdx) {
59058               var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
59059
59060               var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
59061
59062               var tipNode = graph.entity(tipNid);
59063               var midNode = graph.entity(midNid);
59064               var lon = tipNode.loc[0];
59065               var lat = tipNode.loc[1];
59066               var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
59067               var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
59068               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
59069
59070               var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
59071               var t = EXTEND_TH_METERS / edgeLen + 1.0;
59072               var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
59073
59074               var segmentInfos = tree.waySegments(queryExtent, graph);
59075
59076               for (var i = 0; i < segmentInfos.length; i++) {
59077                 var segmentInfo = segmentInfos[i];
59078                 var way2 = graph.entity(segmentInfo.wayId);
59079                 if (!isHighway(way2)) continue;
59080                 if (!canConnectWays(way, way2)) continue;
59081                 var nAid = segmentInfo.nodes[0],
59082                     nBid = segmentInfo.nodes[1];
59083                 if (nAid === tipNid || nBid === tipNid) continue;
59084                 var nA = graph.entity(nAid),
59085                     nB = graph.entity(nBid);
59086                 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
59087
59088                 if (crossLoc) {
59089                   return {
59090                     mid: midNode,
59091                     node: tipNode,
59092                     wid: way2.id,
59093                     edge: [nA.id, nB.id],
59094                     cross_loc: crossLoc
59095                   };
59096                 }
59097               }
59098
59099               return null;
59100             }
59101           };
59102
59103           validation.type = type;
59104           return validation;
59105         }
59106
59107         function validationCloseNodes(context) {
59108           var type = 'close_nodes';
59109           var pointThresholdMeters = 0.2;
59110
59111           var validation = function validation(entity, graph) {
59112             if (entity.type === 'node') {
59113               return getIssuesForNode(entity);
59114             } else if (entity.type === 'way') {
59115               return getIssuesForWay(entity);
59116             }
59117
59118             return [];
59119
59120             function getIssuesForNode(node) {
59121               var parentWays = graph.parentWays(node);
59122
59123               if (parentWays.length) {
59124                 return getIssuesForVertex(node, parentWays);
59125               } else {
59126                 return getIssuesForDetachedPoint(node);
59127               }
59128             }
59129
59130             function wayTypeFor(way) {
59131               if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
59132               if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
59133               if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
59134               if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
59135               var parentRelations = graph.parentRelations(way);
59136
59137               for (var i in parentRelations) {
59138                 var relation = parentRelations[i];
59139                 if (relation.tags.type === 'boundary') return 'boundary';
59140
59141                 if (relation.isMultipolygon()) {
59142                   if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
59143                   if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
59144                 }
59145               }
59146
59147               return 'other';
59148             }
59149
59150             function shouldCheckWay(way) {
59151               // don't flag issues where merging would create degenerate ways
59152               if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
59153               var bbox = way.extent(graph).bbox();
59154               var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
59155
59156               if (hypotenuseMeters < 1.5) return false;
59157               return true;
59158             }
59159
59160             function getIssuesForWay(way) {
59161               if (!shouldCheckWay(way)) return [];
59162               var issues = [],
59163                   nodes = graph.childNodes(way);
59164
59165               for (var i = 0; i < nodes.length - 1; i++) {
59166                 var node1 = nodes[i];
59167                 var node2 = nodes[i + 1];
59168                 var issue = getWayIssueIfAny(node1, node2, way);
59169                 if (issue) issues.push(issue);
59170               }
59171
59172               return issues;
59173             }
59174
59175             function getIssuesForVertex(node, parentWays) {
59176               var issues = [];
59177
59178               function checkForCloseness(node1, node2, way) {
59179                 var issue = getWayIssueIfAny(node1, node2, way);
59180                 if (issue) issues.push(issue);
59181               }
59182
59183               for (var i = 0; i < parentWays.length; i++) {
59184                 var parentWay = parentWays[i];
59185                 if (!shouldCheckWay(parentWay)) continue;
59186                 var lastIndex = parentWay.nodes.length - 1;
59187
59188                 for (var j = 0; j < parentWay.nodes.length; j++) {
59189                   if (j !== 0) {
59190                     if (parentWay.nodes[j - 1] === node.id) {
59191                       checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
59192                     }
59193                   }
59194
59195                   if (j !== lastIndex) {
59196                     if (parentWay.nodes[j + 1] === node.id) {
59197                       checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
59198                     }
59199                   }
59200                 }
59201               }
59202
59203               return issues;
59204             }
59205
59206             function thresholdMetersForWay(way) {
59207               if (!shouldCheckWay(way)) return 0;
59208               var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
59209
59210               if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
59211
59212               if (wayType === 'indoor') return 0.01;
59213               if (wayType === 'building') return 0.05;
59214               if (wayType === 'path') return 0.1;
59215               return 0.2;
59216             }
59217
59218             function getIssuesForDetachedPoint(node) {
59219               var issues = [];
59220               var lon = node.loc[0];
59221               var lat = node.loc[1];
59222               var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
59223               var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
59224               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
59225               var intersected = context.history().tree().intersects(queryExtent, graph);
59226
59227               for (var j = 0; j < intersected.length; j++) {
59228                 var nearby = intersected[j];
59229                 if (nearby.id === node.id) continue;
59230                 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
59231
59232                 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
59233                   // allow very close points if tags indicate the z-axis might vary
59234                   var zAxisKeys = {
59235                     layer: true,
59236                     level: true,
59237                     'addr:housenumber': true,
59238                     'addr:unit': true
59239                   };
59240                   var zAxisDifferentiates = false;
59241
59242                   for (var key in zAxisKeys) {
59243                     var nodeValue = node.tags[key] || '0';
59244                     var nearbyValue = nearby.tags[key] || '0';
59245
59246                     if (nodeValue !== nearbyValue) {
59247                       zAxisDifferentiates = true;
59248                       break;
59249                     }
59250                   }
59251
59252                   if (zAxisDifferentiates) continue;
59253                   issues.push(new validationIssue({
59254                     type: type,
59255                     subtype: 'detached',
59256                     severity: 'warning',
59257                     message: function message(context) {
59258                       var entity = context.hasEntity(this.entityIds[0]),
59259                           entity2 = context.hasEntity(this.entityIds[1]);
59260                       return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
59261                         feature: utilDisplayLabel(entity, context.graph()),
59262                         feature2: utilDisplayLabel(entity2, context.graph())
59263                       }) : '';
59264                     },
59265                     reference: showReference,
59266                     entityIds: [node.id, nearby.id],
59267                     dynamicFixes: function dynamicFixes() {
59268                       return [new validationIssueFix({
59269                         icon: 'iD-operation-disconnect',
59270                         title: _t.html('issues.fix.move_points_apart.title')
59271                       }), new validationIssueFix({
59272                         icon: 'iD-icon-layers',
59273                         title: _t.html('issues.fix.use_different_layers_or_levels.title')
59274                       })];
59275                     }
59276                   }));
59277                 }
59278               }
59279
59280               return issues;
59281
59282               function showReference(selection) {
59283                 var referenceText = _t('issues.close_nodes.detached.reference');
59284                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
59285               }
59286             }
59287
59288             function getWayIssueIfAny(node1, node2, way) {
59289               if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
59290                 return null;
59291               }
59292
59293               if (node1.loc !== node2.loc) {
59294                 var parentWays1 = graph.parentWays(node1);
59295                 var parentWays2 = new Set(graph.parentWays(node2));
59296                 var sharedWays = parentWays1.filter(function (parentWay) {
59297                   return parentWays2.has(parentWay);
59298                 });
59299                 var thresholds = sharedWays.map(function (parentWay) {
59300                   return thresholdMetersForWay(parentWay);
59301                 });
59302                 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
59303                 var distance = geoSphericalDistance(node1.loc, node2.loc);
59304                 if (distance > threshold) return null;
59305               }
59306
59307               return new validationIssue({
59308                 type: type,
59309                 subtype: 'vertices',
59310                 severity: 'warning',
59311                 message: function message(context) {
59312                   var entity = context.hasEntity(this.entityIds[0]);
59313                   return entity ? _t.html('issues.close_nodes.message', {
59314                     way: utilDisplayLabel(entity, context.graph())
59315                   }) : '';
59316                 },
59317                 reference: showReference,
59318                 entityIds: [way.id, node1.id, node2.id],
59319                 loc: node1.loc,
59320                 dynamicFixes: function dynamicFixes() {
59321                   return [new validationIssueFix({
59322                     icon: 'iD-icon-plus',
59323                     title: _t.html('issues.fix.merge_points.title'),
59324                     onClick: function onClick(context) {
59325                       var entityIds = this.issue.entityIds;
59326                       var action = actionMergeNodes([entityIds[1], entityIds[2]]);
59327                       context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
59328                     }
59329                   }), new validationIssueFix({
59330                     icon: 'iD-operation-disconnect',
59331                     title: _t.html('issues.fix.move_points_apart.title')
59332                   })];
59333                 }
59334               });
59335
59336               function showReference(selection) {
59337                 var referenceText = _t('issues.close_nodes.reference');
59338                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
59339               }
59340             }
59341           };
59342
59343           validation.type = type;
59344           return validation;
59345         }
59346
59347         function validationCrossingWays(context) {
59348           var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
59349
59350           function getFeatureWithFeatureTypeTagsForWay(way, graph) {
59351             if (getFeatureType(way, graph) === null) {
59352               // if the way doesn't match a feature type, check its parent relations
59353               var parentRels = graph.parentRelations(way);
59354
59355               for (var i = 0; i < parentRels.length; i++) {
59356                 var rel = parentRels[i];
59357
59358                 if (getFeatureType(rel, graph) !== null) {
59359                   return rel;
59360                 }
59361               }
59362             }
59363
59364             return way;
59365           }
59366
59367           function hasTag(tags, key) {
59368             return tags[key] !== undefined && tags[key] !== 'no';
59369           }
59370
59371           function taggedAsIndoor(tags) {
59372             return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
59373           }
59374
59375           function allowsBridge(featureType) {
59376             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
59377           }
59378
59379           function allowsTunnel(featureType) {
59380             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
59381           } // discard
59382
59383
59384           var ignoredBuildings = {
59385             demolished: true,
59386             dismantled: true,
59387             proposed: true,
59388             razed: true
59389           };
59390
59391           function getFeatureType(entity, graph) {
59392             var geometry = entity.geometry(graph);
59393             if (geometry !== 'line' && geometry !== 'area') return null;
59394             var tags = entity.tags;
59395             if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
59396             if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
59397
59398             if (geometry !== 'line') return null;
59399             if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
59400             if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
59401             return null;
59402           }
59403
59404           function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
59405             // assume 0 by default
59406             var level1 = tags1.level || '0';
59407             var level2 = tags2.level || '0';
59408
59409             if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
59410               // assume features don't interact if they're indoor on different levels
59411               return true;
59412             } // assume 0 by default; don't use way.layer() since we account for structures here
59413
59414
59415             var layer1 = tags1.layer || '0';
59416             var layer2 = tags2.layer || '0';
59417
59418             if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
59419               if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
59420               if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
59421
59422               if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
59423             } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
59424
59425             if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
59426               if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
59427               if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
59428
59429               if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
59430             } 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
59431
59432
59433             if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
59434             if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
59435
59436             if (featureType1 === 'building' || featureType2 === 'building') {
59437               // for building crossings, different layers are enough
59438               if (layer1 !== layer2) return true;
59439             }
59440
59441             return false;
59442           } // highway values for which we shouldn't recommend connecting to waterways
59443
59444
59445           var highwaysDisallowingFords = {
59446             motorway: true,
59447             motorway_link: true,
59448             trunk: true,
59449             trunk_link: true,
59450             primary: true,
59451             primary_link: true,
59452             secondary: true,
59453             secondary_link: true
59454           };
59455           var nonCrossingHighways = {
59456             track: true
59457           };
59458
59459           function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
59460             var featureType1 = getFeatureType(entity1, graph);
59461             var featureType2 = getFeatureType(entity2, graph);
59462             var geometry1 = entity1.geometry(graph);
59463             var geometry2 = entity2.geometry(graph);
59464             var bothLines = geometry1 === 'line' && geometry2 === 'line';
59465
59466             if (featureType1 === featureType2) {
59467               if (featureType1 === 'highway') {
59468                 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
59469                 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
59470
59471                 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
59472                   // one feature is a path but not both
59473                   var roadFeature = entity1IsPath ? entity2 : entity1;
59474
59475                   if (nonCrossingHighways[roadFeature.tags.highway]) {
59476                     // don't mark path connections with certain roads as crossings
59477                     return {};
59478                   }
59479
59480                   var pathFeature = entity1IsPath ? entity1 : entity2;
59481
59482                   if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
59483                     // if the path is a crossing, match the crossing type
59484                     return bothLines ? {
59485                       highway: 'crossing',
59486                       crossing: pathFeature.tags.crossing
59487                     } : {};
59488                   } // don't add a `crossing` subtag to ambiguous crossings
59489
59490
59491                   return bothLines ? {
59492                     highway: 'crossing'
59493                   } : {};
59494                 }
59495
59496                 return {};
59497               }
59498
59499               if (featureType1 === 'waterway') return {};
59500               if (featureType1 === 'railway') return {};
59501             } else {
59502               var featureTypes = [featureType1, featureType2];
59503
59504               if (featureTypes.indexOf('highway') !== -1) {
59505                 if (featureTypes.indexOf('railway') !== -1) {
59506                   if (!bothLines) return {};
59507                   var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
59508
59509                   if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
59510                     // path-tram connections use this tag
59511                     if (isTram) return {
59512                       railway: 'tram_crossing'
59513                     }; // other path-rail connections use this tag
59514
59515                     return {
59516                       railway: 'crossing'
59517                     };
59518                   } else {
59519                     // path-tram connections use this tag
59520                     if (isTram) return {
59521                       railway: 'tram_level_crossing'
59522                     }; // other road-rail connections use this tag
59523
59524                     return {
59525                       railway: 'level_crossing'
59526                     };
59527                   }
59528                 }
59529
59530                 if (featureTypes.indexOf('waterway') !== -1) {
59531                   // do not allow fords on structures
59532                   if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
59533                   if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
59534
59535                   if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
59536                     // do not allow fords on major highways
59537                     return null;
59538                   }
59539
59540                   return bothLines ? {
59541                     ford: 'yes'
59542                   } : {};
59543                 }
59544               }
59545             }
59546
59547             return null;
59548           }
59549
59550           function findCrossingsByWay(way1, graph, tree) {
59551             var edgeCrossInfos = [];
59552             if (way1.type !== 'way') return edgeCrossInfos;
59553             var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
59554             var way1FeatureType = getFeatureType(taggedFeature1, graph);
59555             if (way1FeatureType === null) return edgeCrossInfos;
59556             var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
59557
59558             var i, j;
59559             var extent;
59560             var n1, n2, nA, nB, nAId, nBId;
59561             var segment1, segment2;
59562             var oneOnly;
59563             var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
59564             var way1Nodes = graph.childNodes(way1);
59565             var comparedWays = {};
59566
59567             for (i = 0; i < way1Nodes.length - 1; i++) {
59568               n1 = way1Nodes[i];
59569               n2 = way1Nodes[i + 1];
59570               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
59571               // of overlapping ways
59572
59573               segmentInfos = tree.waySegments(extent, graph);
59574
59575               for (j = 0; j < segmentInfos.length; j++) {
59576                 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
59577
59578                 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
59579
59580                 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
59581
59582                 comparedWays[segment2Info.wayId] = true;
59583                 way2 = graph.hasEntity(segment2Info.wayId);
59584                 if (!way2) continue;
59585                 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
59586
59587                 way2FeatureType = getFeatureType(taggedFeature2, graph);
59588
59589                 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
59590                   continue;
59591                 } // create only one issue for building crossings
59592
59593
59594                 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
59595                 nAId = segment2Info.nodes[0];
59596                 nBId = segment2Info.nodes[1];
59597
59598                 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
59599                   // n1 or n2 is a connection node; skip
59600                   continue;
59601                 }
59602
59603                 nA = graph.hasEntity(nAId);
59604                 if (!nA) continue;
59605                 nB = graph.hasEntity(nBId);
59606                 if (!nB) continue;
59607                 segment1 = [n1.loc, n2.loc];
59608                 segment2 = [nA.loc, nB.loc];
59609                 var point = geoLineIntersection(segment1, segment2);
59610
59611                 if (point) {
59612                   edgeCrossInfos.push({
59613                     wayInfos: [{
59614                       way: way1,
59615                       featureType: way1FeatureType,
59616                       edge: [n1.id, n2.id]
59617                     }, {
59618                       way: way2,
59619                       featureType: way2FeatureType,
59620                       edge: [nA.id, nB.id]
59621                     }],
59622                     crossPoint: point
59623                   });
59624
59625                   if (oneOnly) {
59626                     checkedSingleCrossingWays[way2.id] = true;
59627                     break;
59628                   }
59629                 }
59630               }
59631             }
59632
59633             return edgeCrossInfos;
59634           }
59635
59636           function waysToCheck(entity, graph) {
59637             var featureType = getFeatureType(entity, graph);
59638             if (!featureType) return [];
59639
59640             if (entity.type === 'way') {
59641               return [entity];
59642             } else if (entity.type === 'relation') {
59643               return entity.members.reduce(function (array, member) {
59644                 if (member.type === 'way' && ( // only look at geometry ways
59645                 !member.role || member.role === 'outer' || member.role === 'inner')) {
59646                   var entity = graph.hasEntity(member.id); // don't add duplicates
59647
59648                   if (entity && array.indexOf(entity) === -1) {
59649                     array.push(entity);
59650                   }
59651                 }
59652
59653                 return array;
59654               }, []);
59655             }
59656
59657             return [];
59658           }
59659
59660           var validation = function checkCrossingWays(entity, graph) {
59661             var tree = context.history().tree();
59662             var ways = waysToCheck(entity, graph);
59663             var issues = []; // declare these here to reduce garbage collection
59664
59665             var wayIndex, crossingIndex, crossings;
59666
59667             for (wayIndex in ways) {
59668               crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
59669
59670               for (crossingIndex in crossings) {
59671                 issues.push(createIssue(crossings[crossingIndex], graph));
59672               }
59673             }
59674
59675             return issues;
59676           };
59677
59678           function createIssue(crossing, graph) {
59679             // use the entities with the tags that define the feature type
59680             crossing.wayInfos.sort(function (way1Info, way2Info) {
59681               var type1 = way1Info.featureType;
59682               var type2 = way2Info.featureType;
59683
59684               if (type1 === type2) {
59685                 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
59686               } else if (type1 === 'waterway') {
59687                 return true;
59688               } else if (type2 === 'waterway') {
59689                 return false;
59690               }
59691
59692               return type1 < type2;
59693             });
59694             var entities = crossing.wayInfos.map(function (wayInfo) {
59695               return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
59696             });
59697             var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
59698             var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
59699             var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
59700             var featureType1 = crossing.wayInfos[0].featureType;
59701             var featureType2 = crossing.wayInfos[1].featureType;
59702             var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
59703             var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
59704             var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
59705             var subtype = [featureType1, featureType2].sort().join('-');
59706             var crossingTypeID = subtype;
59707
59708             if (isCrossingIndoors) {
59709               crossingTypeID = 'indoor-indoor';
59710             } else if (isCrossingTunnels) {
59711               crossingTypeID = 'tunnel-tunnel';
59712             } else if (isCrossingBridges) {
59713               crossingTypeID = 'bridge-bridge';
59714             }
59715
59716             if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
59717               crossingTypeID += '_connectable';
59718             }
59719
59720             return new validationIssue({
59721               type: type,
59722               subtype: subtype,
59723               severity: 'warning',
59724               message: function message(context) {
59725                 var graph = context.graph();
59726                 var entity1 = graph.hasEntity(this.entityIds[0]),
59727                     entity2 = graph.hasEntity(this.entityIds[1]);
59728                 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
59729                   feature: utilDisplayLabel(entity1, graph),
59730                   feature2: utilDisplayLabel(entity2, graph)
59731                 }) : '';
59732               },
59733               reference: showReference,
59734               entityIds: entities.map(function (entity) {
59735                 return entity.id;
59736               }),
59737               data: {
59738                 edges: edges,
59739                 featureTypes: featureTypes,
59740                 connectionTags: connectionTags
59741               },
59742               // differentiate based on the loc since two ways can cross multiple times
59743               hash: crossing.crossPoint.toString() + // if the edges change then so does the fix
59744               edges.slice().sort(function (edge1, edge2) {
59745                 // order to assure hash is deterministic
59746                 return edge1[0] < edge2[0] ? -1 : 1;
59747               }).toString() + // ensure the correct connection tags are added in the fix
59748               JSON.stringify(connectionTags),
59749               loc: crossing.crossPoint,
59750               dynamicFixes: function dynamicFixes(context) {
59751                 var mode = context.mode();
59752                 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
59753                 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
59754                 var selectedFeatureType = this.data.featureTypes[selectedIndex];
59755                 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
59756                 var fixes = [];
59757
59758                 if (connectionTags) {
59759                   fixes.push(makeConnectWaysFix(this.data.connectionTags));
59760                 }
59761
59762                 if (isCrossingIndoors) {
59763                   fixes.push(new validationIssueFix({
59764                     icon: 'iD-icon-layers',
59765                     title: _t.html('issues.fix.use_different_levels.title')
59766                   }));
59767                 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
59768                   fixes.push(makeChangeLayerFix('higher'));
59769                   fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
59770                 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
59771                   // don't recommend adding bridges to waterways since they're uncommon
59772                   if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
59773                     fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
59774                   } // don't recommend adding tunnels under waterways since they're uncommon
59775
59776
59777                   var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
59778
59779                   if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
59780                     fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
59781                   }
59782                 } // repositioning the features is always an option
59783
59784
59785                 fixes.push(new validationIssueFix({
59786                   icon: 'iD-operation-move',
59787                   title: _t.html('issues.fix.reposition_features.title')
59788                 }));
59789                 return fixes;
59790               }
59791             });
59792
59793             function showReference(selection) {
59794               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
59795             }
59796           }
59797
59798           function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
59799             return new validationIssueFix({
59800               icon: iconName,
59801               title: _t.html('issues.fix.' + fixTitleID + '.title'),
59802               onClick: function onClick(context) {
59803                 var mode = context.mode();
59804                 if (!mode || mode.id !== 'select') return;
59805                 var selectedIDs = mode.selectedIDs();
59806                 if (selectedIDs.length !== 1) return;
59807                 var selectedWayID = selectedIDs[0];
59808                 if (!context.hasEntity(selectedWayID)) return;
59809                 var resultWayIDs = [selectedWayID];
59810                 var edge, crossedEdge, crossedWayID;
59811
59812                 if (this.issue.entityIds[0] === selectedWayID) {
59813                   edge = this.issue.data.edges[0];
59814                   crossedEdge = this.issue.data.edges[1];
59815                   crossedWayID = this.issue.entityIds[1];
59816                 } else {
59817                   edge = this.issue.data.edges[1];
59818                   crossedEdge = this.issue.data.edges[0];
59819                   crossedWayID = this.issue.entityIds[0];
59820                 }
59821
59822                 var crossingLoc = this.issue.loc;
59823                 var projection = context.projection;
59824
59825                 var action = function actionAddStructure(graph) {
59826                   var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
59827                   var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
59828
59829                   var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
59830
59831                   if (!structLengthMeters) {
59832                     // if no explicit width is set, approximate the width based on the tags
59833                     structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
59834                   }
59835
59836                   if (structLengthMeters) {
59837                     if (getFeatureType(crossedWay, graph) === 'railway') {
59838                       // bridges over railways are generally much longer than the rail bed itself, compensate
59839                       structLengthMeters *= 2;
59840                     }
59841                   } else {
59842                     // should ideally never land here since all rail/water/road tags should have an implied width
59843                     structLengthMeters = 8;
59844                   }
59845
59846                   var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
59847                   var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
59848                   var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
59849                   if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
59850
59851                   structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
59852
59853                   structLengthMeters += 4; // clamp the length to a reasonable range
59854
59855                   structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
59856
59857                   function geomToProj(geoPoint) {
59858                     return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
59859                   }
59860
59861                   function projToGeom(projPoint) {
59862                     var lat = geoMetersToLat(projPoint[1]);
59863                     return [geoMetersToLon(projPoint[0], lat), lat];
59864                   }
59865
59866                   var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
59867                   var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
59868                   var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
59869                   var projectedCrossingLoc = geomToProj(crossingLoc);
59870                   var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
59871
59872                   function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
59873                     var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
59874                     return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
59875                   }
59876
59877                   var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
59878                     return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
59879                   };
59880
59881                   var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
59882                     return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
59883                   }; // avoid creating very short edges from splitting too close to another node
59884
59885
59886                   var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
59887
59888                   function determineEndpoint(edge, endNode, locGetter) {
59889                     var newNode;
59890                     var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
59891                     // the maximum length of this side of the structure
59892
59893                     var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
59894
59895                     if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
59896                       // the edge is long enough to insert a new node
59897                       // the loc that would result in the full expected length
59898                       var idealNodeLoc = locGetter(idealLengthMeters);
59899                       newNode = osmNode();
59900                       graph = actionAddMidpoint({
59901                         loc: idealNodeLoc,
59902                         edge: edge
59903                       }, newNode)(graph);
59904                     } else {
59905                       var edgeCount = 0;
59906                       endNode.parentIntersectionWays(graph).forEach(function (way) {
59907                         way.nodes.forEach(function (nodeID) {
59908                           if (nodeID === endNode.id) {
59909                             if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
59910                               edgeCount += 1;
59911                             } else {
59912                               edgeCount += 2;
59913                             }
59914                           }
59915                         });
59916                       });
59917
59918                       if (edgeCount >= 3) {
59919                         // the end node is a junction, try to leave a segment
59920                         // between it and the structure - #7202
59921                         var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
59922
59923                         if (insetLength > minEdgeLengthMeters) {
59924                           var insetNodeLoc = locGetter(insetLength);
59925                           newNode = osmNode();
59926                           graph = actionAddMidpoint({
59927                             loc: insetNodeLoc,
59928                             edge: edge
59929                           }, newNode)(graph);
59930                         }
59931                       }
59932                     } // if the edge is too short to subdivide as desired, then
59933                     // just bound the structure at the existing end node
59934
59935
59936                     if (!newNode) newNode = endNode;
59937                     var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
59938                     // do the split
59939
59940                     graph = splitAction(graph);
59941
59942                     if (splitAction.getCreatedWayIDs().length) {
59943                       resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
59944                     }
59945
59946                     return newNode;
59947                   }
59948
59949                   var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
59950                   var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
59951                   var structureWay = resultWayIDs.map(function (id) {
59952                     return graph.entity(id);
59953                   }).find(function (way) {
59954                     return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
59955                   });
59956                   var tags = Object.assign({}, structureWay.tags); // copy tags
59957
59958                   if (bridgeOrTunnel === 'bridge') {
59959                     tags.bridge = 'yes';
59960                     tags.layer = '1';
59961                   } else {
59962                     var tunnelValue = 'yes';
59963
59964                     if (getFeatureType(structureWay, graph) === 'waterway') {
59965                       // use `tunnel=culvert` for waterways by default
59966                       tunnelValue = 'culvert';
59967                     }
59968
59969                     tags.tunnel = tunnelValue;
59970                     tags.layer = '-1';
59971                   } // apply the structure tags to the way
59972
59973
59974                   graph = actionChangeTags(structureWay.id, tags)(graph);
59975                   return graph;
59976                 };
59977
59978                 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
59979                 context.enter(modeSelect(context, resultWayIDs));
59980               }
59981             });
59982           }
59983
59984           function makeConnectWaysFix(connectionTags) {
59985             var fixTitleID = 'connect_features';
59986
59987             if (connectionTags.ford) {
59988               fixTitleID = 'connect_using_ford';
59989             }
59990
59991             return new validationIssueFix({
59992               icon: 'iD-icon-crossing',
59993               title: _t.html('issues.fix.' + fixTitleID + '.title'),
59994               onClick: function onClick(context) {
59995                 var loc = this.issue.loc;
59996                 var connectionTags = this.issue.data.connectionTags;
59997                 var edges = this.issue.data.edges;
59998                 context.perform(function actionConnectCrossingWays(graph) {
59999                   // create the new node for the points
60000                   var node = osmNode({
60001                     loc: loc,
60002                     tags: connectionTags
60003                   });
60004                   graph = graph.replace(node);
60005                   var nodesToMerge = [node.id];
60006                   var mergeThresholdInMeters = 0.75;
60007                   edges.forEach(function (edge) {
60008                     var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60009                     var closestNodeInfo = geoSphericalClosestNode(edgeNodes, loc); // if there is already a point nearby, use that
60010
60011                     if (closestNodeInfo.distance < mergeThresholdInMeters) {
60012                       nodesToMerge.push(closestNodeInfo.node.id); // else add the new node to the way
60013                     } else {
60014                       graph = actionAddMidpoint({
60015                         loc: loc,
60016                         edge: edge
60017                       }, node)(graph);
60018                     }
60019                   });
60020
60021                   if (nodesToMerge.length > 1) {
60022                     // if we're using nearby nodes, merge them with the new node
60023                     graph = actionMergeNodes(nodesToMerge, loc)(graph);
60024                   }
60025
60026                   return graph;
60027                 }, _t('issues.fix.connect_crossing_features.annotation'));
60028               }
60029             });
60030           }
60031
60032           function makeChangeLayerFix(higherOrLower) {
60033             return new validationIssueFix({
60034               icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
60035               title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
60036               onClick: function onClick(context) {
60037                 var mode = context.mode();
60038                 if (!mode || mode.id !== 'select') return;
60039                 var selectedIDs = mode.selectedIDs();
60040                 if (selectedIDs.length !== 1) return;
60041                 var selectedID = selectedIDs[0];
60042                 if (!this.issue.entityIds.some(function (entityId) {
60043                   return entityId === selectedID;
60044                 })) return;
60045                 var entity = context.hasEntity(selectedID);
60046                 if (!entity) return;
60047                 var tags = Object.assign({}, entity.tags); // shallow copy
60048
60049                 var layer = tags.layer && Number(tags.layer);
60050
60051                 if (layer && !isNaN(layer)) {
60052                   if (higherOrLower === 'higher') {
60053                     layer += 1;
60054                   } else {
60055                     layer -= 1;
60056                   }
60057                 } else {
60058                   if (higherOrLower === 'higher') {
60059                     layer = 1;
60060                   } else {
60061                     layer = -1;
60062                   }
60063                 }
60064
60065                 tags.layer = layer.toString();
60066                 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
60067               }
60068             });
60069           }
60070
60071           validation.type = type;
60072           return validation;
60073         }
60074
60075         function validationDisconnectedWay() {
60076           var type = 'disconnected_way';
60077
60078           function isTaggedAsHighway(entity) {
60079             return osmRoutableHighwayTagValues[entity.tags.highway];
60080           }
60081
60082           var validation = function checkDisconnectedWay(entity, graph) {
60083             var routingIslandWays = routingIslandForEntity(entity);
60084             if (!routingIslandWays) return [];
60085             return [new validationIssue({
60086               type: type,
60087               subtype: 'highway',
60088               severity: 'warning',
60089               message: function message(context) {
60090                 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
60091                 var label = entity && utilDisplayLabel(entity, context.graph());
60092                 return _t.html('issues.disconnected_way.routable.message', {
60093                   count: this.entityIds.length,
60094                   highway: label
60095                 });
60096               },
60097               reference: showReference,
60098               entityIds: Array.from(routingIslandWays).map(function (way) {
60099                 return way.id;
60100               }),
60101               dynamicFixes: makeFixes
60102             })];
60103
60104             function makeFixes(context) {
60105               var fixes = [];
60106               var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
60107
60108               if (singleEntity) {
60109                 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
60110                   var textDirection = _mainLocalizer.textDirection();
60111                   var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
60112                   if (startFix) fixes.push(startFix);
60113                   var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
60114                   if (endFix) fixes.push(endFix);
60115                 }
60116
60117                 if (!fixes.length) {
60118                   fixes.push(new validationIssueFix({
60119                     title: _t.html('issues.fix.connect_feature.title')
60120                   }));
60121                 }
60122
60123                 fixes.push(new validationIssueFix({
60124                   icon: 'iD-operation-delete',
60125                   title: _t.html('issues.fix.delete_feature.title'),
60126                   entityIds: [singleEntity.id],
60127                   onClick: function onClick(context) {
60128                     var id = this.issue.entityIds[0];
60129                     var operation = operationDelete(context, [id]);
60130
60131                     if (!operation.disabled()) {
60132                       operation();
60133                     }
60134                   }
60135                 }));
60136               } else {
60137                 fixes.push(new validationIssueFix({
60138                   title: _t.html('issues.fix.connect_features.title')
60139                 }));
60140               }
60141
60142               return fixes;
60143             }
60144
60145             function showReference(selection) {
60146               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
60147             }
60148
60149             function routingIslandForEntity(entity) {
60150               var routingIsland = new Set(); // the interconnected routable features
60151
60152               var waysToCheck = []; // the queue of remaining routable ways to traverse
60153
60154               function queueParentWays(node) {
60155                 graph.parentWays(node).forEach(function (parentWay) {
60156                   if (!routingIsland.has(parentWay) && // only check each feature once
60157                   isRoutableWay(parentWay, false)) {
60158                     // only check routable features
60159                     routingIsland.add(parentWay);
60160                     waysToCheck.push(parentWay);
60161                   }
60162                 });
60163               }
60164
60165               if (entity.type === 'way' && isRoutableWay(entity, true)) {
60166                 routingIsland.add(entity);
60167                 waysToCheck.push(entity);
60168               } else if (entity.type === 'node' && isRoutableNode(entity)) {
60169                 routingIsland.add(entity);
60170                 queueParentWays(entity);
60171               } else {
60172                 // this feature isn't routable, cannot be a routing island
60173                 return null;
60174               }
60175
60176               while (waysToCheck.length) {
60177                 var wayToCheck = waysToCheck.pop();
60178                 var childNodes = graph.childNodes(wayToCheck);
60179
60180                 for (var i in childNodes) {
60181                   var vertex = childNodes[i];
60182
60183                   if (isConnectedVertex(vertex)) {
60184                     // found a link to the wider network, not a routing island
60185                     return null;
60186                   }
60187
60188                   if (isRoutableNode(vertex)) {
60189                     routingIsland.add(vertex);
60190                   }
60191
60192                   queueParentWays(vertex);
60193                 }
60194               } // no network link found, this is a routing island, return its members
60195
60196
60197               return routingIsland;
60198             }
60199
60200             function isConnectedVertex(vertex) {
60201               // assume ways overlapping unloaded tiles are connected to the wider road network  - #5938
60202               var osm = services.osm;
60203               if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
60204
60205               if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
60206               if (vertex.tags.amenity === 'parking_entrance') return true;
60207               return false;
60208             }
60209
60210             function isRoutableNode(node) {
60211               // treat elevators as distinct features in the highway network
60212               if (node.tags.highway === 'elevator') return true;
60213               return false;
60214             }
60215
60216             function isRoutableWay(way, ignoreInnerWays) {
60217               if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
60218               return graph.parentRelations(way).some(function (parentRelation) {
60219                 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
60220                 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
60221                 return false;
60222               });
60223             }
60224
60225             function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
60226               var vertex = graph.hasEntity(vertexID);
60227               if (!vertex || vertex.tags.noexit === 'yes') return null;
60228               var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
60229               return new validationIssueFix({
60230                 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
60231                 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
60232                 entityIds: [vertexID],
60233                 onClick: function onClick(context) {
60234                   var wayId = this.issue.entityIds[0];
60235                   var way = context.hasEntity(wayId);
60236                   var vertexId = this.entityIds[0];
60237                   var vertex = context.hasEntity(vertexId);
60238                   if (!way || !vertex) return; // make sure the vertex is actually visible and editable
60239
60240                   var map = context.map();
60241
60242                   if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
60243                     map.zoomToEase(vertex);
60244                   }
60245
60246                   context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
60247                 }
60248               });
60249             }
60250           };
60251
60252           validation.type = type;
60253           return validation;
60254         }
60255
60256         function validationFormatting() {
60257           var type = 'invalid_format';
60258
60259           var validation = function validation(entity) {
60260             var issues = [];
60261
60262             function isValidEmail(email) {
60263               // Emails in OSM are going to be official so they should be pretty simple
60264               // Using negated lists to better support all possible unicode characters (#6494)
60265               var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
60266
60267               return !email || valid_email.test(email);
60268             }
60269             /*
60270             function isSchemePresent(url) {
60271                 var valid_scheme = /^https?:\/\//i;
60272                 return (!url || valid_scheme.test(url));
60273             }
60274             */
60275
60276
60277             function showReferenceEmail(selection) {
60278               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
60279             }
60280             /*
60281             function showReferenceWebsite(selection) {
60282                 selection.selectAll('.issue-reference')
60283                     .data([0])
60284                     .enter()
60285                     .append('div')
60286                     .attr('class', 'issue-reference')
60287                     .html(t.html('issues.invalid_format.website.reference'));
60288             }
60289              if (entity.tags.website) {
60290                 // Multiple websites are possible
60291                 // If ever we support ES6, arrow functions make this nicer
60292                 var websites = entity.tags.website
60293                     .split(';')
60294                     .map(function(s) { return s.trim(); })
60295                     .filter(function(x) { return !isSchemePresent(x); });
60296                  if (websites.length) {
60297                     issues.push(new validationIssue({
60298                         type: type,
60299                         subtype: 'website',
60300                         severity: 'warning',
60301                         message: function(context) {
60302                             var entity = context.hasEntity(this.entityIds[0]);
60303                             return entity ? t.html('issues.invalid_format.website.message' + this.data,
60304                                 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
60305                         },
60306                         reference: showReferenceWebsite,
60307                         entityIds: [entity.id],
60308                         hash: websites.join(),
60309                         data: (websites.length > 1) ? '_multi' : ''
60310                     }));
60311                 }
60312             }
60313             */
60314
60315
60316             if (entity.tags.email) {
60317               // Multiple emails are possible
60318               var emails = entity.tags.email.split(';').map(function (s) {
60319                 return s.trim();
60320               }).filter(function (x) {
60321                 return !isValidEmail(x);
60322               });
60323
60324               if (emails.length) {
60325                 issues.push(new validationIssue({
60326                   type: type,
60327                   subtype: 'email',
60328                   severity: 'warning',
60329                   message: function message(context) {
60330                     var entity = context.hasEntity(this.entityIds[0]);
60331                     return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
60332                       feature: utilDisplayLabel(entity, context.graph()),
60333                       email: emails.join(', ')
60334                     }) : '';
60335                   },
60336                   reference: showReferenceEmail,
60337                   entityIds: [entity.id],
60338                   hash: emails.join(),
60339                   data: emails.length > 1 ? '_multi' : ''
60340                 }));
60341               }
60342             }
60343
60344             return issues;
60345           };
60346
60347           validation.type = type;
60348           return validation;
60349         }
60350
60351         function validationHelpRequest(context) {
60352           var type = 'help_request';
60353
60354           var validation = function checkFixmeTag(entity) {
60355             if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
60356
60357             if (entity.version === undefined) return [];
60358
60359             if (entity.v !== undefined) {
60360               var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
60361
60362               if (!baseEntity || !baseEntity.tags.fixme) return [];
60363             }
60364
60365             return [new validationIssue({
60366               type: type,
60367               subtype: 'fixme_tag',
60368               severity: 'warning',
60369               message: function message(context) {
60370                 var entity = context.hasEntity(this.entityIds[0]);
60371                 return entity ? _t.html('issues.fixme_tag.message', {
60372                   feature: utilDisplayLabel(entity, context.graph())
60373                 }) : '';
60374               },
60375               dynamicFixes: function dynamicFixes() {
60376                 return [new validationIssueFix({
60377                   title: _t.html('issues.fix.address_the_concern.title')
60378                 })];
60379               },
60380               reference: showReference,
60381               entityIds: [entity.id]
60382             })];
60383
60384             function showReference(selection) {
60385               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
60386             }
60387           };
60388
60389           validation.type = type;
60390           return validation;
60391         }
60392
60393         function validationImpossibleOneway() {
60394           var type = 'impossible_oneway';
60395
60396           var validation = function checkImpossibleOneway(entity, graph) {
60397             if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
60398             if (entity.isClosed()) return [];
60399             if (!typeForWay(entity)) return [];
60400             if (!isOneway(entity)) return [];
60401             var firstIssues = issuesForNode(entity, entity.first());
60402             var lastIssues = issuesForNode(entity, entity.last());
60403             return firstIssues.concat(lastIssues);
60404
60405             function typeForWay(way) {
60406               if (way.geometry(graph) !== 'line') return null;
60407               if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
60408               if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
60409               return null;
60410             }
60411
60412             function isOneway(way) {
60413               if (way.tags.oneway === 'yes') return true;
60414               if (way.tags.oneway) return false;
60415
60416               for (var key in way.tags) {
60417                 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
60418                   return true;
60419                 }
60420               }
60421
60422               return false;
60423             }
60424
60425             function nodeOccursMoreThanOnce(way, nodeID) {
60426               var occurrences = 0;
60427
60428               for (var index in way.nodes) {
60429                 if (way.nodes[index] === nodeID) {
60430                   occurrences += 1;
60431                   if (occurrences > 1) return true;
60432                 }
60433               }
60434
60435               return false;
60436             }
60437
60438             function isConnectedViaOtherTypes(way, node) {
60439               var wayType = typeForWay(way);
60440
60441               if (wayType === 'highway') {
60442                 // entrances are considered connected
60443                 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
60444                 if (node.tags.amenity === 'parking_entrance') return true;
60445               } else if (wayType === 'waterway') {
60446                 if (node.id === way.first()) {
60447                   // multiple waterways may start at the same spring
60448                   if (node.tags.natural === 'spring') return true;
60449                 } else {
60450                   // multiple waterways may end at the same drain
60451                   if (node.tags.manhole === 'drain') return true;
60452                 }
60453               }
60454
60455               return graph.parentWays(node).some(function (parentWay) {
60456                 if (parentWay.id === way.id) return false;
60457
60458                 if (wayType === 'highway') {
60459                   // allow connections to highway areas
60460                   if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
60461
60462                   if (parentWay.tags.route === 'ferry') return true;
60463                   return graph.parentRelations(parentWay).some(function (parentRelation) {
60464                     if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
60465
60466                     return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
60467                   });
60468                 } else if (wayType === 'waterway') {
60469                   // multiple waterways may start or end at a water body at the same node
60470                   if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
60471                 }
60472
60473                 return false;
60474               });
60475             }
60476
60477             function issuesForNode(way, nodeID) {
60478               var isFirst = nodeID === way.first();
60479               var wayType = typeForWay(way); // ignore if this way is self-connected at this node
60480
60481               if (nodeOccursMoreThanOnce(way, nodeID)) return [];
60482               var osm = services.osm;
60483               if (!osm) return [];
60484               var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
60485
60486               if (!node || !osm.isDataLoaded(node.loc)) return [];
60487               if (isConnectedViaOtherTypes(way, node)) return [];
60488               var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
60489                 if (parentWay.id === way.id) return false;
60490                 return typeForWay(parentWay) === wayType;
60491               }); // assume it's okay for waterways to start or end disconnected for now
60492
60493               if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
60494               var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
60495                 return isOneway(attachedWay);
60496               }); // ignore if the way is connected to some non-oneway features
60497
60498               if (attachedOneways.length < attachedWaysOfSameType.length) return [];
60499
60500               if (attachedOneways.length) {
60501                 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
60502                   if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
60503                   if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
60504                   return false;
60505                 });
60506                 if (connectedEndpointsOkay) return [];
60507               }
60508
60509               var placement = isFirst ? 'start' : 'end',
60510                   messageID = wayType + '.',
60511                   referenceID = wayType + '.';
60512
60513               if (wayType === 'waterway') {
60514                 messageID += 'connected.' + placement;
60515                 referenceID += 'connected';
60516               } else {
60517                 messageID += placement;
60518                 referenceID += placement;
60519               }
60520
60521               return [new validationIssue({
60522                 type: type,
60523                 subtype: wayType,
60524                 severity: 'warning',
60525                 message: function message(context) {
60526                   var entity = context.hasEntity(this.entityIds[0]);
60527                   return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
60528                     feature: utilDisplayLabel(entity, context.graph())
60529                   }) : '';
60530                 },
60531                 reference: getReference(referenceID),
60532                 entityIds: [way.id, node.id],
60533                 dynamicFixes: function dynamicFixes() {
60534                   var fixes = [];
60535
60536                   if (attachedOneways.length) {
60537                     fixes.push(new validationIssueFix({
60538                       icon: 'iD-operation-reverse',
60539                       title: _t.html('issues.fix.reverse_feature.title'),
60540                       entityIds: [way.id],
60541                       onClick: function onClick(context) {
60542                         var id = this.issue.entityIds[0];
60543                         context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
60544                           n: 1
60545                         }));
60546                       }
60547                     }));
60548                   }
60549
60550                   if (node.tags.noexit !== 'yes') {
60551                     var textDirection = _mainLocalizer.textDirection();
60552                     var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
60553                     fixes.push(new validationIssueFix({
60554                       icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
60555                       title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
60556                       onClick: function onClick(context) {
60557                         var entityID = this.issue.entityIds[0];
60558                         var vertexID = this.issue.entityIds[1];
60559                         var way = context.entity(entityID);
60560                         var vertex = context.entity(vertexID);
60561                         continueDrawing(way, vertex, context);
60562                       }
60563                     }));
60564                   }
60565
60566                   return fixes;
60567                 },
60568                 loc: node.loc
60569               })];
60570
60571               function getReference(referenceID) {
60572                 return function showReference(selection) {
60573                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
60574                 };
60575               }
60576             }
60577           };
60578
60579           function continueDrawing(way, vertex, context) {
60580             // make sure the vertex is actually visible and editable
60581             var map = context.map();
60582
60583             if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
60584               map.zoomToEase(vertex);
60585             }
60586
60587             context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
60588           }
60589
60590           validation.type = type;
60591           return validation;
60592         }
60593
60594         function validationIncompatibleSource() {
60595           var type = 'incompatible_source';
60596           var invalidSources = [{
60597             id: 'google',
60598             regex: 'google',
60599             exceptRegex: 'books.google|Google Books|drive.google|googledrive|Google Drive'
60600           }];
60601
60602           var validation = function checkIncompatibleSource(entity) {
60603             var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
60604             if (!entitySources) return [];
60605             var issues = [];
60606             invalidSources.forEach(function (invalidSource) {
60607               var hasInvalidSource = entitySources.some(function (source) {
60608                 if (!source.match(new RegExp(invalidSource.regex, 'i'))) return false;
60609                 if (invalidSource.exceptRegex && source.match(new RegExp(invalidSource.exceptRegex, 'i'))) return false;
60610                 return true;
60611               });
60612               if (!hasInvalidSource) return;
60613               issues.push(new validationIssue({
60614                 type: type,
60615                 severity: 'warning',
60616                 message: function message(context) {
60617                   var entity = context.hasEntity(this.entityIds[0]);
60618                   return entity ? _t.html('issues.incompatible_source.' + invalidSource.id + '.feature.message', {
60619                     feature: utilDisplayLabel(entity, context.graph())
60620                   }) : '';
60621                 },
60622                 reference: getReference(invalidSource.id),
60623                 entityIds: [entity.id],
60624                 dynamicFixes: function dynamicFixes() {
60625                   return [new validationIssueFix({
60626                     title: _t.html('issues.fix.remove_proprietary_data.title')
60627                   })];
60628                 }
60629               }));
60630             });
60631             return issues;
60632
60633             function getReference(id) {
60634               return function showReference(selection) {
60635                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.incompatible_source.' + id + '.reference'));
60636               };
60637             }
60638           };
60639
60640           validation.type = type;
60641           return validation;
60642         }
60643
60644         function validationMaprules() {
60645           var type = 'maprules';
60646
60647           var validation = function checkMaprules(entity, graph) {
60648             if (!services.maprules) return [];
60649             var rules = services.maprules.validationRules();
60650             var issues = [];
60651
60652             for (var i = 0; i < rules.length; i++) {
60653               var rule = rules[i];
60654               rule.findIssues(entity, graph, issues);
60655             }
60656
60657             return issues;
60658           };
60659
60660           validation.type = type;
60661           return validation;
60662         }
60663
60664         function validationMismatchedGeometry() {
60665           var type = 'mismatched_geometry';
60666
60667           function tagSuggestingLineIsArea(entity) {
60668             if (entity.type !== 'way' || entity.isClosed()) return null;
60669             var tagSuggestingArea = entity.tagSuggestingArea();
60670
60671             if (!tagSuggestingArea) {
60672               return null;
60673             }
60674
60675             var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
60676             var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
60677
60678             if (asLine && asArea && asLine === asArea) {
60679               // these tags also allow lines and making this an area wouldn't matter
60680               return null;
60681             }
60682
60683             return tagSuggestingArea;
60684           }
60685
60686           function makeConnectEndpointsFixOnClick(way, graph) {
60687             // must have at least three nodes to close this automatically
60688             if (way.nodes.length < 3) return null;
60689             var nodes = graph.childNodes(way),
60690                 testNodes;
60691             var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
60692
60693             if (firstToLastDistanceMeters < 0.75) {
60694               testNodes = nodes.slice(); // shallow copy
60695
60696               testNodes.pop();
60697               testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
60698
60699               if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
60700                 return function (context) {
60701                   var way = context.entity(this.issue.entityIds[0]);
60702                   context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
60703                 };
60704               }
60705             } // if the points were not merged, attempt to close the way
60706
60707
60708             testNodes = nodes.slice(); // shallow copy
60709
60710             testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
60711
60712             if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
60713               return function (context) {
60714                 var wayId = this.issue.entityIds[0];
60715                 var way = context.entity(wayId);
60716                 var nodeId = way.nodes[0];
60717                 var index = way.nodes.length;
60718                 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
60719               };
60720             }
60721           }
60722
60723           function lineTaggedAsAreaIssue(entity) {
60724             var tagSuggestingArea = tagSuggestingLineIsArea(entity);
60725             if (!tagSuggestingArea) return null;
60726             return new validationIssue({
60727               type: type,
60728               subtype: 'area_as_line',
60729               severity: 'warning',
60730               message: function message(context) {
60731                 var entity = context.hasEntity(this.entityIds[0]);
60732                 return entity ? _t.html('issues.tag_suggests_area.message', {
60733                   feature: utilDisplayLabel(entity, 'area'),
60734                   tag: utilTagText({
60735                     tags: tagSuggestingArea
60736                   })
60737                 }) : '';
60738               },
60739               reference: showReference,
60740               entityIds: [entity.id],
60741               hash: JSON.stringify(tagSuggestingArea),
60742               dynamicFixes: function dynamicFixes(context) {
60743                 var fixes = [];
60744                 var entity = context.entity(this.entityIds[0]);
60745                 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
60746                 fixes.push(new validationIssueFix({
60747                   title: _t.html('issues.fix.connect_endpoints.title'),
60748                   onClick: connectEndsOnClick
60749                 }));
60750                 fixes.push(new validationIssueFix({
60751                   icon: 'iD-operation-delete',
60752                   title: _t.html('issues.fix.remove_tag.title'),
60753                   onClick: function onClick(context) {
60754                     var entityId = this.issue.entityIds[0];
60755                     var entity = context.entity(entityId);
60756                     var tags = Object.assign({}, entity.tags); // shallow copy
60757
60758                     for (var key in tagSuggestingArea) {
60759                       delete tags[key];
60760                     }
60761
60762                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
60763                   }
60764                 }));
60765                 return fixes;
60766               }
60767             });
60768
60769             function showReference(selection) {
60770               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
60771             }
60772           }
60773
60774           function vertexTaggedAsPointIssue(entity, graph) {
60775             // we only care about nodes
60776             if (entity.type !== 'node') return null; // ignore tagless points
60777
60778             if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
60779
60780             if (entity.isOnAddressLine(graph)) return null;
60781             var geometry = entity.geometry(graph);
60782             var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
60783
60784             if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
60785               return new validationIssue({
60786                 type: type,
60787                 subtype: 'vertex_as_point',
60788                 severity: 'warning',
60789                 message: function message(context) {
60790                   var entity = context.hasEntity(this.entityIds[0]);
60791                   return entity ? _t.html('issues.vertex_as_point.message', {
60792                     feature: utilDisplayLabel(entity, 'vertex')
60793                   }) : '';
60794                 },
60795                 reference: function showReference(selection) {
60796                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
60797                 },
60798                 entityIds: [entity.id]
60799               });
60800             } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
60801               return new validationIssue({
60802                 type: type,
60803                 subtype: 'point_as_vertex',
60804                 severity: 'warning',
60805                 message: function message(context) {
60806                   var entity = context.hasEntity(this.entityIds[0]);
60807                   return entity ? _t.html('issues.point_as_vertex.message', {
60808                     feature: utilDisplayLabel(entity, 'point')
60809                   }) : '';
60810                 },
60811                 reference: function showReference(selection) {
60812                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
60813                 },
60814                 entityIds: [entity.id],
60815                 dynamicFixes: function dynamicFixes(context) {
60816                   var entityId = this.entityIds[0];
60817                   var extractOnClick = null;
60818
60819                   if (!context.hasHiddenConnections(entityId)) {
60820                     extractOnClick = function extractOnClick(context) {
60821                       var entityId = this.issue.entityIds[0];
60822                       var action = actionExtract(entityId);
60823                       context.perform(action, _t('operations.extract.annotation', {
60824                         n: 1
60825                       })); // re-enter mode to trigger updates
60826
60827                       context.enter(modeSelect(context, [action.getExtractedNodeID()]));
60828                     };
60829                   }
60830
60831                   return [new validationIssueFix({
60832                     icon: 'iD-operation-extract',
60833                     title: _t.html('issues.fix.extract_point.title'),
60834                     onClick: extractOnClick
60835                   })];
60836                 }
60837               });
60838             }
60839
60840             return null;
60841           }
60842
60843           function unclosedMultipolygonPartIssues(entity, graph) {
60844             if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
60845             !entity.isComplete(graph)) return null;
60846             var sequences = osmJoinWays(entity.members, graph);
60847             var issues = [];
60848
60849             for (var i in sequences) {
60850               var sequence = sequences[i];
60851               if (!sequence.nodes) continue;
60852               var firstNode = sequence.nodes[0];
60853               var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
60854
60855               if (firstNode === lastNode) continue;
60856               var issue = new validationIssue({
60857                 type: type,
60858                 subtype: 'unclosed_multipolygon_part',
60859                 severity: 'warning',
60860                 message: function message(context) {
60861                   var entity = context.hasEntity(this.entityIds[0]);
60862                   return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
60863                     feature: utilDisplayLabel(entity, context.graph())
60864                   }) : '';
60865                 },
60866                 reference: showReference,
60867                 loc: sequence.nodes[0].loc,
60868                 entityIds: [entity.id],
60869                 hash: sequence.map(function (way) {
60870                   return way.id;
60871                 }).join()
60872               });
60873               issues.push(issue);
60874             }
60875
60876             return issues;
60877
60878             function showReference(selection) {
60879               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
60880             }
60881           }
60882
60883           var validation = function checkMismatchedGeometry(entity, graph) {
60884             var issues = [vertexTaggedAsPointIssue(entity, graph), lineTaggedAsAreaIssue(entity)];
60885             issues = issues.concat(unclosedMultipolygonPartIssues(entity, graph));
60886             return issues.filter(Boolean);
60887           };
60888
60889           validation.type = type;
60890           return validation;
60891         }
60892
60893         function validationMissingRole() {
60894           var type = 'missing_role';
60895
60896           var validation = function checkMissingRole(entity, graph) {
60897             var issues = [];
60898
60899             if (entity.type === 'way') {
60900               graph.parentRelations(entity).forEach(function (relation) {
60901                 if (!relation.isMultipolygon()) return;
60902                 var member = relation.memberById(entity.id);
60903
60904                 if (member && isMissingRole(member)) {
60905                   issues.push(makeIssue(entity, relation, member));
60906                 }
60907               });
60908             } else if (entity.type === 'relation' && entity.isMultipolygon()) {
60909               entity.indexedMembers().forEach(function (member) {
60910                 var way = graph.hasEntity(member.id);
60911
60912                 if (way && isMissingRole(member)) {
60913                   issues.push(makeIssue(way, entity, member));
60914                 }
60915               });
60916             }
60917
60918             return issues;
60919           };
60920
60921           function isMissingRole(member) {
60922             return !member.role || !member.role.trim().length;
60923           }
60924
60925           function makeIssue(way, relation, member) {
60926             return new validationIssue({
60927               type: type,
60928               severity: 'warning',
60929               message: function message(context) {
60930                 var member = context.hasEntity(this.entityIds[1]),
60931                     relation = context.hasEntity(this.entityIds[0]);
60932                 return member && relation ? _t.html('issues.missing_role.message', {
60933                   member: utilDisplayLabel(member, context.graph()),
60934                   relation: utilDisplayLabel(relation, context.graph())
60935                 }) : '';
60936               },
60937               reference: showReference,
60938               entityIds: [relation.id, way.id],
60939               data: {
60940                 member: member
60941               },
60942               hash: member.index.toString(),
60943               dynamicFixes: function dynamicFixes() {
60944                 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
60945                   icon: 'iD-operation-delete',
60946                   title: _t.html('issues.fix.remove_from_relation.title'),
60947                   onClick: function onClick(context) {
60948                     context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
60949                       n: 1
60950                     }));
60951                   }
60952                 })];
60953               }
60954             });
60955
60956             function showReference(selection) {
60957               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
60958             }
60959           }
60960
60961           function makeAddRoleFix(role) {
60962             return new validationIssueFix({
60963               title: _t.html('issues.fix.set_as_' + role + '.title'),
60964               onClick: function onClick(context) {
60965                 var oldMember = this.issue.data.member;
60966                 var member = {
60967                   id: this.issue.entityIds[1],
60968                   type: oldMember.type,
60969                   role: role
60970                 };
60971                 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
60972                   n: 1
60973                 }));
60974               }
60975             });
60976           }
60977
60978           validation.type = type;
60979           return validation;
60980         }
60981
60982         function validationMissingTag(context) {
60983           var type = 'missing_tag';
60984
60985           function hasDescriptiveTags(entity, graph) {
60986             var keys = Object.keys(entity.tags).filter(function (k) {
60987               if (k === 'area' || k === 'name') {
60988                 return false;
60989               } else {
60990                 return osmIsInterestingTag(k);
60991               }
60992             });
60993
60994             if (entity.type === 'relation' && keys.length === 1 && entity.tags.type === 'multipolygon') {
60995               // this relation's only interesting tag just says its a multipolygon,
60996               // which is not descriptive enough
60997               // It's okay for a simple multipolygon to have no descriptive tags
60998               // if its outer way has them (old model, see `outdated_tags.js`)
60999               return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
61000             }
61001
61002             return keys.length > 0;
61003           }
61004
61005           function isUnknownRoad(entity) {
61006             return entity.type === 'way' && entity.tags.highway === 'road';
61007           }
61008
61009           function isUntypedRelation(entity) {
61010             return entity.type === 'relation' && !entity.tags.type;
61011           }
61012
61013           var validation = function checkMissingTag(entity, graph) {
61014             var subtype;
61015             var osm = context.connection();
61016             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
61017
61018             if (!isUnloadedNode && // allow untagged nodes that are part of ways
61019             entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
61020             !entity.hasParentRelations(graph)) {
61021               if (Object.keys(entity.tags).length === 0) {
61022                 subtype = 'any';
61023               } else if (!hasDescriptiveTags(entity, graph)) {
61024                 subtype = 'descriptive';
61025               } else if (isUntypedRelation(entity)) {
61026                 subtype = 'relation_type';
61027               }
61028             } // flag an unknown road even if it's a member of a relation
61029
61030
61031             if (!subtype && isUnknownRoad(entity)) {
61032               subtype = 'highway_classification';
61033             }
61034
61035             if (!subtype) return [];
61036             var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
61037             var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
61038
61039             var canDelete = entity.version === undefined || entity.v !== undefined;
61040             var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
61041             return [new validationIssue({
61042               type: type,
61043               subtype: subtype,
61044               severity: severity,
61045               message: function message(context) {
61046                 var entity = context.hasEntity(this.entityIds[0]);
61047                 return entity ? _t.html('issues.' + messageID + '.message', {
61048                   feature: utilDisplayLabel(entity, context.graph())
61049                 }) : '';
61050               },
61051               reference: showReference,
61052               entityIds: [entity.id],
61053               dynamicFixes: function dynamicFixes(context) {
61054                 var fixes = [];
61055                 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
61056                 fixes.push(new validationIssueFix({
61057                   icon: 'iD-icon-search',
61058                   title: _t.html('issues.fix.' + selectFixType + '.title'),
61059                   onClick: function onClick(context) {
61060                     context.ui().sidebar.showPresetList();
61061                   }
61062                 }));
61063                 var deleteOnClick;
61064                 var id = this.entityIds[0];
61065                 var operation = operationDelete(context, [id]);
61066                 var disabledReasonID = operation.disabled();
61067
61068                 if (!disabledReasonID) {
61069                   deleteOnClick = function deleteOnClick(context) {
61070                     var id = this.issue.entityIds[0];
61071                     var operation = operationDelete(context, [id]);
61072
61073                     if (!operation.disabled()) {
61074                       operation();
61075                     }
61076                   };
61077                 }
61078
61079                 fixes.push(new validationIssueFix({
61080                   icon: 'iD-operation-delete',
61081                   title: _t.html('issues.fix.delete_feature.title'),
61082                   disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
61083                   onClick: deleteOnClick
61084                 }));
61085                 return fixes;
61086               }
61087             })];
61088
61089             function showReference(selection) {
61090               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
61091             }
61092           };
61093
61094           validation.type = type;
61095           return validation;
61096         }
61097
61098         var simplify = function simplify(str) {
61099           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());
61100         };
61101
61102         // {
61103         //   kvnd:        "amenity/fast_food|Thaï Express~(North America)",
61104         //   kvn:         "amenity/fast_food|Thaï Express",
61105         //   kv:          "amenity/fast_food",
61106         //   k:           "amenity",
61107         //   v:           "fast_food",
61108         //   n:           "Thaï Express",
61109         //   d:           "(North America)",
61110         //   nsimple:     "thaiexpress",
61111         //   kvnnsimple:  "amenity/fast_food|thaiexpress"
61112         // }
61113
61114         var to_parts = function to_parts(kvnd) {
61115           var parts = {};
61116           parts.kvnd = kvnd;
61117           var kvndparts = kvnd.split('~', 2);
61118           if (kvndparts.length > 1) parts.d = kvndparts[1];
61119           parts.kvn = kvndparts[0];
61120           var kvnparts = parts.kvn.split('|', 2);
61121           if (kvnparts.length > 1) parts.n = kvnparts[1];
61122           parts.kv = kvnparts[0];
61123           var kvparts = parts.kv.split('/', 2);
61124           parts.k = kvparts[0];
61125           parts.v = kvparts[1];
61126           parts.nsimple = simplify(parts.n);
61127           parts.kvnsimple = parts.kv + '|' + parts.nsimple;
61128           return parts;
61129         };
61130
61131         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"]};
61132         var require$$0 = {
61133         matchGroups: matchGroups
61134         };
61135
61136         var matchGroups$1 = require$$0.matchGroups;
61137
61138         var matcher$1 = function matcher() {
61139           var _warnings = []; // array of match conflict pairs
61140
61141           var _ambiguous = {};
61142           var _matchIndex = {};
61143           var matcher = {}; // Create an index of all the keys/simplenames for fast matching
61144
61145           matcher.buildMatchIndex = function (brands) {
61146             // two passes - once for primary names, once for secondary/alternate names
61147             Object.keys(brands).forEach(function (kvnd) {
61148               return insertNames(kvnd, 'primary');
61149             });
61150             Object.keys(brands).forEach(function (kvnd) {
61151               return insertNames(kvnd, 'secondary');
61152             });
61153
61154             function insertNames(kvnd, which) {
61155               var obj = brands[kvnd];
61156               var parts = to_parts(kvnd); // Exit early for ambiguous names in the second pass.
61157               // They were collected in the first pass and we don't gather alt names for them.
61158
61159               if (which === 'secondary' && parts.d) return;
61160
61161               if (obj.countryCodes) {
61162                 parts.countryCodes = obj.countryCodes.slice(); // copy
61163               }
61164
61165               var nomatches = obj.nomatch || [];
61166
61167               if (nomatches.some(function (s) {
61168                 return s === kvnd;
61169               })) {
61170                 console.log("WARNING match/nomatch conflict for ".concat(kvnd));
61171                 return;
61172               }
61173
61174               var match_kv = [parts.kv].concat(obj.matchTags || []).concat(["".concat(parts.k, "/yes"), "building/yes"]) // #3454 - match some generic tags
61175               .map(function (s) {
61176                 return s.toLowerCase();
61177               });
61178               var match_nsimple = [];
61179
61180               if (which === 'primary') {
61181                 match_nsimple = [parts.n].concat(obj.matchNames || []).concat(obj.tags.official_name || []) // #2732 - match alternate names
61182                 .map(simplify);
61183               } else if (which === 'secondary') {
61184                 match_nsimple = [].concat(obj.tags.alt_name || []) // #2732 - match alternate names
61185                 .concat(obj.tags.short_name || []) // #2732 - match alternate names
61186                 .map(simplify);
61187               }
61188
61189               if (!match_nsimple.length) return; // nothing to do
61190
61191               match_kv.forEach(function (kv) {
61192                 match_nsimple.forEach(function (nsimple) {
61193                   if (parts.d) {
61194                     // Known ambiguous names with disambiguation string ~(USA) / ~(Canada)
61195                     // FIXME: Name collisions will overwrite the initial entry (ok for now)
61196                     if (!_ambiguous[kv]) _ambiguous[kv] = {};
61197                     _ambiguous[kv][nsimple] = parts;
61198                   } else {
61199                     // Names we mostly expect to be unique..
61200                     if (!_matchIndex[kv]) _matchIndex[kv] = {};
61201                     var m = _matchIndex[kv][nsimple];
61202
61203                     if (m) {
61204                       // There already is a match for this name, skip it
61205                       // Warn if we detect collisions in a primary name.
61206                       // Skip warning if a secondary name or a generic `*=yes` tag - #2972 / #3454
61207                       if (which === 'primary' && !/\/yes$/.test(kv)) {
61208                         _warnings.push([m.kvnd, "".concat(kvnd, " (").concat(kv, "/").concat(nsimple, ")")]);
61209                       }
61210                     } else {
61211                       _matchIndex[kv][nsimple] = parts; // insert
61212                     }
61213                   }
61214                 });
61215               });
61216             }
61217           }; // pass a `key`, `value`, `name` and return the best match,
61218           // `countryCode` optional (if supplied, must match that too)
61219
61220
61221           matcher.matchKVN = function (key, value, name, countryCode) {
61222             return matcher.matchParts(to_parts("".concat(key, "/").concat(value, "|").concat(name)), countryCode);
61223           }; // pass a parts object and return the best match,
61224           // `countryCode` optional (if supplied, must match that too)
61225
61226
61227           matcher.matchParts = function (parts, countryCode) {
61228             var match = null;
61229             var inGroup = false; // fixme: we currently return a single match for ambiguous
61230
61231             match = _ambiguous[parts.kv] && _ambiguous[parts.kv][parts.nsimple];
61232             if (match && matchesCountryCode(match)) return match; // try to return an exact match
61233
61234             match = _matchIndex[parts.kv] && _matchIndex[parts.kv][parts.nsimple];
61235             if (match && matchesCountryCode(match)) return match; // look in match groups
61236
61237             for (var mg in matchGroups$1) {
61238               var matchGroup = matchGroups$1[mg];
61239               match = null;
61240               inGroup = false;
61241
61242               for (var i = 0; i < matchGroup.length; i++) {
61243                 var otherkv = matchGroup[i].toLowerCase();
61244
61245                 if (!inGroup) {
61246                   inGroup = otherkv === parts.kv;
61247                 }
61248
61249                 if (!match) {
61250                   // fixme: we currently return a single match for ambiguous
61251                   match = _ambiguous[otherkv] && _ambiguous[otherkv][parts.nsimple];
61252                 }
61253
61254                 if (!match) {
61255                   match = _matchIndex[otherkv] && _matchIndex[otherkv][parts.nsimple];
61256                 }
61257
61258                 if (match && !matchesCountryCode(match)) {
61259                   match = null;
61260                 }
61261
61262                 if (inGroup && match) {
61263                   return match;
61264                 }
61265               }
61266             }
61267
61268             return null;
61269
61270             function matchesCountryCode(match) {
61271               if (!countryCode) return true;
61272               if (!match.countryCodes) return true;
61273               return match.countryCodes.indexOf(countryCode) !== -1;
61274             }
61275           };
61276
61277           matcher.getWarnings = function () {
61278             return _warnings;
61279           };
61280
61281           return matcher;
61282         };
61283
61284         var fromCharCode = String.fromCharCode;
61285         var nativeFromCodePoint = String.fromCodePoint;
61286
61287         // length should be 1, old FF problem
61288         var INCORRECT_LENGTH = !!nativeFromCodePoint && nativeFromCodePoint.length != 1;
61289
61290         // `String.fromCodePoint` method
61291         // https://tc39.es/ecma262/#sec-string.fromcodepoint
61292         _export({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
61293           // eslint-disable-next-line no-unused-vars -- required for `.length`
61294           fromCodePoint: function fromCodePoint(x) {
61295             var elements = [];
61296             var length = arguments.length;
61297             var i = 0;
61298             var code;
61299             while (length > i) {
61300               code = +arguments[i++];
61301               if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
61302               elements.push(code < 0x10000
61303                 ? fromCharCode(code)
61304                 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
61305               );
61306             } return elements.join('');
61307           }
61308         });
61309
61310         var quickselect$2 = createCommonjsModule(function (module, exports) {
61311           (function (global, factory) {
61312              module.exports = factory() ;
61313           })(commonjsGlobal, function () {
61314
61315             function quickselect(arr, k, left, right, compare) {
61316               quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
61317             }
61318
61319             function quickselectStep(arr, k, left, right, compare) {
61320               while (right > left) {
61321                 if (right - left > 600) {
61322                   var n = right - left + 1;
61323                   var m = k - left + 1;
61324                   var z = Math.log(n);
61325                   var s = 0.5 * Math.exp(2 * z / 3);
61326                   var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
61327                   var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
61328                   var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
61329                   quickselectStep(arr, k, newLeft, newRight, compare);
61330                 }
61331
61332                 var t = arr[k];
61333                 var i = left;
61334                 var j = right;
61335                 swap(arr, left, k);
61336                 if (compare(arr[right], t) > 0) swap(arr, left, right);
61337
61338                 while (i < j) {
61339                   swap(arr, i, j);
61340                   i++;
61341                   j--;
61342
61343                   while (compare(arr[i], t) < 0) {
61344                     i++;
61345                   }
61346
61347                   while (compare(arr[j], t) > 0) {
61348                     j--;
61349                   }
61350                 }
61351
61352                 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
61353                   j++;
61354                   swap(arr, j, right);
61355                 }
61356                 if (j <= k) left = j + 1;
61357                 if (k <= j) right = j - 1;
61358               }
61359             }
61360
61361             function swap(arr, i, j) {
61362               var tmp = arr[i];
61363               arr[i] = arr[j];
61364               arr[j] = tmp;
61365             }
61366
61367             function defaultCompare(a, b) {
61368               return a < b ? -1 : a > b ? 1 : 0;
61369             }
61370
61371             return quickselect;
61372           });
61373         });
61374
61375         var rbush_1 = rbush;
61376         var _default$1 = rbush;
61377
61378         function rbush(maxEntries, format) {
61379           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
61380
61381           this._maxEntries = Math.max(4, maxEntries || 9);
61382           this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
61383
61384           if (format) {
61385             this._initFormat(format);
61386           }
61387
61388           this.clear();
61389         }
61390
61391         rbush.prototype = {
61392           all: function all() {
61393             return this._all(this.data, []);
61394           },
61395           search: function search(bbox) {
61396             var node = this.data,
61397                 result = [],
61398                 toBBox = this.toBBox;
61399             if (!intersects$1(bbox, node)) return result;
61400             var nodesToSearch = [],
61401                 i,
61402                 len,
61403                 child,
61404                 childBBox;
61405
61406             while (node) {
61407               for (i = 0, len = node.children.length; i < len; i++) {
61408                 child = node.children[i];
61409                 childBBox = node.leaf ? toBBox(child) : child;
61410
61411                 if (intersects$1(bbox, childBBox)) {
61412                   if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
61413                 }
61414               }
61415
61416               node = nodesToSearch.pop();
61417             }
61418
61419             return result;
61420           },
61421           collides: function collides(bbox) {
61422             var node = this.data,
61423                 toBBox = this.toBBox;
61424             if (!intersects$1(bbox, node)) return false;
61425             var nodesToSearch = [],
61426                 i,
61427                 len,
61428                 child,
61429                 childBBox;
61430
61431             while (node) {
61432               for (i = 0, len = node.children.length; i < len; i++) {
61433                 child = node.children[i];
61434                 childBBox = node.leaf ? toBBox(child) : child;
61435
61436                 if (intersects$1(bbox, childBBox)) {
61437                   if (node.leaf || contains$1(bbox, childBBox)) return true;
61438                   nodesToSearch.push(child);
61439                 }
61440               }
61441
61442               node = nodesToSearch.pop();
61443             }
61444
61445             return false;
61446           },
61447           load: function load(data) {
61448             if (!(data && data.length)) return this;
61449
61450             if (data.length < this._minEntries) {
61451               for (var i = 0, len = data.length; i < len; i++) {
61452                 this.insert(data[i]);
61453               }
61454
61455               return this;
61456             } // recursively build the tree with the given data from scratch using OMT algorithm
61457
61458
61459             var node = this._build(data.slice(), 0, data.length - 1, 0);
61460
61461             if (!this.data.children.length) {
61462               // save as is if tree is empty
61463               this.data = node;
61464             } else if (this.data.height === node.height) {
61465               // split root if trees have the same height
61466               this._splitRoot(this.data, node);
61467             } else {
61468               if (this.data.height < node.height) {
61469                 // swap trees if inserted one is bigger
61470                 var tmpNode = this.data;
61471                 this.data = node;
61472                 node = tmpNode;
61473               } // insert the small tree into the large tree at appropriate level
61474
61475
61476               this._insert(node, this.data.height - node.height - 1, true);
61477             }
61478
61479             return this;
61480           },
61481           insert: function insert(item) {
61482             if (item) this._insert(item, this.data.height - 1);
61483             return this;
61484           },
61485           clear: function clear() {
61486             this.data = createNode$1([]);
61487             return this;
61488           },
61489           remove: function remove(item, equalsFn) {
61490             if (!item) return this;
61491             var node = this.data,
61492                 bbox = this.toBBox(item),
61493                 path = [],
61494                 indexes = [],
61495                 i,
61496                 parent,
61497                 index,
61498                 goingUp; // depth-first iterative tree traversal
61499
61500             while (node || path.length) {
61501               if (!node) {
61502                 // go up
61503                 node = path.pop();
61504                 parent = path[path.length - 1];
61505                 i = indexes.pop();
61506                 goingUp = true;
61507               }
61508
61509               if (node.leaf) {
61510                 // check current node
61511                 index = findItem$1(item, node.children, equalsFn);
61512
61513                 if (index !== -1) {
61514                   // item found, remove the item and condense tree upwards
61515                   node.children.splice(index, 1);
61516                   path.push(node);
61517
61518                   this._condense(path);
61519
61520                   return this;
61521                 }
61522               }
61523
61524               if (!goingUp && !node.leaf && contains$1(node, bbox)) {
61525                 // go down
61526                 path.push(node);
61527                 indexes.push(i);
61528                 i = 0;
61529                 parent = node;
61530                 node = node.children[0];
61531               } else if (parent) {
61532                 // go right
61533                 i++;
61534                 node = parent.children[i];
61535                 goingUp = false;
61536               } else node = null; // nothing found
61537
61538             }
61539
61540             return this;
61541           },
61542           toBBox: function toBBox(item) {
61543             return item;
61544           },
61545           compareMinX: compareNodeMinX$1,
61546           compareMinY: compareNodeMinY$1,
61547           toJSON: function toJSON() {
61548             return this.data;
61549           },
61550           fromJSON: function fromJSON(data) {
61551             this.data = data;
61552             return this;
61553           },
61554           _all: function _all(node, result) {
61555             var nodesToSearch = [];
61556
61557             while (node) {
61558               if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
61559               node = nodesToSearch.pop();
61560             }
61561
61562             return result;
61563           },
61564           _build: function _build(items, left, right, height) {
61565             var N = right - left + 1,
61566                 M = this._maxEntries,
61567                 node;
61568
61569             if (N <= M) {
61570               // reached leaf level; return leaf
61571               node = createNode$1(items.slice(left, right + 1));
61572               calcBBox$1(node, this.toBBox);
61573               return node;
61574             }
61575
61576             if (!height) {
61577               // target height of the bulk-loaded tree
61578               height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
61579
61580               M = Math.ceil(N / Math.pow(M, height - 1));
61581             }
61582
61583             node = createNode$1([]);
61584             node.leaf = false;
61585             node.height = height; // split the items into M mostly square tiles
61586
61587             var N2 = Math.ceil(N / M),
61588                 N1 = N2 * Math.ceil(Math.sqrt(M)),
61589                 i,
61590                 j,
61591                 right2,
61592                 right3;
61593             multiSelect$1(items, left, right, N1, this.compareMinX);
61594
61595             for (i = left; i <= right; i += N1) {
61596               right2 = Math.min(i + N1 - 1, right);
61597               multiSelect$1(items, i, right2, N2, this.compareMinY);
61598
61599               for (j = i; j <= right2; j += N2) {
61600                 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
61601
61602                 node.children.push(this._build(items, j, right3, height - 1));
61603               }
61604             }
61605
61606             calcBBox$1(node, this.toBBox);
61607             return node;
61608           },
61609           _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
61610             var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
61611
61612             while (true) {
61613               path.push(node);
61614               if (node.leaf || path.length - 1 === level) break;
61615               minArea = minEnlargement = Infinity;
61616
61617               for (i = 0, len = node.children.length; i < len; i++) {
61618                 child = node.children[i];
61619                 area = bboxArea$1(child);
61620                 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
61621
61622                 if (enlargement < minEnlargement) {
61623                   minEnlargement = enlargement;
61624                   minArea = area < minArea ? area : minArea;
61625                   targetNode = child;
61626                 } else if (enlargement === minEnlargement) {
61627                   // otherwise choose one with the smallest area
61628                   if (area < minArea) {
61629                     minArea = area;
61630                     targetNode = child;
61631                   }
61632                 }
61633               }
61634
61635               node = targetNode || node.children[0];
61636             }
61637
61638             return node;
61639           },
61640           _insert: function _insert(item, level, isNode) {
61641             var toBBox = this.toBBox,
61642                 bbox = isNode ? item : toBBox(item),
61643                 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
61644
61645             var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
61646
61647
61648             node.children.push(item);
61649             extend$3(node, bbox); // split on node overflow; propagate upwards if necessary
61650
61651             while (level >= 0) {
61652               if (insertPath[level].children.length > this._maxEntries) {
61653                 this._split(insertPath, level);
61654
61655                 level--;
61656               } else break;
61657             } // adjust bboxes along the insertion path
61658
61659
61660             this._adjustParentBBoxes(bbox, insertPath, level);
61661           },
61662           // split overflowed node into two
61663           _split: function _split(insertPath, level) {
61664             var node = insertPath[level],
61665                 M = node.children.length,
61666                 m = this._minEntries;
61667
61668             this._chooseSplitAxis(node, m, M);
61669
61670             var splitIndex = this._chooseSplitIndex(node, m, M);
61671
61672             var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
61673             newNode.height = node.height;
61674             newNode.leaf = node.leaf;
61675             calcBBox$1(node, this.toBBox);
61676             calcBBox$1(newNode, this.toBBox);
61677             if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
61678           },
61679           _splitRoot: function _splitRoot(node, newNode) {
61680             // split root node
61681             this.data = createNode$1([node, newNode]);
61682             this.data.height = node.height + 1;
61683             this.data.leaf = false;
61684             calcBBox$1(this.data, this.toBBox);
61685           },
61686           _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
61687             var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
61688             minOverlap = minArea = Infinity;
61689
61690             for (i = m; i <= M - m; i++) {
61691               bbox1 = distBBox$1(node, 0, i, this.toBBox);
61692               bbox2 = distBBox$1(node, i, M, this.toBBox);
61693               overlap = intersectionArea$1(bbox1, bbox2);
61694               area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
61695
61696               if (overlap < minOverlap) {
61697                 minOverlap = overlap;
61698                 index = i;
61699                 minArea = area < minArea ? area : minArea;
61700               } else if (overlap === minOverlap) {
61701                 // otherwise choose distribution with minimum area
61702                 if (area < minArea) {
61703                   minArea = area;
61704                   index = i;
61705                 }
61706               }
61707             }
61708
61709             return index;
61710           },
61711           // sorts node children by the best axis for split
61712           _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
61713             var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
61714                 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
61715                 xMargin = this._allDistMargin(node, m, M, compareMinX),
61716                 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
61717             // otherwise it's already sorted by minY
61718
61719
61720             if (xMargin < yMargin) node.children.sort(compareMinX);
61721           },
61722           // total margin of all possible split distributions where each node is at least m full
61723           _allDistMargin: function _allDistMargin(node, m, M, compare) {
61724             node.children.sort(compare);
61725             var toBBox = this.toBBox,
61726                 leftBBox = distBBox$1(node, 0, m, toBBox),
61727                 rightBBox = distBBox$1(node, M - m, M, toBBox),
61728                 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
61729                 i,
61730                 child;
61731
61732             for (i = m; i < M - m; i++) {
61733               child = node.children[i];
61734               extend$3(leftBBox, node.leaf ? toBBox(child) : child);
61735               margin += bboxMargin$1(leftBBox);
61736             }
61737
61738             for (i = M - m - 1; i >= m; i--) {
61739               child = node.children[i];
61740               extend$3(rightBBox, node.leaf ? toBBox(child) : child);
61741               margin += bboxMargin$1(rightBBox);
61742             }
61743
61744             return margin;
61745           },
61746           _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
61747             // adjust bboxes along the given tree path
61748             for (var i = level; i >= 0; i--) {
61749               extend$3(path[i], bbox);
61750             }
61751           },
61752           _condense: function _condense(path) {
61753             // go through the path, removing empty nodes and updating bboxes
61754             for (var i = path.length - 1, siblings; i >= 0; i--) {
61755               if (path[i].children.length === 0) {
61756                 if (i > 0) {
61757                   siblings = path[i - 1].children;
61758                   siblings.splice(siblings.indexOf(path[i]), 1);
61759                 } else this.clear();
61760               } else calcBBox$1(path[i], this.toBBox);
61761             }
61762           },
61763           _initFormat: function _initFormat(format) {
61764             // data format (minX, minY, maxX, maxY accessors)
61765             // uses eval-type function compilation instead of just accepting a toBBox function
61766             // because the algorithms are very sensitive to sorting functions performance,
61767             // so they should be dead simple and without inner calls
61768             var compareArr = ['return a', ' - b', ';'];
61769             this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
61770             this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
61771             this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
61772           }
61773         };
61774
61775         function findItem$1(item, items, equalsFn) {
61776           if (!equalsFn) return items.indexOf(item);
61777
61778           for (var i = 0; i < items.length; i++) {
61779             if (equalsFn(item, items[i])) return i;
61780           }
61781
61782           return -1;
61783         } // calculate node's bbox from bboxes of its children
61784
61785
61786         function calcBBox$1(node, toBBox) {
61787           distBBox$1(node, 0, node.children.length, toBBox, node);
61788         } // min bounding rectangle of node children from k to p-1
61789
61790
61791         function distBBox$1(node, k, p, toBBox, destNode) {
61792           if (!destNode) destNode = createNode$1(null);
61793           destNode.minX = Infinity;
61794           destNode.minY = Infinity;
61795           destNode.maxX = -Infinity;
61796           destNode.maxY = -Infinity;
61797
61798           for (var i = k, child; i < p; i++) {
61799             child = node.children[i];
61800             extend$3(destNode, node.leaf ? toBBox(child) : child);
61801           }
61802
61803           return destNode;
61804         }
61805
61806         function extend$3(a, b) {
61807           a.minX = Math.min(a.minX, b.minX);
61808           a.minY = Math.min(a.minY, b.minY);
61809           a.maxX = Math.max(a.maxX, b.maxX);
61810           a.maxY = Math.max(a.maxY, b.maxY);
61811           return a;
61812         }
61813
61814         function compareNodeMinX$1(a, b) {
61815           return a.minX - b.minX;
61816         }
61817
61818         function compareNodeMinY$1(a, b) {
61819           return a.minY - b.minY;
61820         }
61821
61822         function bboxArea$1(a) {
61823           return (a.maxX - a.minX) * (a.maxY - a.minY);
61824         }
61825
61826         function bboxMargin$1(a) {
61827           return a.maxX - a.minX + (a.maxY - a.minY);
61828         }
61829
61830         function enlargedArea$1(a, b) {
61831           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));
61832         }
61833
61834         function intersectionArea$1(a, b) {
61835           var minX = Math.max(a.minX, b.minX),
61836               minY = Math.max(a.minY, b.minY),
61837               maxX = Math.min(a.maxX, b.maxX),
61838               maxY = Math.min(a.maxY, b.maxY);
61839           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
61840         }
61841
61842         function contains$1(a, b) {
61843           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
61844         }
61845
61846         function intersects$1(a, b) {
61847           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
61848         }
61849
61850         function createNode$1(children) {
61851           return {
61852             children: children,
61853             height: 1,
61854             leaf: true,
61855             minX: Infinity,
61856             minY: Infinity,
61857             maxX: -Infinity,
61858             maxY: -Infinity
61859           };
61860         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
61861         // combines selection algorithm with binary divide & conquer approach
61862
61863
61864         function multiSelect$1(arr, left, right, n, compare) {
61865           var stack = [left, right],
61866               mid;
61867
61868           while (stack.length) {
61869             right = stack.pop();
61870             left = stack.pop();
61871             if (right - left <= n) continue;
61872             mid = left + Math.ceil((right - left) / n / 2) * n;
61873             quickselect$2(arr, mid, left, right, compare);
61874             stack.push(left, mid, mid, right);
61875           }
61876         }
61877         rbush_1["default"] = _default$1;
61878
61879         var lineclip_1 = lineclip$1;
61880         lineclip$1.polyline = lineclip$1;
61881         lineclip$1.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
61882         // handle polylines rather than just segments
61883
61884         function lineclip$1(points, bbox, result) {
61885           var len = points.length,
61886               codeA = bitCode$1(points[0], bbox),
61887               part = [],
61888               i,
61889               a,
61890               b,
61891               codeB,
61892               lastCode;
61893           if (!result) result = [];
61894
61895           for (i = 1; i < len; i++) {
61896             a = points[i - 1];
61897             b = points[i];
61898             codeB = lastCode = bitCode$1(b, bbox);
61899
61900             while (true) {
61901               if (!(codeA | codeB)) {
61902                 // accept
61903                 part.push(a);
61904
61905                 if (codeB !== lastCode) {
61906                   // segment went outside
61907                   part.push(b);
61908
61909                   if (i < len - 1) {
61910                     // start a new line
61911                     result.push(part);
61912                     part = [];
61913                   }
61914                 } else if (i === len - 1) {
61915                   part.push(b);
61916                 }
61917
61918                 break;
61919               } else if (codeA & codeB) {
61920                 // trivial reject
61921                 break;
61922               } else if (codeA) {
61923                 // a outside, intersect with clip edge
61924                 a = intersect$1(a, b, codeA, bbox);
61925                 codeA = bitCode$1(a, bbox);
61926               } else {
61927                 // b outside
61928                 b = intersect$1(a, b, codeB, bbox);
61929                 codeB = bitCode$1(b, bbox);
61930               }
61931             }
61932
61933             codeA = lastCode;
61934           }
61935
61936           if (part.length) result.push(part);
61937           return result;
61938         } // Sutherland-Hodgeman polygon clipping algorithm
61939
61940
61941         function polygonclip$1(points, bbox) {
61942           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
61943
61944           for (edge = 1; edge <= 8; edge *= 2) {
61945             result = [];
61946             prev = points[points.length - 1];
61947             prevInside = !(bitCode$1(prev, bbox) & edge);
61948
61949             for (i = 0; i < points.length; i++) {
61950               p = points[i];
61951               inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
61952
61953               if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
61954               if (inside) result.push(p); // add a point if it's inside
61955
61956               prev = p;
61957               prevInside = inside;
61958             }
61959
61960             points = result;
61961             if (!points.length) break;
61962           }
61963
61964           return result;
61965         } // intersect a segment against one of the 4 lines that make up the bbox
61966
61967
61968         function intersect$1(a, b, edge, bbox) {
61969           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
61970           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
61971           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
61972           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
61973           null;
61974         } // bit code reflects the point position relative to the bbox:
61975         //         left  mid  right
61976         //    top  1001  1000  1010
61977         //    mid  0001  0000  0010
61978         // bottom  0101  0100  0110
61979
61980
61981         function bitCode$1(p, bbox) {
61982           var code = 0;
61983           if (p[0] < bbox[0]) code |= 1; // left
61984           else if (p[0] > bbox[2]) code |= 2; // right
61985
61986           if (p[1] < bbox[1]) code |= 4; // bottom
61987           else if (p[1] > bbox[3]) code |= 8; // top
61988
61989           return code;
61990         }
61991
61992         var whichPolygon_1 = whichPolygon;
61993
61994         function whichPolygon(data) {
61995           var bboxes = [];
61996
61997           for (var i = 0; i < data.features.length; i++) {
61998             var feature = data.features[i];
61999             var coords = feature.geometry.coordinates;
62000
62001             if (feature.geometry.type === 'Polygon') {
62002               bboxes.push(treeItem(coords, feature.properties));
62003             } else if (feature.geometry.type === 'MultiPolygon') {
62004               for (var j = 0; j < coords.length; j++) {
62005                 bboxes.push(treeItem(coords[j], feature.properties));
62006               }
62007             }
62008           }
62009
62010           var tree = rbush_1().load(bboxes);
62011
62012           function query(p, multi) {
62013             var output = [],
62014                 result = tree.search({
62015               minX: p[0],
62016               minY: p[1],
62017               maxX: p[0],
62018               maxY: p[1]
62019             });
62020
62021             for (var i = 0; i < result.length; i++) {
62022               if (insidePolygon(result[i].coords, p)) {
62023                 if (multi) output.push(result[i].props);else return result[i].props;
62024               }
62025             }
62026
62027             return multi && output.length ? output : null;
62028           }
62029
62030           query.tree = tree;
62031
62032           query.bbox = function queryBBox(bbox) {
62033             var output = [];
62034             var result = tree.search({
62035               minX: bbox[0],
62036               minY: bbox[1],
62037               maxX: bbox[2],
62038               maxY: bbox[3]
62039             });
62040
62041             for (var i = 0; i < result.length; i++) {
62042               if (polygonIntersectsBBox(result[i].coords, bbox)) {
62043                 output.push(result[i].props);
62044               }
62045             }
62046
62047             return output;
62048           };
62049
62050           return query;
62051         }
62052
62053         function polygonIntersectsBBox(polygon, bbox) {
62054           var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
62055           if (insidePolygon(polygon, bboxCenter)) return true;
62056
62057           for (var i = 0; i < polygon.length; i++) {
62058             if (lineclip_1(polygon[i], bbox).length > 0) return true;
62059           }
62060
62061           return false;
62062         } // ray casting algorithm for detecting if point is in polygon
62063
62064
62065         function insidePolygon(rings, p) {
62066           var inside = false;
62067
62068           for (var i = 0, len = rings.length; i < len; i++) {
62069             var ring = rings[i];
62070
62071             for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
62072               if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
62073             }
62074           }
62075
62076           return inside;
62077         }
62078
62079         function rayIntersect(p, p1, p2) {
62080           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];
62081         }
62082
62083         function treeItem(coords, props) {
62084           var item = {
62085             minX: Infinity,
62086             minY: Infinity,
62087             maxX: -Infinity,
62088             maxY: -Infinity,
62089             coords: coords,
62090             props: props
62091           };
62092
62093           for (var i = 0; i < coords[0].length; i++) {
62094             var p = coords[0][i];
62095             item.minX = Math.min(item.minX, p[0]);
62096             item.minY = Math.min(item.minY, p[1]);
62097             item.maxX = Math.max(item.maxX, p[0]);
62098             item.maxY = Math.max(item.maxY, p[1]);
62099           }
62100
62101           return item;
62102         }
62103
62104         var type = "FeatureCollection";
62105         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]]]]}}];
62106         var rawBorders = {
62107         type: type,
62108         features: features
62109         };
62110
62111         var borders = rawBorders;
62112         var whichPolygonGetter = {};
62113         var featuresByCode = {};
62114         var idFilterRegex = /\bThe\b|\bthe\b|\band\b|\bof\b|[-_ .,()&[\]/]/g;
62115         var levels = ['subterritory', 'territory', 'country', 'intermediateRegion', 'subregion', 'region', 'union', 'world'];
62116         loadDerivedDataAndCaches(borders);
62117
62118         function loadDerivedDataAndCaches(borders) {
62119           var identifierProps = ['iso1A2', 'iso1A3', 'm49', 'wikidata', 'emojiFlag', 'nameEn'];
62120           var geometryFeatures = [];
62121
62122           for (var i in borders.features) {
62123             var _feature = borders.features[i];
62124             _feature.properties.id = _feature.properties.iso1A2 || _feature.properties.m49;
62125             loadM49(_feature);
62126             loadIsoStatus(_feature);
62127             loadLevel(_feature);
62128             loadGroups(_feature);
62129             loadRoadSpeedUnit(_feature);
62130             loadDriveSide(_feature);
62131             loadFlag(_feature);
62132             cacheFeatureByIDs(_feature);
62133             if (_feature.geometry) geometryFeatures.push(_feature);
62134           }
62135
62136           for (var _i in borders.features) {
62137             var _feature2 = borders.features[_i];
62138
62139             _feature2.properties.groups.sort(function (groupID1, groupID2) {
62140               return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
62141             });
62142
62143             loadMembersForGroupsOf(_feature2);
62144           }
62145
62146           var geometryOnlyCollection = {
62147             type: 'RegionFeatureCollection',
62148             features: geometryFeatures
62149           };
62150           whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
62151
62152           function loadGroups(feature) {
62153             var props = feature.properties;
62154
62155             if (!props.groups) {
62156               props.groups = [];
62157             }
62158
62159             if (props.country) {
62160               props.groups.push(props.country);
62161             }
62162
62163             if (props.m49 !== '001') {
62164               props.groups.push('001');
62165             }
62166           }
62167
62168           function loadM49(feature) {
62169             var props = feature.properties;
62170
62171             if (!props.m49 && props.iso1N3) {
62172               props.m49 = props.iso1N3;
62173             }
62174           }
62175
62176           function loadIsoStatus(feature) {
62177             var props = feature.properties;
62178
62179             if (!props.isoStatus && props.iso1A2) {
62180               props.isoStatus = 'official';
62181             }
62182           }
62183
62184           function loadLevel(feature) {
62185             var props = feature.properties;
62186             if (props.level) return;
62187
62188             if (!props.country) {
62189               props.level = 'country';
62190             } else if (props.isoStatus === 'official') {
62191               props.level = 'territory';
62192             } else {
62193               props.level = 'subterritory';
62194             }
62195           }
62196
62197           function loadRoadSpeedUnit(feature) {
62198             var props = feature.properties;
62199
62200             if (props.roadSpeedUnit === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
62201               props.roadSpeedUnit = 'km/h';
62202             }
62203           }
62204
62205           function loadDriveSide(feature) {
62206             var props = feature.properties;
62207
62208             if (props.driveSide === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
62209               props.driveSide = 'right';
62210             }
62211           }
62212
62213           function loadFlag(feature) {
62214             if (!feature.properties.iso1A2) return;
62215             var flag = feature.properties.iso1A2.replace(/./g, function (_char) {
62216               return String.fromCodePoint(_char.charCodeAt(0) + 127397);
62217             });
62218             feature.properties.emojiFlag = flag;
62219           }
62220
62221           function loadMembersForGroupsOf(feature) {
62222             var featureID = feature.properties.id;
62223             var standardizedGroupIDs = [];
62224
62225             for (var j in feature.properties.groups) {
62226               var groupID = feature.properties.groups[j];
62227               var groupFeature = featuresByCode[groupID];
62228               standardizedGroupIDs.push(groupFeature.properties.id);
62229
62230               if (groupFeature.properties.members) {
62231                 groupFeature.properties.members.push(featureID);
62232               } else {
62233                 groupFeature.properties.members = [featureID];
62234               }
62235             }
62236
62237             feature.properties.groups = standardizedGroupIDs;
62238           }
62239
62240           function cacheFeatureByIDs(feature) {
62241             for (var k in identifierProps) {
62242               var prop = identifierProps[k];
62243               var id = prop && feature.properties[prop];
62244
62245               if (id) {
62246                 id = id.replace(idFilterRegex, '').toUpperCase();
62247                 featuresByCode[id] = feature;
62248               }
62249             }
62250
62251             if (feature.properties.aliases) {
62252               for (var j in feature.properties.aliases) {
62253                 var alias = feature.properties.aliases[j].replace(idFilterRegex, '').toUpperCase();
62254                 featuresByCode[alias] = feature;
62255               }
62256             }
62257           }
62258         }
62259
62260         function locArray(loc) {
62261           if (Array.isArray(loc)) {
62262             return loc;
62263           } else if (loc.coordinates) {
62264             return loc.coordinates;
62265           }
62266
62267           return loc.geometry.coordinates;
62268         }
62269
62270         function smallestFeature(loc) {
62271           var query = locArray(loc);
62272           var featureProperties = whichPolygonGetter(query);
62273           if (!featureProperties) return null;
62274           return featuresByCode[featureProperties.id];
62275         }
62276
62277         function countryFeature(loc) {
62278           var feature = smallestFeature(loc);
62279           if (!feature) return null;
62280           var countryCode = feature.properties.country || feature.properties.iso1A2;
62281           return featuresByCode[countryCode];
62282         }
62283
62284         function featureForLoc(loc, opts) {
62285           if (opts && opts.level && opts.level !== 'country') {
62286             var features = featuresContaining(loc);
62287             var targetLevel = opts.level;
62288             var targetLevelIndex = levels.indexOf(targetLevel);
62289             if (targetLevelIndex === -1) return null;
62290
62291             for (var i in features) {
62292               var _feature3 = features[i];
62293
62294               if (_feature3.properties.level === targetLevel || levels.indexOf(_feature3.properties.level) > targetLevelIndex) {
62295                 return _feature3;
62296               }
62297             }
62298
62299             return null;
62300           }
62301
62302           return countryFeature(loc);
62303         }
62304
62305         function featureForID(id) {
62306           var stringID;
62307
62308           if (typeof id === 'number') {
62309             stringID = id.toString();
62310
62311             if (stringID.length === 1) {
62312               stringID = '00' + stringID;
62313             } else if (stringID.length === 2) {
62314               stringID = '0' + stringID;
62315             }
62316           } else {
62317             stringID = id.replace(idFilterRegex, '').toUpperCase();
62318           }
62319
62320           return featuresByCode[stringID] || null;
62321         }
62322
62323         function smallestOrMatchingFeature(query) {
62324           if (_typeof(query) === 'object') {
62325             return smallestFeature(query);
62326           }
62327
62328           return featureForID(query);
62329         }
62330
62331         function feature$1(query, opts) {
62332           if (_typeof(query) === 'object') {
62333             return featureForLoc(query, opts);
62334           }
62335
62336           return featureForID(query);
62337         }
62338         function iso1A2Code(query, opts) {
62339           var match = feature$1(query, opts);
62340           if (!match) return null;
62341           return match.properties.iso1A2 || null;
62342         }
62343         function featuresContaining(query, strict) {
62344           var feature = smallestOrMatchingFeature(query);
62345           if (!feature) return [];
62346           var features = [];
62347
62348           if (!strict || _typeof(query) === 'object') {
62349             features.push(feature);
62350           }
62351
62352           var properties = feature.properties;
62353
62354           for (var i in properties.groups) {
62355             var groupID = properties.groups[i];
62356             features.push(featuresByCode[groupID]);
62357           }
62358
62359           return features;
62360         }
62361         function roadSpeedUnit(query) {
62362           var feature = smallestOrMatchingFeature(query);
62363           return feature && feature.properties.roadSpeedUnit || null;
62364         }
62365
62366         var _dataDeprecated;
62367
62368         var _nsi;
62369
62370         function validationOutdatedTags() {
62371           var type = 'outdated_tags';
62372           var nsiKeys = ['amenity', 'shop', 'tourism', 'leisure', 'office']; // A concern here in switching to async data means that `_dataDeprecated`
62373           // and `_nsi` will not be available at first, so the data on early tiles
62374           // may not have tags validated fully.
62375           // initialize deprecated tags array
62376
62377           _mainFileFetcher.get('deprecated').then(function (d) {
62378             return _dataDeprecated = d;
62379           })["catch"](function () {
62380             /* ignore */
62381           });
62382           _mainFileFetcher.get('nsi_brands').then(function (d) {
62383             _nsi = {
62384               brands: d.brands,
62385               matcher: matcher$1(),
62386               wikidata: {},
62387               wikipedia: {}
62388             }; // initialize name-suggestion-index matcher
62389
62390             _nsi.matcher.buildMatchIndex(d.brands); // index all known wikipedia and wikidata tags
62391
62392
62393             Object.keys(d.brands).forEach(function (kvnd) {
62394               var brand = d.brands[kvnd];
62395               var wd = brand.tags['brand:wikidata'];
62396               var wp = brand.tags['brand:wikipedia'];
62397
62398               if (wd) {
62399                 _nsi.wikidata[wd] = kvnd;
62400               }
62401
62402               if (wp) {
62403                 _nsi.wikipedia[wp] = kvnd;
62404               }
62405             });
62406             return _nsi;
62407           })["catch"](function () {
62408             /* ignore */
62409           });
62410
62411           function oldTagIssues(entity, graph) {
62412             var oldTags = Object.assign({}, entity.tags); // shallow copy
62413
62414             var preset = _mainPresetIndex.match(entity, graph);
62415             var subtype = 'deprecated_tags';
62416             if (!preset) return []; // upgrade preset..
62417
62418             if (preset.replacement) {
62419               var newPreset = _mainPresetIndex.item(preset.replacement);
62420               graph = actionChangePreset(entity.id, preset, newPreset, true
62421               /* skip field defaults */
62422               )(graph);
62423               entity = graph.entity(entity.id);
62424               preset = newPreset;
62425             } // upgrade tags..
62426
62427
62428             if (_dataDeprecated) {
62429               var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
62430
62431               if (deprecatedTags.length) {
62432                 deprecatedTags.forEach(function (tag) {
62433                   graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
62434                 });
62435                 entity = graph.entity(entity.id);
62436               }
62437             } // add missing addTags..
62438
62439
62440             var newTags = Object.assign({}, entity.tags); // shallow copy
62441
62442             if (preset.tags !== preset.addTags) {
62443               Object.keys(preset.addTags).forEach(function (k) {
62444                 if (!newTags[k]) {
62445                   if (preset.addTags[k] === '*') {
62446                     newTags[k] = 'yes';
62447                   } else {
62448                     newTags[k] = preset.addTags[k];
62449                   }
62450                 }
62451               });
62452             }
62453
62454             if (_nsi) {
62455               // Do `wikidata` or `wikipedia` identify this entity as a brand?  #6416
62456               // If so, these tags can be swapped to `brand:wikidata`/`brand:wikipedia`
62457               var isBrand;
62458
62459               if (newTags.wikidata) {
62460                 // try matching `wikidata`
62461                 isBrand = _nsi.wikidata[newTags.wikidata];
62462               }
62463
62464               if (!isBrand && newTags.wikipedia) {
62465                 // fallback to `wikipedia`
62466                 isBrand = _nsi.wikipedia[newTags.wikipedia];
62467               }
62468
62469               if (isBrand && !newTags.office) {
62470                 // but avoid doing this for corporate offices
62471                 if (newTags.wikidata) {
62472                   newTags['brand:wikidata'] = newTags.wikidata;
62473                   delete newTags.wikidata;
62474                 }
62475
62476                 if (newTags.wikipedia) {
62477                   newTags['brand:wikipedia'] = newTags.wikipedia;
62478                   delete newTags.wikipedia;
62479                 } // I considered setting `name` and other tags here, but they aren't unique per wikidata
62480                 // (Q2759586 -> in USA "Papa John's", in Russia "Папа Джонс")
62481                 // So users will really need to use a preset or assign `name` themselves.
62482
62483               } // try key/value|name match against name-suggestion-index
62484
62485
62486               if (newTags.name) {
62487                 for (var i = 0; i < nsiKeys.length; i++) {
62488                   var k = nsiKeys[i];
62489                   if (!newTags[k]) continue;
62490                   var center = entity.extent(graph).center();
62491                   var countryCode = iso1A2Code(center);
62492
62493                   var match = _nsi.matcher.matchKVN(k, newTags[k], newTags.name, countryCode && countryCode.toLowerCase());
62494
62495                   if (!match) continue; // for now skip ambiguous matches (like Target~(USA) vs Target~(Australia))
62496
62497                   if (match.d) continue;
62498                   var brand = _nsi.brands[match.kvnd];
62499
62500                   if (brand && brand.tags['brand:wikidata'] && brand.tags['brand:wikidata'] !== entity.tags['not:brand:wikidata']) {
62501                     subtype = 'noncanonical_brand';
62502                     var keepTags = ['takeaway'].reduce(function (acc, k) {
62503                       if (newTags[k]) {
62504                         acc[k] = newTags[k];
62505                       }
62506
62507                       return acc;
62508                     }, {});
62509                     nsiKeys.forEach(function (k) {
62510                       return delete newTags[k];
62511                     });
62512                     Object.assign(newTags, brand.tags, keepTags);
62513                     break;
62514                   }
62515                 }
62516               }
62517             } // determine diff
62518
62519
62520             var tagDiff = utilTagDiff(oldTags, newTags);
62521             if (!tagDiff.length) return [];
62522             var isOnlyAddingTags = tagDiff.every(function (d) {
62523               return d.type === '+';
62524             });
62525             var prefix = '';
62526
62527             if (subtype === 'noncanonical_brand') {
62528               prefix = 'noncanonical_brand.';
62529             } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
62530               subtype = 'incomplete_tags';
62531               prefix = 'incomplete.';
62532             } // don't allow autofixing brand tags
62533
62534
62535             var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
62536             return [new validationIssue({
62537               type: type,
62538               subtype: subtype,
62539               severity: 'warning',
62540               message: showMessage,
62541               reference: showReference,
62542               entityIds: [entity.id],
62543               hash: JSON.stringify(tagDiff),
62544               dynamicFixes: function dynamicFixes() {
62545                 return [new validationIssueFix({
62546                   autoArgs: autoArgs,
62547                   title: _t.html('issues.fix.upgrade_tags.title'),
62548                   onClick: function onClick(context) {
62549                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
62550                   }
62551                 })];
62552               }
62553             })];
62554
62555             function doUpgrade(graph) {
62556               var currEntity = graph.hasEntity(entity.id);
62557               if (!currEntity) return graph;
62558               var newTags = Object.assign({}, currEntity.tags); // shallow copy
62559
62560               tagDiff.forEach(function (diff) {
62561                 if (diff.type === '-') {
62562                   delete newTags[diff.key];
62563                 } else if (diff.type === '+') {
62564                   newTags[diff.key] = diff.newVal;
62565                 }
62566               });
62567               return actionChangeTags(currEntity.id, newTags)(graph);
62568             }
62569
62570             function showMessage(context) {
62571               var currEntity = context.hasEntity(entity.id);
62572               if (!currEntity) return '';
62573               var messageID = "issues.outdated_tags.".concat(prefix, "message");
62574
62575               if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
62576                 messageID += '_incomplete';
62577               }
62578
62579               return _t.html(messageID, {
62580                 feature: utilDisplayLabel(currEntity, context.graph())
62581               });
62582             }
62583
62584             function showReference(selection) {
62585               var enter = selection.selectAll('.issue-reference').data([0]).enter();
62586               enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
62587               enter.append('strong').html(_t.html('issues.suggested'));
62588               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) {
62589                 var klass = d.type === '+' ? 'add' : 'remove';
62590                 return "tagDiff-cell tagDiff-cell-".concat(klass);
62591               }).html(function (d) {
62592                 return d.display;
62593               });
62594             }
62595           }
62596
62597           function oldMultipolygonIssues(entity, graph) {
62598             var multipolygon, outerWay;
62599
62600             if (entity.type === 'relation') {
62601               outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
62602               multipolygon = entity;
62603             } else if (entity.type === 'way') {
62604               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
62605               outerWay = entity;
62606             } else {
62607               return [];
62608             }
62609
62610             if (!multipolygon || !outerWay) return [];
62611             return [new validationIssue({
62612               type: type,
62613               subtype: 'old_multipolygon',
62614               severity: 'warning',
62615               message: showMessage,
62616               reference: showReference,
62617               entityIds: [outerWay.id, multipolygon.id],
62618               dynamicFixes: function dynamicFixes() {
62619                 return [new validationIssueFix({
62620                   autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
62621                   title: _t.html('issues.fix.move_tags.title'),
62622                   onClick: function onClick(context) {
62623                     context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
62624                   }
62625                 })];
62626               }
62627             })];
62628
62629             function doUpgrade(graph) {
62630               var currMultipolygon = graph.hasEntity(multipolygon.id);
62631               var currOuterWay = graph.hasEntity(outerWay.id);
62632               if (!currMultipolygon || !currOuterWay) return graph;
62633               currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
62634               graph = graph.replace(currMultipolygon);
62635               return actionChangeTags(currOuterWay.id, {})(graph);
62636             }
62637
62638             function showMessage(context) {
62639               var currMultipolygon = context.hasEntity(multipolygon.id);
62640               if (!currMultipolygon) return '';
62641               return _t.html('issues.old_multipolygon.message', {
62642                 multipolygon: utilDisplayLabel(currMultipolygon, context.graph())
62643               });
62644             }
62645
62646             function showReference(selection) {
62647               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
62648             }
62649           }
62650
62651           var validation = function checkOutdatedTags(entity, graph) {
62652             var issues = oldMultipolygonIssues(entity, graph);
62653             if (!issues.length) issues = oldTagIssues(entity, graph);
62654             return issues;
62655           };
62656
62657           validation.type = type;
62658           return validation;
62659         }
62660
62661         function validationPrivateData() {
62662           var type = 'private_data'; // assume that some buildings are private
62663
62664           var privateBuildingValues = {
62665             detached: true,
62666             farm: true,
62667             house: true,
62668             houseboat: true,
62669             residential: true,
62670             semidetached_house: true,
62671             static_caravan: true
62672           }; // but they might be public if they have one of these other tags
62673
62674           var publicKeys = {
62675             amenity: true,
62676             craft: true,
62677             historic: true,
62678             leisure: true,
62679             office: true,
62680             shop: true,
62681             tourism: true
62682           }; // these tags may contain personally identifying info
62683
62684           var personalTags = {
62685             'contact:email': true,
62686             'contact:fax': true,
62687             'contact:phone': true,
62688             email: true,
62689             fax: true,
62690             phone: true
62691           };
62692
62693           var validation = function checkPrivateData(entity) {
62694             var tags = entity.tags;
62695             if (!tags.building || !privateBuildingValues[tags.building]) return [];
62696             var keepTags = {};
62697
62698             for (var k in tags) {
62699               if (publicKeys[k]) return []; // probably a public feature
62700
62701               if (!personalTags[k]) {
62702                 keepTags[k] = tags[k];
62703               }
62704             }
62705
62706             var tagDiff = utilTagDiff(tags, keepTags);
62707             if (!tagDiff.length) return [];
62708             var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
62709             return [new validationIssue({
62710               type: type,
62711               severity: 'warning',
62712               message: showMessage,
62713               reference: showReference,
62714               entityIds: [entity.id],
62715               dynamicFixes: function dynamicFixes() {
62716                 return [new validationIssueFix({
62717                   icon: 'iD-operation-delete',
62718                   title: _t.html('issues.fix.' + fixID + '.title'),
62719                   onClick: function onClick(context) {
62720                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
62721                   }
62722                 })];
62723               }
62724             })];
62725
62726             function doUpgrade(graph) {
62727               var currEntity = graph.hasEntity(entity.id);
62728               if (!currEntity) return graph;
62729               var newTags = Object.assign({}, currEntity.tags); // shallow copy
62730
62731               tagDiff.forEach(function (diff) {
62732                 if (diff.type === '-') {
62733                   delete newTags[diff.key];
62734                 } else if (diff.type === '+') {
62735                   newTags[diff.key] = diff.newVal;
62736                 }
62737               });
62738               return actionChangeTags(currEntity.id, newTags)(graph);
62739             }
62740
62741             function showMessage(context) {
62742               var currEntity = context.hasEntity(this.entityIds[0]);
62743               if (!currEntity) return '';
62744               return _t.html('issues.private_data.contact.message', {
62745                 feature: utilDisplayLabel(currEntity, context.graph())
62746               });
62747             }
62748
62749             function showReference(selection) {
62750               var enter = selection.selectAll('.issue-reference').data([0]).enter();
62751               enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
62752               enter.append('strong').html(_t.html('issues.suggested'));
62753               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) {
62754                 var klass = d.type === '+' ? 'add' : 'remove';
62755                 return 'tagDiff-cell tagDiff-cell-' + klass;
62756               }).html(function (d) {
62757                 return d.display;
62758               });
62759             }
62760           };
62761
62762           validation.type = type;
62763           return validation;
62764         }
62765
62766         var _discardNameRegexes = [];
62767         function validationSuspiciousName() {
62768           var type = 'suspicious_name';
62769           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
62770           // be available at first, so the data on early tiles may not have tags validated fully.
62771
62772           _mainFileFetcher.get('nsi_filters').then(function (filters) {
62773             // known list of generic names (e.g. "bar")
62774             _discardNameRegexes = filters.discardNames.map(function (discardName) {
62775               return new RegExp(discardName, 'i');
62776             });
62777           })["catch"](function () {
62778             /* ignore */
62779           });
62780
62781           function isDiscardedSuggestionName(lowercaseName) {
62782             return _discardNameRegexes.some(function (regex) {
62783               return regex.test(lowercaseName);
62784             });
62785           } // test if the name is just the key or tag value (e.g. "park")
62786
62787
62788           function nameMatchesRawTag(lowercaseName, tags) {
62789             for (var i = 0; i < keysToTestForGenericValues.length; i++) {
62790               var key = keysToTestForGenericValues[i];
62791               var val = tags[key];
62792
62793               if (val) {
62794                 val = val.toLowerCase();
62795
62796                 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
62797                   return true;
62798                 }
62799               }
62800             }
62801
62802             return false;
62803           }
62804
62805           function isGenericName(name, tags) {
62806             name = name.toLowerCase();
62807             return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
62808           }
62809
62810           function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
62811             return new validationIssue({
62812               type: type,
62813               subtype: 'generic_name',
62814               severity: 'warning',
62815               message: function message(context) {
62816                 var entity = context.hasEntity(this.entityIds[0]);
62817                 if (!entity) return '';
62818                 var preset = _mainPresetIndex.match(entity, context.graph());
62819                 var langName = langCode && _mainLocalizer.languageName(langCode);
62820                 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
62821                   feature: preset.name(),
62822                   name: genericName,
62823                   language: langName
62824                 });
62825               },
62826               reference: showReference,
62827               entityIds: [entityId],
62828               hash: nameKey + '=' + genericName,
62829               dynamicFixes: function dynamicFixes() {
62830                 return [new validationIssueFix({
62831                   icon: 'iD-operation-delete',
62832                   title: _t.html('issues.fix.remove_the_name.title'),
62833                   onClick: function onClick(context) {
62834                     var entityId = this.issue.entityIds[0];
62835                     var entity = context.entity(entityId);
62836                     var tags = Object.assign({}, entity.tags); // shallow copy
62837
62838                     delete tags[nameKey];
62839                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
62840                   }
62841                 })];
62842               }
62843             });
62844
62845             function showReference(selection) {
62846               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
62847             }
62848           }
62849
62850           function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
62851             return new validationIssue({
62852               type: type,
62853               subtype: 'not_name',
62854               severity: 'warning',
62855               message: function message(context) {
62856                 var entity = context.hasEntity(this.entityIds[0]);
62857                 if (!entity) return '';
62858                 var preset = _mainPresetIndex.match(entity, context.graph());
62859                 var langName = langCode && _mainLocalizer.languageName(langCode);
62860                 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
62861                   feature: preset.name(),
62862                   name: incorrectName,
62863                   language: langName
62864                 });
62865               },
62866               reference: showReference,
62867               entityIds: [entityId],
62868               hash: nameKey + '=' + incorrectName,
62869               dynamicFixes: function dynamicFixes() {
62870                 return [new validationIssueFix({
62871                   icon: 'iD-operation-delete',
62872                   title: _t.html('issues.fix.remove_the_name.title'),
62873                   onClick: function onClick(context) {
62874                     var entityId = this.issue.entityIds[0];
62875                     var entity = context.entity(entityId);
62876                     var tags = Object.assign({}, entity.tags); // shallow copy
62877
62878                     delete tags[nameKey];
62879                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
62880                   }
62881                 })];
62882               }
62883             });
62884
62885             function showReference(selection) {
62886               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
62887             }
62888           }
62889
62890           var validation = function checkGenericName(entity) {
62891             // a generic name is okay if it's a known brand or entity
62892             if (entity.hasWikidata()) return [];
62893             var issues = [];
62894             var notNames = (entity.tags['not:name'] || '').split(';');
62895
62896             for (var key in entity.tags) {
62897               var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
62898               if (!m) continue;
62899               var langCode = m.length >= 2 ? m[1] : null;
62900               var value = entity.tags[key];
62901
62902               if (notNames.length) {
62903                 for (var i in notNames) {
62904                   var notName = notNames[i];
62905
62906                   if (notName && value === notName) {
62907                     issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
62908                     continue;
62909                   }
62910                 }
62911               }
62912
62913               if (isGenericName(value, entity.tags)) {
62914                 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
62915               }
62916             }
62917
62918             return issues;
62919           };
62920
62921           validation.type = type;
62922           return validation;
62923         }
62924
62925         function validationUnsquareWay(context) {
62926           var type = 'unsquare_way';
62927           var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
62928           // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
62929
62930           var epsilon = 0.05;
62931           var nodeThreshold = 10;
62932
62933           function isBuilding(entity, graph) {
62934             if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
62935             return entity.tags.building && entity.tags.building !== 'no';
62936           }
62937
62938           var validation = function checkUnsquareWay(entity, graph) {
62939             if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
62940
62941             if (entity.tags.nonsquare === 'yes') return [];
62942             var isClosed = entity.isClosed();
62943             if (!isClosed) return []; // this building has bigger problems
62944             // don't flag ways with lots of nodes since they are likely detail-mapped
62945
62946             var nodes = graph.childNodes(entity).slice(); // shallow copy
62947
62948             if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
62949             // ignore if not all nodes are fully downloaded
62950
62951             var osm = services.osm;
62952             if (!osm || nodes.some(function (node) {
62953               return !osm.isDataLoaded(node.loc);
62954             })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
62955
62956             var hasConnectedSquarableWays = nodes.some(function (node) {
62957               return graph.parentWays(node).some(function (way) {
62958                 if (way.id === entity.id) return false;
62959                 if (isBuilding(way, graph)) return true;
62960                 return graph.parentRelations(way).some(function (parentRelation) {
62961                   return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
62962                 });
62963               });
62964             });
62965             if (hasConnectedSquarableWays) return []; // user-configurable square threshold
62966
62967             var storedDegreeThreshold = corePreferences('validate-square-degrees');
62968             var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
62969             var points = nodes.map(function (node) {
62970               return context.projection(node.loc);
62971             });
62972             if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
62973             var autoArgs; // don't allow autosquaring features linked to wikidata
62974
62975             if (!entity.tags.wikidata) {
62976               // use same degree threshold as for detection
62977               var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
62978               autoAction.transitionable = false; // when autofixing, do it instantly
62979
62980               autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
62981                 n: 1
62982               })];
62983             }
62984
62985             return [new validationIssue({
62986               type: type,
62987               subtype: 'building',
62988               severity: 'warning',
62989               message: function message(context) {
62990                 var entity = context.hasEntity(this.entityIds[0]);
62991                 return entity ? _t.html('issues.unsquare_way.message', {
62992                   feature: utilDisplayLabel(entity, context.graph())
62993                 }) : '';
62994               },
62995               reference: showReference,
62996               entityIds: [entity.id],
62997               hash: JSON.stringify(autoArgs !== undefined) + degreeThreshold,
62998               dynamicFixes: function dynamicFixes() {
62999                 return [new validationIssueFix({
63000                   icon: 'iD-operation-orthogonalize',
63001                   title: _t.html('issues.fix.square_feature.title'),
63002                   autoArgs: autoArgs,
63003                   onClick: function onClick(context, completionHandler) {
63004                     var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
63005
63006                     context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
63007                       n: 1
63008                     })); // run after the squaring transition (currently 150ms)
63009
63010                     window.setTimeout(function () {
63011                       completionHandler();
63012                     }, 175);
63013                   }
63014                 })
63015                 /*
63016                 new validationIssueFix({
63017                     title: t.html('issues.fix.tag_as_unsquare.title'),
63018                     onClick: function(context) {
63019                         var entityId = this.issue.entityIds[0];
63020                         var entity = context.entity(entityId);
63021                         var tags = Object.assign({}, entity.tags);  // shallow copy
63022                         tags.nonsquare = 'yes';
63023                         context.perform(
63024                             actionChangeTags(entityId, tags),
63025                             t('issues.fix.tag_as_unsquare.annotation')
63026                         );
63027                     }
63028                 })
63029                 */
63030                 ];
63031               }
63032             })];
63033
63034             function showReference(selection) {
63035               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
63036             }
63037           };
63038
63039           validation.type = type;
63040           return validation;
63041         }
63042
63043         var Validations = /*#__PURE__*/Object.freeze({
63044                 __proto__: null,
63045                 validationAlmostJunction: validationAlmostJunction,
63046                 validationCloseNodes: validationCloseNodes,
63047                 validationCrossingWays: validationCrossingWays,
63048                 validationDisconnectedWay: validationDisconnectedWay,
63049                 validationFormatting: validationFormatting,
63050                 validationHelpRequest: validationHelpRequest,
63051                 validationImpossibleOneway: validationImpossibleOneway,
63052                 validationIncompatibleSource: validationIncompatibleSource,
63053                 validationMaprules: validationMaprules,
63054                 validationMismatchedGeometry: validationMismatchedGeometry,
63055                 validationMissingRole: validationMissingRole,
63056                 validationMissingTag: validationMissingTag,
63057                 validationOutdatedTags: validationOutdatedTags,
63058                 validationPrivateData: validationPrivateData,
63059                 validationSuspiciousName: validationSuspiciousName,
63060                 validationUnsquareWay: validationUnsquareWay
63061         });
63062
63063         function coreValidator(context) {
63064           var dispatch$1 = dispatch('validated', 'focusedIssue');
63065           var validator = utilRebind({}, dispatch$1, 'on');
63066           var _rules = {};
63067           var _disabledRules = {};
63068           var _ignoredIssueIDs = {}; // issue.id -> true
63069
63070           var _baseCache = validationCache(); // issues before any user edits
63071
63072
63073           var _headCache = validationCache(); // issues after all user edits
63074
63075
63076           var _validatedGraph = null;
63077
63078           var _deferred = new Set(); //
63079           // initialize the validator rulesets
63080           //
63081
63082
63083           validator.init = function () {
63084             Object.values(Validations).forEach(function (validation) {
63085               if (typeof validation !== 'function') return;
63086               var fn = validation(context);
63087               var key = fn.type;
63088               _rules[key] = fn;
63089             });
63090             var disabledRules = corePreferences('validate-disabledRules');
63091
63092             if (disabledRules) {
63093               disabledRules.split(',').forEach(function (key) {
63094                 _disabledRules[key] = true;
63095               });
63096             }
63097           };
63098
63099           function reset(resetIgnored) {
63100             Array.from(_deferred).forEach(function (handle) {
63101               window.cancelIdleCallback(handle);
63102
63103               _deferred["delete"](handle);
63104             }); // clear caches
63105
63106             if (resetIgnored) _ignoredIssueIDs = {};
63107             _baseCache = validationCache();
63108             _headCache = validationCache();
63109             _validatedGraph = null;
63110           } //
63111           // clear caches, called whenever iD resets after a save
63112           //
63113
63114
63115           validator.reset = function () {
63116             reset(true);
63117           };
63118
63119           validator.resetIgnoredIssues = function () {
63120             _ignoredIssueIDs = {}; // reload UI
63121
63122             dispatch$1.call('validated');
63123           }; // must update issues when the user changes the unsquare thereshold
63124
63125
63126           validator.reloadUnsquareIssues = function () {
63127             reloadUnsquareIssues(_headCache, context.graph());
63128             reloadUnsquareIssues(_baseCache, context.history().base());
63129             dispatch$1.call('validated');
63130           };
63131
63132           function reloadUnsquareIssues(cache, graph) {
63133             var checkUnsquareWay = _rules.unsquare_way;
63134             if (typeof checkUnsquareWay !== 'function') return; // uncache existing
63135
63136             cache.uncacheIssuesOfType('unsquare_way');
63137             var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), graph) // everywhere
63138             .filter(function (entity) {
63139               return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
63140             }); // rerun for all buildings
63141
63142             buildings.forEach(function (entity) {
63143               var detected = checkUnsquareWay(entity, graph);
63144               if (detected.length !== 1) return;
63145               var issue = detected[0];
63146
63147               if (!cache.issuesByEntityID[entity.id]) {
63148                 cache.issuesByEntityID[entity.id] = new Set();
63149               }
63150
63151               cache.issuesByEntityID[entity.id].add(issue.id);
63152               cache.issuesByIssueID[issue.id] = issue;
63153             });
63154           } // options = {
63155           //     what: 'all',     // 'all' or 'edited'
63156           //     where: 'all',   // 'all' or 'visible'
63157           //     includeIgnored: false   // true, false, or 'only'
63158           //     includeDisabledRules: false   // true, false, or 'only'
63159           // };
63160
63161
63162           validator.getIssues = function (options) {
63163             var opts = Object.assign({
63164               what: 'all',
63165               where: 'all',
63166               includeIgnored: false,
63167               includeDisabledRules: false
63168             }, options);
63169             var issues = Object.values(_headCache.issuesByIssueID);
63170             var view = context.map().extent();
63171             return issues.filter(function (issue) {
63172               if (!issue) return false;
63173               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
63174               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
63175               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
63176               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false; // Sanity check:  This issue may be for an entity that not longer exists.
63177               // If we detect this, uncache and return false so it is not included..
63178
63179               var entityIds = issue.entityIds || [];
63180
63181               for (var i = 0; i < entityIds.length; i++) {
63182                 var entityId = entityIds[i];
63183
63184                 if (!context.hasEntity(entityId)) {
63185                   delete _headCache.issuesByEntityID[entityId];
63186                   delete _headCache.issuesByIssueID[issue.id];
63187                   return false;
63188                 }
63189               }
63190
63191               if (opts.what === 'edited' && _baseCache.issuesByIssueID[issue.id]) return false;
63192
63193               if (opts.where === 'visible') {
63194                 var extent = issue.extent(context.graph());
63195                 if (!view.intersects(extent)) return false;
63196               }
63197
63198               return true;
63199             });
63200           };
63201
63202           validator.getResolvedIssues = function () {
63203             var baseIssues = Object.values(_baseCache.issuesByIssueID);
63204             return baseIssues.filter(function (issue) {
63205               return !_headCache.issuesByIssueID[issue.id];
63206             });
63207           };
63208
63209           validator.focusIssue = function (issue) {
63210             var extent = issue.extent(context.graph());
63211
63212             if (extent) {
63213               var setZoom = Math.max(context.map().zoom(), 19);
63214               context.map().unobscuredCenterZoomEase(extent.center(), setZoom); // select the first entity
63215
63216               if (issue.entityIds && issue.entityIds.length) {
63217                 window.setTimeout(function () {
63218                   var ids = issue.entityIds;
63219                   context.enter(modeSelect(context, [ids[0]]));
63220                   dispatch$1.call('focusedIssue', this, issue);
63221                 }, 250); // after ease
63222               }
63223             }
63224           };
63225
63226           validator.getIssuesBySeverity = function (options) {
63227             var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
63228             groups.error = groups.error || [];
63229             groups.warning = groups.warning || [];
63230             return groups;
63231           }; // show some issue types in a particular order
63232
63233
63234           var orderedIssueTypes = [// flag missing data first
63235           'missing_tag', 'missing_role', // then flag identity issues
63236           'outdated_tags', 'mismatched_geometry', // flag geometry issues where fixing them might solve connectivity issues
63237           'crossing_ways', 'almost_junction', // then flag connectivity issues
63238           'disconnected_way', 'impossible_oneway']; // returns the issues that the given entity IDs have in common, matching the given options
63239
63240           validator.getSharedEntityIssues = function (entityIDs, options) {
63241             var cache = _headCache; // gather the issues that are common to all the entities
63242
63243             var issueIDs = entityIDs.reduce(function (acc, entityID) {
63244               var entityIssueIDs = cache.issuesByEntityID[entityID] || new Set();
63245
63246               if (!acc) {
63247                 return new Set(entityIssueIDs);
63248               }
63249
63250               return new Set(_toConsumableArray(acc).filter(function (elem) {
63251                 return entityIssueIDs.has(elem);
63252               }));
63253             }, null) || [];
63254             var opts = options || {};
63255             return Array.from(issueIDs).map(function (id) {
63256               return cache.issuesByIssueID[id];
63257             }).filter(function (issue) {
63258               if (!issue) return false;
63259               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
63260               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
63261               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
63262               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false;
63263               return true;
63264             }).sort(function (issue1, issue2) {
63265               if (issue1.type === issue2.type) {
63266                 // issues of the same type, sort deterministically
63267                 return issue1.id < issue2.id ? -1 : 1;
63268               }
63269
63270               var index1 = orderedIssueTypes.indexOf(issue1.type);
63271               var index2 = orderedIssueTypes.indexOf(issue2.type);
63272
63273               if (index1 !== -1 && index2 !== -1) {
63274                 // both issue types have explicit sort orders
63275                 return index1 - index2;
63276               } else if (index1 === -1 && index2 === -1) {
63277                 // neither issue type has an explicit sort order, sort by type
63278                 return issue1.type < issue2.type ? -1 : 1;
63279               } else {
63280                 // order explicit types before everything else
63281                 return index1 !== -1 ? -1 : 1;
63282               }
63283             });
63284           };
63285
63286           validator.getEntityIssues = function (entityID, options) {
63287             return validator.getSharedEntityIssues([entityID], options);
63288           };
63289
63290           validator.getRuleKeys = function () {
63291             return Object.keys(_rules);
63292           };
63293
63294           validator.isRuleEnabled = function (key) {
63295             return !_disabledRules[key];
63296           };
63297
63298           validator.toggleRule = function (key) {
63299             if (_disabledRules[key]) {
63300               delete _disabledRules[key];
63301             } else {
63302               _disabledRules[key] = true;
63303             }
63304
63305             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
63306             validator.validate();
63307           };
63308
63309           validator.disableRules = function (keys) {
63310             _disabledRules = {};
63311             keys.forEach(function (k) {
63312               _disabledRules[k] = true;
63313             });
63314             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
63315             validator.validate();
63316           };
63317
63318           validator.ignoreIssue = function (id) {
63319             _ignoredIssueIDs[id] = true;
63320           }; //
63321           // Run validation on a single entity for the given graph
63322           //
63323
63324
63325           function validateEntity(entity, graph) {
63326             var entityIssues = []; // runs validation and appends resulting issues
63327
63328             function runValidation(key) {
63329               var fn = _rules[key];
63330
63331               if (typeof fn !== 'function') {
63332                 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
63333
63334                 return;
63335               }
63336
63337               var detected = fn(entity, graph);
63338               entityIssues = entityIssues.concat(detected);
63339             } // run all rules
63340
63341
63342             Object.keys(_rules).forEach(runValidation);
63343             return entityIssues;
63344           }
63345
63346           function entityIDsToValidate(entityIDs, graph) {
63347             var processedIDs = new Set();
63348             return entityIDs.reduce(function (acc, entityID) {
63349               // keep redundancy check separate from `acc` because an `entityID`
63350               // could have been added to `acc` as a related entity through an earlier pass
63351               if (processedIDs.has(entityID)) return acc;
63352               processedIDs.add(entityID);
63353               var entity = graph.hasEntity(entityID);
63354               if (!entity) return acc;
63355               acc.add(entityID);
63356               var checkParentRels = [entity];
63357
63358               if (entity.type === 'node') {
63359                 graph.parentWays(entity).forEach(function (parentWay) {
63360                   acc.add(parentWay.id); // include parent ways
63361
63362                   checkParentRels.push(parentWay);
63363                 });
63364               } else if (entity.type === 'relation') {
63365                 entity.members.forEach(function (member) {
63366                   acc.add(member.id); // include members
63367                 });
63368               } else if (entity.type === 'way') {
63369                 entity.nodes.forEach(function (nodeID) {
63370                   acc.add(nodeID); // include child nodes
63371
63372                   graph._parentWays[nodeID].forEach(function (wayID) {
63373                     acc.add(wayID); // include connected ways
63374                   });
63375                 });
63376               }
63377
63378               checkParentRels.forEach(function (entity) {
63379                 // include parent relations
63380                 if (entity.type !== 'relation') {
63381                   // but not super-relations
63382                   graph.parentRelations(entity).forEach(function (parentRelation) {
63383                     acc.add(parentRelation.id);
63384                   });
63385                 }
63386               });
63387               return acc;
63388             }, new Set());
63389           } //
63390           // Run validation for several entities, supplied `entityIDs`,
63391           // against `graph` for the given `cache`
63392           //
63393
63394
63395           function validateEntities(entityIDs, graph, cache) {
63396             // clear caches for existing issues related to these entities
63397             entityIDs.forEach(cache.uncacheEntityID); // detect new issues and update caches
63398
63399             entityIDs.forEach(function (entityID) {
63400               var entity = graph.hasEntity(entityID); // don't validate deleted entities
63401
63402               if (!entity) return;
63403               var issues = validateEntity(entity, graph);
63404               cache.cacheIssues(issues);
63405             });
63406           } //
63407           // Validates anything that has changed since the last time it was run.
63408           // Also updates the "validatedGraph" to be the current graph
63409           // and dispatches a `validated` event when finished.
63410           //
63411
63412
63413           validator.validate = function () {
63414             var currGraph = context.graph();
63415             _validatedGraph = _validatedGraph || context.history().base();
63416
63417             if (currGraph === _validatedGraph) {
63418               dispatch$1.call('validated');
63419               return;
63420             }
63421
63422             var oldGraph = _validatedGraph;
63423             var difference = coreDifference(oldGraph, currGraph);
63424             _validatedGraph = currGraph;
63425             var createdAndModifiedEntityIDs = difference.extantIDs(true); // created/modified (true = w/relation members)
63426
63427             var entityIDsToCheck = entityIDsToValidate(createdAndModifiedEntityIDs, currGraph); // check modified and deleted entities against the old graph in order to update their related entities
63428             // (e.g. deleting the only highway connected to a road should create a disconnected highway issue)
63429
63430             var modifiedAndDeletedEntityIDs = difference.deleted().concat(difference.modified()).map(function (entity) {
63431               return entity.id;
63432             });
63433             var entityIDsToCheckForOldGraph = entityIDsToValidate(modifiedAndDeletedEntityIDs, oldGraph); // concat the sets
63434
63435             entityIDsToCheckForOldGraph.forEach(entityIDsToCheck.add, entityIDsToCheck);
63436             validateEntities(entityIDsToCheck, context.graph(), _headCache);
63437             dispatch$1.call('validated');
63438           };
63439
63440           context.history().on('reset.validator', function () {
63441             // cached issues aren't valid any longer if the history has been reset
63442             reset(false);
63443             validator.validate();
63444           }); // WHEN TO RUN VALIDATION:
63445           // When graph changes:
63446
63447           context.history().on('restore.validator', validator.validate) // restore saved history
63448           .on('undone.validator', validator.validate) // undo
63449           .on('redone.validator', validator.validate); // redo
63450           // but not on 'change' (e.g. while drawing)
63451           // When user changes editing modes:
63452
63453           context.on('exit.validator', validator.validate); // When merging fetched data:
63454
63455           context.history().on('merge.validator', function (entities) {
63456             if (!entities) return;
63457             var handle = window.requestIdleCallback(function () {
63458               var entityIDs = entities.map(function (entity) {
63459                 return entity.id;
63460               });
63461               var headGraph = context.graph();
63462               validateEntities(entityIDsToValidate(entityIDs, headGraph), headGraph, _headCache);
63463               var baseGraph = context.history().base();
63464               validateEntities(entityIDsToValidate(entityIDs, baseGraph), baseGraph, _baseCache);
63465               dispatch$1.call('validated');
63466             });
63467
63468             _deferred.add(handle);
63469           });
63470           return validator;
63471         }
63472
63473         function validationCache() {
63474           var cache = {
63475             issuesByIssueID: {},
63476             // issue.id -> issue
63477             issuesByEntityID: {} // entity.id -> set(issue.id)
63478
63479           };
63480
63481           cache.cacheIssues = function (issues) {
63482             issues.forEach(function (issue) {
63483               var entityIds = issue.entityIds || [];
63484               entityIds.forEach(function (entityId) {
63485                 if (!cache.issuesByEntityID[entityId]) {
63486                   cache.issuesByEntityID[entityId] = new Set();
63487                 }
63488
63489                 cache.issuesByEntityID[entityId].add(issue.id);
63490               });
63491               cache.issuesByIssueID[issue.id] = issue;
63492             });
63493           };
63494
63495           cache.uncacheIssue = function (issue) {
63496             // When multiple entities are involved (e.g. crossing_ways),
63497             // remove this issue from the other entity caches too..
63498             var entityIds = issue.entityIds || [];
63499             entityIds.forEach(function (entityId) {
63500               if (cache.issuesByEntityID[entityId]) {
63501                 cache.issuesByEntityID[entityId]["delete"](issue.id);
63502               }
63503             });
63504             delete cache.issuesByIssueID[issue.id];
63505           };
63506
63507           cache.uncacheIssues = function (issues) {
63508             issues.forEach(cache.uncacheIssue);
63509           };
63510
63511           cache.uncacheIssuesOfType = function (type) {
63512             var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
63513               return issue.type === type;
63514             });
63515             cache.uncacheIssues(issuesOfType);
63516           }; //
63517           // Remove a single entity and all its related issues from the caches
63518           //
63519
63520
63521           cache.uncacheEntityID = function (entityID) {
63522             var issueIDs = cache.issuesByEntityID[entityID];
63523             if (!issueIDs) return;
63524             issueIDs.forEach(function (issueID) {
63525               var issue = cache.issuesByIssueID[issueID];
63526
63527               if (issue) {
63528                 cache.uncacheIssue(issue);
63529               } else {
63530                 delete cache.issuesByIssueID[issueID];
63531               }
63532             });
63533             delete cache.issuesByEntityID[entityID];
63534           };
63535
63536           return cache;
63537         }
63538
63539         function coreUploader(context) {
63540           var dispatch$1 = dispatch( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
63541           'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
63542           'saveEnded', // dispatched after the result event has been dispatched
63543           'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
63544           'progressChanged', // Each save results in one of these outcomes:
63545           'resultNoChanges', // upload wasn't attempted since there were no edits
63546           'resultErrors', // upload failed due to errors
63547           'resultConflicts', // upload failed due to data conflicts
63548           'resultSuccess' // upload completed without errors
63549           );
63550           var _isSaving = false;
63551           var _conflicts = [];
63552           var _errors = [];
63553
63554           var _origChanges;
63555
63556           var _discardTags = {};
63557           _mainFileFetcher.get('discarded').then(function (d) {
63558             _discardTags = d;
63559           })["catch"](function () {
63560             /* ignore */
63561           });
63562           var uploader = utilRebind({}, dispatch$1, 'on');
63563
63564           uploader.isSaving = function () {
63565             return _isSaving;
63566           };
63567
63568           uploader.save = function (changeset, tryAgain, checkConflicts) {
63569             // Guard against accidentally entering save code twice - #4641
63570             if (_isSaving && !tryAgain) {
63571               return;
63572             }
63573
63574             var osm = context.connection();
63575             if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
63576             // This can happen if they were logged in from before, but the tokens are no longer valid.
63577
63578             if (!osm.authenticated()) {
63579               osm.authenticate(function (err) {
63580                 if (!err) {
63581                   uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
63582                 }
63583               });
63584               return;
63585             }
63586
63587             if (!_isSaving) {
63588               _isSaving = true;
63589               dispatch$1.call('saveStarted', this);
63590             }
63591
63592             var history = context.history();
63593             _conflicts = [];
63594             _errors = []; // Store original changes, in case user wants to download them as an .osc file
63595
63596             _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
63597             // Any conflict resolutions will be done as `history.replace`
63598             // Remember to pop this later if needed
63599
63600             if (!tryAgain) {
63601               history.perform(actionNoop());
63602             } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
63603
63604
63605             if (!checkConflicts) {
63606               upload(changeset); // Do the full (slow) conflict check..
63607             } else {
63608               performFullConflictCheck(changeset);
63609             }
63610           };
63611
63612           function performFullConflictCheck(changeset) {
63613             var osm = context.connection();
63614             if (!osm) return;
63615             var history = context.history();
63616             var localGraph = context.graph();
63617             var remoteGraph = coreGraph(history.base(), true);
63618             var summary = history.difference().summary();
63619             var _toCheck = [];
63620
63621             for (var i = 0; i < summary.length; i++) {
63622               var item = summary[i];
63623
63624               if (item.changeType === 'modified') {
63625                 _toCheck.push(item.entity.id);
63626               }
63627             }
63628
63629             var _toLoad = withChildNodes(_toCheck, localGraph);
63630
63631             var _loaded = {};
63632             var _toLoadCount = 0;
63633             var _toLoadTotal = _toLoad.length;
63634
63635             if (_toCheck.length) {
63636               dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
63637
63638               _toLoad.forEach(function (id) {
63639                 _loaded[id] = false;
63640               });
63641
63642               osm.loadMultiple(_toLoad, loaded);
63643             } else {
63644               upload(changeset);
63645             }
63646
63647             return;
63648
63649             function withChildNodes(ids, graph) {
63650               var s = new Set(ids);
63651               ids.forEach(function (id) {
63652                 var entity = graph.entity(id);
63653                 if (entity.type !== 'way') return;
63654                 graph.childNodes(entity).forEach(function (child) {
63655                   if (child.version !== undefined) {
63656                     s.add(child.id);
63657                   }
63658                 });
63659               });
63660               return Array.from(s);
63661             } // Reload modified entities into an alternate graph and check for conflicts..
63662
63663
63664             function loaded(err, result) {
63665               if (_errors.length) return;
63666
63667               if (err) {
63668                 _errors.push({
63669                   msg: err.message || err.responseText,
63670                   details: [_t('save.status_code', {
63671                     code: err.status
63672                   })]
63673                 });
63674
63675                 didResultInErrors();
63676               } else {
63677                 var loadMore = [];
63678                 result.data.forEach(function (entity) {
63679                   remoteGraph.replace(entity);
63680                   _loaded[entity.id] = true;
63681                   _toLoad = _toLoad.filter(function (val) {
63682                     return val !== entity.id;
63683                   });
63684                   if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
63685                   // need to also load children that aren't already being checked..
63686
63687                   var i, id;
63688
63689                   if (entity.type === 'way') {
63690                     for (i = 0; i < entity.nodes.length; i++) {
63691                       id = entity.nodes[i];
63692
63693                       if (_loaded[id] === undefined) {
63694                         _loaded[id] = false;
63695                         loadMore.push(id);
63696                       }
63697                     }
63698                   } else if (entity.type === 'relation' && entity.isMultipolygon()) {
63699                     for (i = 0; i < entity.members.length; i++) {
63700                       id = entity.members[i].id;
63701
63702                       if (_loaded[id] === undefined) {
63703                         _loaded[id] = false;
63704                         loadMore.push(id);
63705                       }
63706                     }
63707                   }
63708                 });
63709                 _toLoadCount += result.data.length;
63710                 _toLoadTotal += loadMore.length;
63711                 dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
63712
63713                 if (loadMore.length) {
63714                   _toLoad.push.apply(_toLoad, loadMore);
63715
63716                   osm.loadMultiple(loadMore, loaded);
63717                 }
63718
63719                 if (!_toLoad.length) {
63720                   detectConflicts();
63721                   upload(changeset);
63722                 }
63723               }
63724             }
63725
63726             function detectConflicts() {
63727               function choice(id, text, _action) {
63728                 return {
63729                   id: id,
63730                   text: text,
63731                   action: function action() {
63732                     history.replace(_action);
63733                   }
63734                 };
63735               }
63736
63737               function formatUser(d) {
63738                 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
63739               }
63740
63741               function entityName(entity) {
63742                 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
63743               }
63744
63745               function sameVersions(local, remote) {
63746                 if (local.version !== remote.version) return false;
63747
63748                 if (local.type === 'way') {
63749                   var children = utilArrayUnion(local.nodes, remote.nodes);
63750
63751                   for (var i = 0; i < children.length; i++) {
63752                     var a = localGraph.hasEntity(children[i]);
63753                     var b = remoteGraph.hasEntity(children[i]);
63754                     if (a && b && a.version !== b.version) return false;
63755                   }
63756                 }
63757
63758                 return true;
63759               }
63760
63761               _toCheck.forEach(function (id) {
63762                 var local = localGraph.entity(id);
63763                 var remote = remoteGraph.entity(id);
63764                 if (sameVersions(local, remote)) return;
63765                 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
63766                 history.replace(merge);
63767                 var mergeConflicts = merge.conflicts();
63768                 if (!mergeConflicts.length) return; // merged safely
63769
63770                 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
63771                 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
63772                 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
63773                 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
63774
63775                 _conflicts.push({
63776                   id: id,
63777                   name: entityName(local),
63778                   details: mergeConflicts,
63779                   chosen: 1,
63780                   choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
63781                 });
63782               });
63783             }
63784           }
63785
63786           function upload(changeset) {
63787             var osm = context.connection();
63788
63789             if (!osm) {
63790               _errors.push({
63791                 msg: 'No OSM Service'
63792               });
63793             }
63794
63795             if (_conflicts.length) {
63796               didResultInConflicts(changeset);
63797             } else if (_errors.length) {
63798               didResultInErrors();
63799             } else {
63800               var history = context.history();
63801               var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
63802
63803               if (changes.modified.length || changes.created.length || changes.deleted.length) {
63804                 dispatch$1.call('willAttemptUpload', this);
63805                 osm.putChangeset(changeset, changes, uploadCallback);
63806               } else {
63807                 // changes were insignificant or reverted by user
63808                 didResultInNoChanges();
63809               }
63810             }
63811           }
63812
63813           function uploadCallback(err, changeset) {
63814             if (err) {
63815               if (err.status === 409) {
63816                 // 409 Conflict
63817                 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
63818               } else {
63819                 _errors.push({
63820                   msg: err.message || err.responseText,
63821                   details: [_t('save.status_code', {
63822                     code: err.status
63823                   })]
63824                 });
63825
63826                 didResultInErrors();
63827               }
63828             } else {
63829               didResultInSuccess(changeset);
63830             }
63831           }
63832
63833           function didResultInNoChanges() {
63834             dispatch$1.call('resultNoChanges', this);
63835             endSave();
63836             context.flush(); // reset iD
63837           }
63838
63839           function didResultInErrors() {
63840             context.history().pop();
63841             dispatch$1.call('resultErrors', this, _errors);
63842             endSave();
63843           }
63844
63845           function didResultInConflicts(changeset) {
63846             _conflicts.sort(function (a, b) {
63847               return b.id.localeCompare(a.id);
63848             });
63849
63850             dispatch$1.call('resultConflicts', this, changeset, _conflicts, _origChanges);
63851             endSave();
63852           }
63853
63854           function didResultInSuccess(changeset) {
63855             // delete the edit stack cached to local storage
63856             context.history().clearSaved();
63857             dispatch$1.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
63858
63859             window.setTimeout(function () {
63860               endSave();
63861               context.flush(); // reset iD
63862             }, 2500);
63863           }
63864
63865           function endSave() {
63866             _isSaving = false;
63867             dispatch$1.call('saveEnded', this);
63868           }
63869
63870           uploader.cancelConflictResolution = function () {
63871             context.history().pop();
63872           };
63873
63874           uploader.processResolvedConflicts = function (changeset) {
63875             var history = context.history();
63876
63877             for (var i = 0; i < _conflicts.length; i++) {
63878               if (_conflicts[i].chosen === 1) {
63879                 // user chose "use theirs"
63880                 var entity = context.hasEntity(_conflicts[i].id);
63881
63882                 if (entity && entity.type === 'way') {
63883                   var children = utilArrayUniq(entity.nodes);
63884
63885                   for (var j = 0; j < children.length; j++) {
63886                     history.replace(actionRevert(children[j]));
63887                   }
63888                 }
63889
63890                 history.replace(actionRevert(_conflicts[i].id));
63891               }
63892             }
63893
63894             uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
63895           };
63896
63897           uploader.reset = function () {};
63898
63899           return uploader;
63900         }
63901
63902         var abs$4 = Math.abs;
63903         var exp$2 = Math.exp;
63904         var E = Math.E;
63905
63906         var FORCED$g = fails(function () {
63907           return Math.sinh(-2e-17) != -2e-17;
63908         });
63909
63910         // `Math.sinh` method
63911         // https://tc39.es/ecma262/#sec-math.sinh
63912         // V8 near Chromium 38 has a problem with very small numbers
63913         _export({ target: 'Math', stat: true, forced: FORCED$g }, {
63914           sinh: function sinh(x) {
63915             return abs$4(x = +x) < 1 ? (mathExpm1(x) - mathExpm1(-x)) / 2 : (exp$2(x - 1) - exp$2(-x - 1)) * (E / 2);
63916           }
63917         });
63918
63919         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
63920
63921         window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function () {
63922           isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
63923         });
63924
63925         function localeDateString(s) {
63926           if (!s) return null;
63927           var options = {
63928             day: 'numeric',
63929             month: 'short',
63930             year: 'numeric'
63931           };
63932           var d = new Date(s);
63933           if (isNaN(d.getTime())) return null;
63934           return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
63935         }
63936
63937         function vintageRange(vintage) {
63938           var s;
63939
63940           if (vintage.start || vintage.end) {
63941             s = vintage.start || '?';
63942
63943             if (vintage.start !== vintage.end) {
63944               s += ' - ' + (vintage.end || '?');
63945             }
63946           }
63947
63948           return s;
63949         }
63950
63951         function rendererBackgroundSource(data) {
63952           var source = Object.assign({}, data); // shallow copy
63953
63954           var _offset = [0, 0];
63955           var _name = source.name;
63956           var _description = source.description;
63957
63958           var _best = !!source.best;
63959
63960           var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
63961
63962           source.tileSize = data.tileSize || 256;
63963           source.zoomExtent = data.zoomExtent || [0, 22];
63964           source.overzoom = data.overzoom !== false;
63965
63966           source.offset = function (val) {
63967             if (!arguments.length) return _offset;
63968             _offset = val;
63969             return source;
63970           };
63971
63972           source.nudge = function (val, zoomlevel) {
63973             _offset[0] += val[0] / Math.pow(2, zoomlevel);
63974             _offset[1] += val[1] / Math.pow(2, zoomlevel);
63975             return source;
63976           };
63977
63978           source.name = function () {
63979             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
63980             return _t('imagery.' + id_safe + '.name', {
63981               "default": _name
63982             });
63983           };
63984
63985           source.label = function () {
63986             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
63987             return _t.html('imagery.' + id_safe + '.name', {
63988               "default": _name
63989             });
63990           };
63991
63992           source.description = function () {
63993             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
63994             return _t.html('imagery.' + id_safe + '.description', {
63995               "default": _description
63996             });
63997           };
63998
63999           source.best = function () {
64000             return _best;
64001           };
64002
64003           source.area = function () {
64004             if (!data.polygon) return Number.MAX_VALUE; // worldwide
64005
64006             var area = d3_geoArea({
64007               type: 'MultiPolygon',
64008               coordinates: [data.polygon]
64009             });
64010             return isNaN(area) ? 0 : area;
64011           };
64012
64013           source.imageryUsed = function () {
64014             return _name || source.id;
64015           };
64016
64017           source.template = function (val) {
64018             if (!arguments.length) return _template;
64019
64020             if (source.id === 'custom') {
64021               _template = val;
64022             }
64023
64024             return source;
64025           };
64026
64027           source.url = function (coord) {
64028             var result = _template;
64029             if (result === '') return result; // source 'none'
64030             // Guess a type based on the tokens present in the template
64031             // (This is for 'custom' source, where we don't know)
64032
64033             if (!source.type) {
64034               if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
64035                 source.type = 'wms';
64036                 source.projection = 'EPSG:3857'; // guess
64037               } else if (/\{(x|y)\}/.test(_template)) {
64038                 source.type = 'tms';
64039               } else if (/\{u\}/.test(_template)) {
64040                 source.type = 'bing';
64041               }
64042             }
64043
64044             if (source.type === 'wms') {
64045               var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
64046                 //polyfill for IE11, PhantomJS
64047                 var sinh = Math.sinh || function (x) {
64048                   var y = Math.exp(x);
64049                   return (y - 1 / y) / 2;
64050                 };
64051
64052                 var zoomSize = Math.pow(2, z);
64053                 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
64054                 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
64055
64056                 switch (source.projection) {
64057                   case 'EPSG:4326':
64058                     return {
64059                       x: lon * 180 / Math.PI,
64060                       y: lat * 180 / Math.PI
64061                     };
64062
64063                   default:
64064                     // EPSG:3857 and synonyms
64065                     var mercCoords = mercatorRaw(lon, lat);
64066                     return {
64067                       x: 20037508.34 / Math.PI * mercCoords[0],
64068                       y: 20037508.34 / Math.PI * mercCoords[1]
64069                     };
64070                 }
64071               };
64072
64073               var tileSize = source.tileSize;
64074               var projection = source.projection;
64075               var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
64076               var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
64077               result = result.replace(/\{(\w+)\}/g, function (token, key) {
64078                 switch (key) {
64079                   case 'width':
64080                   case 'height':
64081                     return tileSize;
64082
64083                   case 'proj':
64084                     return projection;
64085
64086                   case 'wkid':
64087                     return projection.replace(/^EPSG:/, '');
64088
64089                   case 'bbox':
64090                     // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
64091                     if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
64092                     /VERSION=1.3|CRS={proj}/.test(source.template())) {
64093                       return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
64094                     } else {
64095                       return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
64096                     }
64097
64098                   case 'w':
64099                     return minXmaxY.x;
64100
64101                   case 's':
64102                     return maxXminY.y;
64103
64104                   case 'n':
64105                     return maxXminY.x;
64106
64107                   case 'e':
64108                     return minXmaxY.y;
64109
64110                   default:
64111                     return token;
64112                 }
64113               });
64114             } else if (source.type === 'tms') {
64115               result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
64116               .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
64117               .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
64118             } else if (source.type === 'bing') {
64119               result = result.replace('{u}', function () {
64120                 var u = '';
64121
64122                 for (var zoom = coord[2]; zoom > 0; zoom--) {
64123                   var b = 0;
64124                   var mask = 1 << zoom - 1;
64125                   if ((coord[0] & mask) !== 0) b++;
64126                   if ((coord[1] & mask) !== 0) b += 2;
64127                   u += b.toString();
64128                 }
64129
64130                 return u;
64131               });
64132             } // these apply to any type..
64133
64134
64135             result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
64136               var subdomains = r.split(',');
64137               return subdomains[(coord[0] + coord[1]) % subdomains.length];
64138             });
64139             return result;
64140           };
64141
64142           source.validZoom = function (z) {
64143             return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
64144           };
64145
64146           source.isLocatorOverlay = function () {
64147             return source.id === 'mapbox_locator_overlay';
64148           };
64149           /* hides a source from the list, but leaves it available for use */
64150
64151
64152           source.isHidden = function () {
64153             return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
64154           };
64155
64156           source.copyrightNotices = function () {};
64157
64158           source.getMetadata = function (center, tileCoord, callback) {
64159             var vintage = {
64160               start: localeDateString(source.startDate),
64161               end: localeDateString(source.endDate)
64162             };
64163             vintage.range = vintageRange(vintage);
64164             var metadata = {
64165               vintage: vintage
64166             };
64167             callback(null, metadata);
64168           };
64169
64170           return source;
64171         }
64172
64173         rendererBackgroundSource.Bing = function (data, dispatch) {
64174           // http://msdn.microsoft.com/en-us/library/ff701716.aspx
64175           // http://msdn.microsoft.com/en-us/library/ff701701.aspx
64176           data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
64177           var bing = rendererBackgroundSource(data); // var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
64178
64179           var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
64180
64181           var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' + key;
64182           var cache = {};
64183           var inflight = {};
64184           var providers = [];
64185           d3_json(url).then(function (json) {
64186             providers = json.resourceSets[0].resources[0].imageryProviders.map(function (provider) {
64187               return {
64188                 attribution: provider.attribution,
64189                 areas: provider.coverageAreas.map(function (area) {
64190                   return {
64191                     zoom: [area.zoomMin, area.zoomMax],
64192                     extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
64193                   };
64194                 })
64195               };
64196             });
64197             dispatch.call('change');
64198           })["catch"](function () {
64199             /* ignore */
64200           });
64201
64202           bing.copyrightNotices = function (zoom, extent) {
64203             zoom = Math.min(zoom, 21);
64204             return providers.filter(function (provider) {
64205               return provider.areas.some(function (area) {
64206                 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
64207               });
64208             }).map(function (provider) {
64209               return provider.attribution;
64210             }).join(', ');
64211           };
64212
64213           bing.getMetadata = function (center, tileCoord, callback) {
64214             var tileID = tileCoord.slice(0, 3).join('/');
64215             var zoom = Math.min(tileCoord[2], 21);
64216             var centerPoint = center[1] + ',' + center[0]; // lat,lng
64217
64218             var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
64219             if (inflight[tileID]) return;
64220
64221             if (!cache[tileID]) {
64222               cache[tileID] = {};
64223             }
64224
64225             if (cache[tileID] && cache[tileID].metadata) {
64226               return callback(null, cache[tileID].metadata);
64227             }
64228
64229             inflight[tileID] = true;
64230             d3_json(url).then(function (result) {
64231               delete inflight[tileID];
64232
64233               if (!result) {
64234                 throw new Error('Unknown Error');
64235               }
64236
64237               var vintage = {
64238                 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
64239                 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
64240               };
64241               vintage.range = vintageRange(vintage);
64242               var metadata = {
64243                 vintage: vintage
64244               };
64245               cache[tileID].metadata = metadata;
64246               if (callback) callback(null, metadata);
64247             })["catch"](function (err) {
64248               delete inflight[tileID];
64249               if (callback) callback(err.message);
64250             });
64251           };
64252
64253           bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
64254           return bing;
64255         };
64256
64257         rendererBackgroundSource.Esri = function (data) {
64258           // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
64259           if (data.template.match(/blankTile/) === null) {
64260             data.template = data.template + '?blankTile=false';
64261           }
64262
64263           var esri = rendererBackgroundSource(data);
64264           var cache = {};
64265           var inflight = {};
64266
64267           var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
64268           // https://developers.arcgis.com/documentation/tiled-elevation-service/
64269
64270
64271           esri.fetchTilemap = function (center) {
64272             // skip if we have already fetched a tilemap within 5km
64273             if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
64274             _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
64275
64276             var z = 20; // first generate a random url using the template
64277
64278             var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
64279
64280             var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
64281             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
64282
64283             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
64284
64285             d3_json(tilemapUrl).then(function (tilemap) {
64286               if (!tilemap) {
64287                 throw new Error('Unknown Error');
64288               }
64289
64290               var hasTiles = true;
64291
64292               for (var i = 0; i < tilemap.data.length; i++) {
64293                 // 0 means an individual tile in the grid doesn't exist
64294                 if (!tilemap.data[i]) {
64295                   hasTiles = false;
64296                   break;
64297                 }
64298               } // if any tiles are missing at level 20 we restrict maxZoom to 19
64299
64300
64301               esri.zoomExtent[1] = hasTiles ? 22 : 19;
64302             })["catch"](function () {
64303               /* ignore */
64304             });
64305           };
64306
64307           esri.getMetadata = function (center, tileCoord, callback) {
64308             var tileID = tileCoord.slice(0, 3).join('/');
64309             var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
64310             var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
64311
64312             var unknown = _t('info_panels.background.unknown');
64313             var metadataLayer;
64314             var vintage = {};
64315             var metadata = {};
64316             if (inflight[tileID]) return;
64317
64318             switch (true) {
64319               case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
64320                 metadataLayer = 4;
64321                 break;
64322
64323               case zoom >= 19:
64324                 metadataLayer = 3;
64325                 break;
64326
64327               case zoom >= 17:
64328                 metadataLayer = 2;
64329                 break;
64330
64331               case zoom >= 13:
64332                 metadataLayer = 0;
64333                 break;
64334
64335               default:
64336                 metadataLayer = 99;
64337             }
64338
64339             var url; // build up query using the layer appropriate to the current zoom
64340
64341             if (esri.id === 'EsriWorldImagery') {
64342               url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
64343             } else if (esri.id === 'EsriWorldImageryClarity') {
64344               url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
64345             }
64346
64347             url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
64348
64349             if (!cache[tileID]) {
64350               cache[tileID] = {};
64351             }
64352
64353             if (cache[tileID] && cache[tileID].metadata) {
64354               return callback(null, cache[tileID].metadata);
64355             } // accurate metadata is only available >= 13
64356
64357
64358             if (metadataLayer === 99) {
64359               vintage = {
64360                 start: null,
64361                 end: null,
64362                 range: null
64363               };
64364               metadata = {
64365                 vintage: null,
64366                 source: unknown,
64367                 description: unknown,
64368                 resolution: unknown,
64369                 accuracy: unknown
64370               };
64371               callback(null, metadata);
64372             } else {
64373               inflight[tileID] = true;
64374               d3_json(url).then(function (result) {
64375                 delete inflight[tileID];
64376
64377                 if (!result) {
64378                   throw new Error('Unknown Error');
64379                 } else if (result.features && result.features.length < 1) {
64380                   throw new Error('No Results');
64381                 } else if (result.error && result.error.message) {
64382                   throw new Error(result.error.message);
64383                 } // pass through the discrete capture date from metadata
64384
64385
64386                 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
64387                 vintage = {
64388                   start: captureDate,
64389                   end: captureDate,
64390                   range: captureDate
64391                 };
64392                 metadata = {
64393                   vintage: vintage,
64394                   source: clean(result.features[0].attributes.NICE_NAME),
64395                   description: clean(result.features[0].attributes.NICE_DESC),
64396                   resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
64397                   accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
64398                 }; // append units - meters
64399
64400                 if (isFinite(metadata.resolution)) {
64401                   metadata.resolution += ' m';
64402                 }
64403
64404                 if (isFinite(metadata.accuracy)) {
64405                   metadata.accuracy += ' m';
64406                 }
64407
64408                 cache[tileID].metadata = metadata;
64409                 if (callback) callback(null, metadata);
64410               })["catch"](function (err) {
64411                 delete inflight[tileID];
64412                 if (callback) callback(err.message);
64413               });
64414             }
64415
64416             function clean(val) {
64417               return String(val).trim() || unknown;
64418             }
64419           };
64420
64421           return esri;
64422         };
64423
64424         rendererBackgroundSource.None = function () {
64425           var source = rendererBackgroundSource({
64426             id: 'none',
64427             template: ''
64428           });
64429
64430           source.name = function () {
64431             return _t('background.none');
64432           };
64433
64434           source.label = function () {
64435             return _t.html('background.none');
64436           };
64437
64438           source.imageryUsed = function () {
64439             return null;
64440           };
64441
64442           source.area = function () {
64443             return -1; // sources in background pane are sorted by area
64444           };
64445
64446           return source;
64447         };
64448
64449         rendererBackgroundSource.Custom = function (template) {
64450           var source = rendererBackgroundSource({
64451             id: 'custom',
64452             template: template
64453           });
64454
64455           source.name = function () {
64456             return _t('background.custom');
64457           };
64458
64459           source.label = function () {
64460             return _t.html('background.custom');
64461           };
64462
64463           source.imageryUsed = function () {
64464             // sanitize personal connection tokens - #6801
64465             var cleaned = source.template(); // from query string parameters
64466
64467             if (cleaned.indexOf('?') !== -1) {
64468               var parts = cleaned.split('?', 2);
64469               var qs = utilStringQs(parts[1]);
64470               ['access_token', 'connectId', 'token'].forEach(function (param) {
64471                 if (qs[param]) {
64472                   qs[param] = '{apikey}';
64473                 }
64474               });
64475               cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
64476             } // from wms/wmts api path parameters
64477
64478
64479             cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
64480             return 'Custom (' + cleaned + ' )';
64481           };
64482
64483           source.area = function () {
64484             return -2; // sources in background pane are sorted by area
64485           };
64486
64487           return source;
64488         };
64489
64490         function rendererTileLayer(context) {
64491           var transformProp = utilPrefixCSSProperty('Transform');
64492           var tiler = utilTiler();
64493           var _tileSize = 256;
64494
64495           var _projection;
64496
64497           var _cache = {};
64498
64499           var _tileOrigin;
64500
64501           var _zoom;
64502
64503           var _source;
64504
64505           function tileSizeAtZoom(d, z) {
64506             var EPSILON = 0.002; // close seams
64507
64508             return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
64509           }
64510
64511           function atZoom(t, distance) {
64512             var power = Math.pow(2, distance);
64513             return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
64514           }
64515
64516           function lookUp(d) {
64517             for (var up = -1; up > -d[2]; up--) {
64518               var tile = atZoom(d, up);
64519
64520               if (_cache[_source.url(tile)] !== false) {
64521                 return tile;
64522               }
64523             }
64524           }
64525
64526           function uniqueBy(a, n) {
64527             var o = [];
64528             var seen = {};
64529
64530             for (var i = 0; i < a.length; i++) {
64531               if (seen[a[i][n]] === undefined) {
64532                 o.push(a[i]);
64533                 seen[a[i][n]] = true;
64534               }
64535             }
64536
64537             return o;
64538           }
64539
64540           function addSource(d) {
64541             d.push(_source.url(d));
64542             return d;
64543           } // Update tiles based on current state of `projection`.
64544
64545
64546           function background(selection) {
64547             _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
64548             var pixelOffset;
64549
64550             if (_source) {
64551               pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
64552             } else {
64553               pixelOffset = [0, 0];
64554             }
64555
64556             var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
64557             tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
64558             _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
64559             render(selection);
64560           } // Derive the tiles onscreen, remove those offscreen and position them.
64561           // Important that this part not depend on `_projection` because it's
64562           // rentered when tiles load/error (see #644).
64563
64564
64565           function render(selection) {
64566             if (!_source) return;
64567             var requests = [];
64568             var showDebug = context.getDebug('tile') && !_source.overlay;
64569
64570             if (_source.validZoom(_zoom)) {
64571               tiler.skipNullIsland(!!_source.overlay);
64572               tiler().forEach(function (d) {
64573                 addSource(d);
64574                 if (d[3] === '') return;
64575                 if (typeof d[3] !== 'string') return; // Workaround for #2295
64576
64577                 requests.push(d);
64578
64579                 if (_cache[d[3]] === false && lookUp(d)) {
64580                   requests.push(addSource(lookUp(d)));
64581                 }
64582               });
64583               requests = uniqueBy(requests, 3).filter(function (r) {
64584                 // don't re-request tiles which have failed in the past
64585                 return _cache[r[3]] !== false;
64586               });
64587             }
64588
64589             function load(d3_event, d) {
64590               _cache[d[3]] = true;
64591               select(this).on('error', null).on('load', null).classed('tile-loaded', true);
64592               render(selection);
64593             }
64594
64595             function error(d3_event, d) {
64596               _cache[d[3]] = false;
64597               select(this).on('error', null).on('load', null).remove();
64598               render(selection);
64599             }
64600
64601             function imageTransform(d) {
64602               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
64603
64604               var scale = tileSizeAtZoom(d, _zoom);
64605               return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
64606             }
64607
64608             function tileCenter(d) {
64609               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
64610
64611               return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
64612             }
64613
64614             function debugTransform(d) {
64615               var coord = tileCenter(d);
64616               return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
64617             } // Pick a representative tile near the center of the viewport
64618             // (This is useful for sampling the imagery vintage)
64619
64620
64621             var dims = tiler.size();
64622             var mapCenter = [dims[0] / 2, dims[1] / 2];
64623             var minDist = Math.max(dims[0], dims[1]);
64624             var nearCenter;
64625             requests.forEach(function (d) {
64626               var c = tileCenter(d);
64627               var dist = geoVecLength(c, mapCenter);
64628
64629               if (dist < minDist) {
64630                 minDist = dist;
64631                 nearCenter = d;
64632               }
64633             });
64634             var image = selection.selectAll('img').data(requests, function (d) {
64635               return d[3];
64636             });
64637             image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
64638               var tile = select(this);
64639               window.setTimeout(function () {
64640                 if (tile.classed('tile-removing')) {
64641                   tile.remove();
64642                 }
64643               }, 300);
64644             });
64645             image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
64646               return d[3];
64647             }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
64648               return d === nearCenter;
64649             });
64650             var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
64651               return d[3];
64652             });
64653             debug.exit().remove();
64654
64655             if (showDebug) {
64656               var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
64657               debugEnter.append('div').attr('class', 'tile-label-debug-coord');
64658               debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
64659               debug = debug.merge(debugEnter);
64660               debug.style(transformProp, debugTransform);
64661               debug.selectAll('.tile-label-debug-coord').html(function (d) {
64662                 return d[2] + ' / ' + d[0] + ' / ' + d[1];
64663               });
64664               debug.selectAll('.tile-label-debug-vintage').each(function (d) {
64665                 var span = select(this);
64666                 var center = context.projection.invert(tileCenter(d));
64667
64668                 _source.getMetadata(center, d, function (err, result) {
64669                   span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
64670                 });
64671               });
64672             }
64673           }
64674
64675           background.projection = function (val) {
64676             if (!arguments.length) return _projection;
64677             _projection = val;
64678             return background;
64679           };
64680
64681           background.dimensions = function (val) {
64682             if (!arguments.length) return tiler.size();
64683             tiler.size(val);
64684             return background;
64685           };
64686
64687           background.source = function (val) {
64688             if (!arguments.length) return _source;
64689             _source = val;
64690             _tileSize = _source.tileSize;
64691             _cache = {};
64692             tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
64693             return background;
64694           };
64695
64696           return background;
64697         }
64698
64699         var _imageryIndex = null;
64700         function rendererBackground(context) {
64701           var dispatch$1 = dispatch('change');
64702           var detected = utilDetect();
64703           var baseLayer = rendererTileLayer(context).projection(context.projection);
64704           var _isValid = true;
64705           var _overlayLayers = [];
64706           var _brightness = 1;
64707           var _contrast = 1;
64708           var _saturation = 1;
64709           var _sharpness = 1;
64710
64711           function ensureImageryIndex() {
64712             return _mainFileFetcher.get('imagery').then(function (sources) {
64713               if (_imageryIndex) return _imageryIndex;
64714               _imageryIndex = {
64715                 imagery: sources,
64716                 features: {}
64717               }; // use which-polygon to support efficient index and querying for imagery
64718
64719               var features = sources.map(function (source) {
64720                 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
64721                 // Add an extra array nest to each element in `source.polygon`
64722                 // so the rings are not treated as a bunch of holes:
64723                 // what we have: [ [[outer],[hole],[hole]] ]
64724                 // what we want: [ [[outer]],[[outer]],[[outer]] ]
64725
64726                 var rings = source.polygon.map(function (ring) {
64727                   return [ring];
64728                 });
64729                 var feature = {
64730                   type: 'Feature',
64731                   properties: {
64732                     id: source.id
64733                   },
64734                   geometry: {
64735                     type: 'MultiPolygon',
64736                     coordinates: rings
64737                   }
64738                 };
64739                 _imageryIndex.features[source.id] = feature;
64740                 return feature;
64741               }).filter(Boolean);
64742               _imageryIndex.query = whichPolygon_1({
64743                 type: 'FeatureCollection',
64744                 features: features
64745               }); // Instantiate `rendererBackgroundSource` objects for each source
64746
64747               _imageryIndex.backgrounds = sources.map(function (source) {
64748                 if (source.type === 'bing') {
64749                   return rendererBackgroundSource.Bing(source, dispatch$1);
64750                 } else if (/^EsriWorldImagery/.test(source.id)) {
64751                   return rendererBackgroundSource.Esri(source);
64752                 } else {
64753                   return rendererBackgroundSource(source);
64754                 }
64755               }); // Add 'None'
64756
64757               _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
64758
64759
64760               var template = corePreferences('background-custom-template') || '';
64761               var custom = rendererBackgroundSource.Custom(template);
64762
64763               _imageryIndex.backgrounds.unshift(custom);
64764
64765               return _imageryIndex;
64766             });
64767           }
64768
64769           function background(selection) {
64770             var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
64771             // check its tilemap to see how high the zoom can go
64772
64773             if (context.map().zoom() > 18) {
64774               if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
64775                 var center = context.map().center();
64776                 currSource.fetchTilemap(center);
64777               }
64778             } // Is the imagery valid here? - #4827
64779
64780
64781             var sources = background.sources(context.map().extent());
64782             var wasValid = _isValid;
64783             _isValid = !!sources.filter(function (d) {
64784               return d === currSource;
64785             }).length;
64786
64787             if (wasValid !== _isValid) {
64788               // change in valid status
64789               background.updateImagery();
64790             }
64791
64792             var baseFilter = '';
64793
64794             if (detected.cssfilters) {
64795               if (_brightness !== 1) {
64796                 baseFilter += " brightness(".concat(_brightness, ")");
64797               }
64798
64799               if (_contrast !== 1) {
64800                 baseFilter += " contrast(".concat(_contrast, ")");
64801               }
64802
64803               if (_saturation !== 1) {
64804                 baseFilter += " saturate(".concat(_saturation, ")");
64805               }
64806
64807               if (_sharpness < 1) {
64808                 // gaussian blur
64809                 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
64810                 baseFilter += " blur(".concat(blur, "px)");
64811               }
64812             }
64813
64814             var base = selection.selectAll('.layer-background').data([0]);
64815             base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
64816
64817             if (detected.cssfilters) {
64818               base.style('filter', baseFilter || null);
64819             } else {
64820               base.style('opacity', _brightness);
64821             }
64822
64823             var imagery = base.selectAll('.layer-imagery').data([0]);
64824             imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
64825             var maskFilter = '';
64826             var mixBlendMode = '';
64827
64828             if (detected.cssfilters && _sharpness > 1) {
64829               // apply unsharp mask
64830               mixBlendMode = 'overlay';
64831               maskFilter = 'saturate(0) blur(3px) invert(1)';
64832               var contrast = _sharpness - 1;
64833               maskFilter += " contrast(".concat(contrast, ")");
64834               var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
64835               maskFilter += " brightness(".concat(brightness, ")");
64836             }
64837
64838             var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
64839             mask.exit().remove();
64840             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);
64841             var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
64842               return d.source().name();
64843             });
64844             overlays.exit().remove();
64845             overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
64846               return select(nodes[i]).call(layer);
64847             });
64848           }
64849
64850           background.updateImagery = function () {
64851             var currSource = baseLayer.source();
64852             if (context.inIntro() || !currSource) return;
64853
64854             var o = _overlayLayers.filter(function (d) {
64855               return !d.source().isLocatorOverlay() && !d.source().isHidden();
64856             }).map(function (d) {
64857               return d.source().id;
64858             }).join(',');
64859
64860             var meters = geoOffsetToMeters(currSource.offset());
64861             var EPSILON = 0.01;
64862             var x = +meters[0].toFixed(2);
64863             var y = +meters[1].toFixed(2);
64864             var hash = utilStringQs(window.location.hash);
64865             var id = currSource.id;
64866
64867             if (id === 'custom') {
64868               id = "custom:".concat(currSource.template());
64869             }
64870
64871             if (id) {
64872               hash.background = id;
64873             } else {
64874               delete hash.background;
64875             }
64876
64877             if (o) {
64878               hash.overlays = o;
64879             } else {
64880               delete hash.overlays;
64881             }
64882
64883             if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
64884               hash.offset = "".concat(x, ",").concat(y);
64885             } else {
64886               delete hash.offset;
64887             }
64888
64889             if (!window.mocha) {
64890               window.location.replace('#' + utilQsString(hash, true));
64891             }
64892
64893             var imageryUsed = [];
64894             var photoOverlaysUsed = [];
64895             var currUsed = currSource.imageryUsed();
64896
64897             if (currUsed && _isValid) {
64898               imageryUsed.push(currUsed);
64899             }
64900
64901             _overlayLayers.filter(function (d) {
64902               return !d.source().isLocatorOverlay() && !d.source().isHidden();
64903             }).forEach(function (d) {
64904               return imageryUsed.push(d.source().imageryUsed());
64905             });
64906
64907             var dataLayer = context.layers().layer('data');
64908
64909             if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
64910               imageryUsed.push(dataLayer.getSrc());
64911             }
64912
64913             var photoOverlayLayers = {
64914               streetside: 'Bing Streetside',
64915               mapillary: 'Mapillary Images',
64916               'mapillary-map-features': 'Mapillary Map Features',
64917               'mapillary-signs': 'Mapillary Signs',
64918               openstreetcam: 'OpenStreetCam Images'
64919             };
64920
64921             for (var layerID in photoOverlayLayers) {
64922               var layer = context.layers().layer(layerID);
64923
64924               if (layer && layer.enabled()) {
64925                 photoOverlaysUsed.push(layerID);
64926                 imageryUsed.push(photoOverlayLayers[layerID]);
64927               }
64928             }
64929
64930             context.history().imageryUsed(imageryUsed);
64931             context.history().photoOverlaysUsed(photoOverlaysUsed);
64932           };
64933
64934           var _checkedBlocklists;
64935
64936           background.sources = function (extent, zoom, includeCurrent) {
64937             if (!_imageryIndex) return []; // called before init()?
64938
64939             var visible = {};
64940             (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
64941               return visible[d.id] = true;
64942             });
64943             var currSource = baseLayer.source();
64944             var osm = context.connection();
64945             var blocklists = osm && osm.imageryBlocklists();
64946
64947             if (blocklists && blocklists !== _checkedBlocklists) {
64948               _imageryIndex.backgrounds.forEach(function (source) {
64949                 source.isBlocked = blocklists.some(function (blocklist) {
64950                   return blocklist.test(source.template());
64951                 });
64952               });
64953
64954               _checkedBlocklists = blocklists;
64955             }
64956
64957             return _imageryIndex.backgrounds.filter(function (source) {
64958               if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
64959
64960               if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
64961
64962               if (!source.polygon) return true; // always include imagery with worldwide coverage
64963
64964               if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
64965
64966               return visible[source.id]; // include imagery visible in given extent
64967             });
64968           };
64969
64970           background.dimensions = function (val) {
64971             if (!val) return;
64972             baseLayer.dimensions(val);
64973
64974             _overlayLayers.forEach(function (layer) {
64975               return layer.dimensions(val);
64976             });
64977           };
64978
64979           background.baseLayerSource = function (d) {
64980             if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
64981
64982             var osm = context.connection();
64983             if (!osm) return background;
64984             var blocklists = osm.imageryBlocklists();
64985             var template = d.template();
64986             var fail = false;
64987             var tested = 0;
64988             var regex;
64989
64990             for (var i = 0; i < blocklists.length; i++) {
64991               regex = blocklists[i];
64992               fail = regex.test(template);
64993               tested++;
64994               if (fail) break;
64995             } // ensure at least one test was run.
64996
64997
64998             if (!tested) {
64999               regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
65000               fail = regex.test(template);
65001             }
65002
65003             baseLayer.source(!fail ? d : background.findSource('none'));
65004             dispatch$1.call('change');
65005             background.updateImagery();
65006             return background;
65007           };
65008
65009           background.findSource = function (id) {
65010             if (!id || !_imageryIndex) return null; // called before init()?
65011
65012             return _imageryIndex.backgrounds.find(function (d) {
65013               return d.id && d.id === id;
65014             });
65015           };
65016
65017           background.bing = function () {
65018             background.baseLayerSource(background.findSource('Bing'));
65019           };
65020
65021           background.showsLayer = function (d) {
65022             var currSource = baseLayer.source();
65023             if (!d || !currSource) return false;
65024             return d.id === currSource.id || _overlayLayers.some(function (layer) {
65025               return d.id === layer.source().id;
65026             });
65027           };
65028
65029           background.overlayLayerSources = function () {
65030             return _overlayLayers.map(function (layer) {
65031               return layer.source();
65032             });
65033           };
65034
65035           background.toggleOverlayLayer = function (d) {
65036             var layer;
65037
65038             for (var i = 0; i < _overlayLayers.length; i++) {
65039               layer = _overlayLayers[i];
65040
65041               if (layer.source() === d) {
65042                 _overlayLayers.splice(i, 1);
65043
65044                 dispatch$1.call('change');
65045                 background.updateImagery();
65046                 return;
65047               }
65048             }
65049
65050             layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
65051
65052             _overlayLayers.push(layer);
65053
65054             dispatch$1.call('change');
65055             background.updateImagery();
65056           };
65057
65058           background.nudge = function (d, zoom) {
65059             var currSource = baseLayer.source();
65060
65061             if (currSource) {
65062               currSource.nudge(d, zoom);
65063               dispatch$1.call('change');
65064               background.updateImagery();
65065             }
65066
65067             return background;
65068           };
65069
65070           background.offset = function (d) {
65071             var currSource = baseLayer.source();
65072
65073             if (!arguments.length) {
65074               return currSource && currSource.offset() || [0, 0];
65075             }
65076
65077             if (currSource) {
65078               currSource.offset(d);
65079               dispatch$1.call('change');
65080               background.updateImagery();
65081             }
65082
65083             return background;
65084           };
65085
65086           background.brightness = function (d) {
65087             if (!arguments.length) return _brightness;
65088             _brightness = d;
65089             if (context.mode()) dispatch$1.call('change');
65090             return background;
65091           };
65092
65093           background.contrast = function (d) {
65094             if (!arguments.length) return _contrast;
65095             _contrast = d;
65096             if (context.mode()) dispatch$1.call('change');
65097             return background;
65098           };
65099
65100           background.saturation = function (d) {
65101             if (!arguments.length) return _saturation;
65102             _saturation = d;
65103             if (context.mode()) dispatch$1.call('change');
65104             return background;
65105           };
65106
65107           background.sharpness = function (d) {
65108             if (!arguments.length) return _sharpness;
65109             _sharpness = d;
65110             if (context.mode()) dispatch$1.call('change');
65111             return background;
65112           };
65113
65114           var _loadPromise;
65115
65116           background.ensureLoaded = function () {
65117             if (_loadPromise) return _loadPromise;
65118
65119             function parseMapParams(qmap) {
65120               if (!qmap) return false;
65121               var params = qmap.split('/').map(Number);
65122               if (params.length < 3 || params.some(isNaN)) return false;
65123               return geoExtent([params[2], params[1]]); // lon,lat
65124             }
65125
65126             var hash = utilStringQs(window.location.hash);
65127             var requested = hash.background || hash.layer;
65128             var extent = parseMapParams(hash.map);
65129             return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
65130               var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
65131               var best;
65132
65133               if (!requested && extent) {
65134                 best = background.sources(extent).find(function (s) {
65135                   return s.best();
65136                 });
65137               } // Decide which background layer to display
65138
65139
65140               if (requested && requested.indexOf('custom:') === 0) {
65141                 var template = requested.replace(/^custom:/, '');
65142                 var custom = background.findSource('custom');
65143                 background.baseLayerSource(custom.template(template));
65144                 corePreferences('background-custom-template', template);
65145               } else {
65146                 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
65147               }
65148
65149               var locator = imageryIndex.backgrounds.find(function (d) {
65150                 return d.overlay && d["default"];
65151               });
65152
65153               if (locator) {
65154                 background.toggleOverlayLayer(locator);
65155               }
65156
65157               var overlays = (hash.overlays || '').split(',');
65158               overlays.forEach(function (overlay) {
65159                 overlay = background.findSource(overlay);
65160
65161                 if (overlay) {
65162                   background.toggleOverlayLayer(overlay);
65163                 }
65164               });
65165
65166               if (hash.gpx) {
65167                 var gpx = context.layers().layer('data');
65168
65169                 if (gpx) {
65170                   gpx.url(hash.gpx, '.gpx');
65171                 }
65172               }
65173
65174               if (hash.offset) {
65175                 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
65176                   return !isNaN(n) && n;
65177                 });
65178
65179                 if (offset.length === 2) {
65180                   background.offset(geoMetersToOffset(offset));
65181                 }
65182               }
65183             })["catch"](function () {
65184               /* ignore */
65185             });
65186           };
65187
65188           return utilRebind(background, dispatch$1, 'on');
65189         }
65190
65191         function rendererFeatures(context) {
65192           var dispatch$1 = dispatch('change', 'redraw');
65193           var features = utilRebind({}, dispatch$1, 'on');
65194
65195           var _deferred = new Set();
65196
65197           var traffic_roads = {
65198             'motorway': true,
65199             'motorway_link': true,
65200             'trunk': true,
65201             'trunk_link': true,
65202             'primary': true,
65203             'primary_link': true,
65204             'secondary': true,
65205             'secondary_link': true,
65206             'tertiary': true,
65207             'tertiary_link': true,
65208             'residential': true,
65209             'unclassified': true,
65210             'living_street': true
65211           };
65212           var service_roads = {
65213             'service': true,
65214             'road': true,
65215             'track': true
65216           };
65217           var paths = {
65218             'path': true,
65219             'footway': true,
65220             'cycleway': true,
65221             'bridleway': true,
65222             'steps': true,
65223             'pedestrian': true
65224           };
65225           var past_futures = {
65226             'proposed': true,
65227             'construction': true,
65228             'abandoned': true,
65229             'dismantled': true,
65230             'disused': true,
65231             'razed': true,
65232             'demolished': true,
65233             'obliterated': true
65234           };
65235           var _cullFactor = 1;
65236           var _cache = {};
65237           var _rules = {};
65238           var _stats = {};
65239           var _keys = [];
65240           var _hidden = [];
65241           var _forceVisible = {};
65242
65243           function update() {
65244             if (!window.mocha) {
65245               var hash = utilStringQs(window.location.hash);
65246               var disabled = features.disabled();
65247
65248               if (disabled.length) {
65249                 hash.disable_features = disabled.join(',');
65250               } else {
65251                 delete hash.disable_features;
65252               }
65253
65254               window.location.replace('#' + utilQsString(hash, true));
65255               corePreferences('disabled-features', disabled.join(','));
65256             }
65257
65258             _hidden = features.hidden();
65259             dispatch$1.call('change');
65260             dispatch$1.call('redraw');
65261           }
65262
65263           function defineRule(k, filter, max) {
65264             var isEnabled = true;
65265
65266             _keys.push(k);
65267
65268             _rules[k] = {
65269               filter: filter,
65270               enabled: isEnabled,
65271               // whether the user wants it enabled..
65272               count: 0,
65273               currentMax: max || Infinity,
65274               defaultMax: max || Infinity,
65275               enable: function enable() {
65276                 this.enabled = true;
65277                 this.currentMax = this.defaultMax;
65278               },
65279               disable: function disable() {
65280                 this.enabled = false;
65281                 this.currentMax = 0;
65282               },
65283               hidden: function hidden() {
65284                 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
65285               },
65286               autoHidden: function autoHidden() {
65287                 return this.hidden() && this.currentMax > 0;
65288               }
65289             };
65290           }
65291
65292           defineRule('points', function isPoint(tags, geometry) {
65293             return geometry === 'point';
65294           }, 200);
65295           defineRule('traffic_roads', function isTrafficRoad(tags) {
65296             return traffic_roads[tags.highway];
65297           });
65298           defineRule('service_roads', function isServiceRoad(tags) {
65299             return service_roads[tags.highway];
65300           });
65301           defineRule('paths', function isPath(tags) {
65302             return paths[tags.highway];
65303           });
65304           defineRule('buildings', function isBuilding(tags) {
65305             return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
65306           }, 250);
65307           defineRule('building_parts', function isBuildingPart(tags) {
65308             return tags['building:part'];
65309           });
65310           defineRule('indoor', function isIndoor(tags) {
65311             return tags.indoor;
65312           });
65313           defineRule('landuse', function isLanduse(tags, geometry) {
65314             return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
65315           });
65316           defineRule('boundaries', function isBoundary(tags) {
65317             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);
65318           });
65319           defineRule('water', function isWater(tags) {
65320             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';
65321           });
65322           defineRule('rail', function isRail(tags) {
65323             return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
65324           });
65325           defineRule('pistes', function isPiste(tags) {
65326             return tags['piste:type'];
65327           });
65328           defineRule('aerialways', function isPiste(tags) {
65329             return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
65330           });
65331           defineRule('power', function isPower(tags) {
65332             return !!tags.power;
65333           }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
65334
65335           defineRule('past_future', function isPastFuture(tags) {
65336             if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
65337               return false;
65338             }
65339
65340             var strings = Object.keys(tags);
65341
65342             for (var i = 0; i < strings.length; i++) {
65343               var s = strings[i];
65344
65345               if (past_futures[s] || past_futures[tags[s]]) {
65346                 return true;
65347               }
65348             }
65349
65350             return false;
65351           }); // Lines or areas that don't match another feature filter.
65352           // IMPORTANT: The 'others' feature must be the last one defined,
65353           //   so that code in getMatches can skip this test if `hasMatch = true`
65354
65355           defineRule('others', function isOther(tags, geometry) {
65356             return geometry === 'line' || geometry === 'area';
65357           });
65358
65359           features.features = function () {
65360             return _rules;
65361           };
65362
65363           features.keys = function () {
65364             return _keys;
65365           };
65366
65367           features.enabled = function (k) {
65368             if (!arguments.length) {
65369               return _keys.filter(function (k) {
65370                 return _rules[k].enabled;
65371               });
65372             }
65373
65374             return _rules[k] && _rules[k].enabled;
65375           };
65376
65377           features.disabled = function (k) {
65378             if (!arguments.length) {
65379               return _keys.filter(function (k) {
65380                 return !_rules[k].enabled;
65381               });
65382             }
65383
65384             return _rules[k] && !_rules[k].enabled;
65385           };
65386
65387           features.hidden = function (k) {
65388             if (!arguments.length) {
65389               return _keys.filter(function (k) {
65390                 return _rules[k].hidden();
65391               });
65392             }
65393
65394             return _rules[k] && _rules[k].hidden();
65395           };
65396
65397           features.autoHidden = function (k) {
65398             if (!arguments.length) {
65399               return _keys.filter(function (k) {
65400                 return _rules[k].autoHidden();
65401               });
65402             }
65403
65404             return _rules[k] && _rules[k].autoHidden();
65405           };
65406
65407           features.enable = function (k) {
65408             if (_rules[k] && !_rules[k].enabled) {
65409               _rules[k].enable();
65410
65411               update();
65412             }
65413           };
65414
65415           features.enableAll = function () {
65416             var didEnable = false;
65417
65418             for (var k in _rules) {
65419               if (!_rules[k].enabled) {
65420                 didEnable = true;
65421
65422                 _rules[k].enable();
65423               }
65424             }
65425
65426             if (didEnable) update();
65427           };
65428
65429           features.disable = function (k) {
65430             if (_rules[k] && _rules[k].enabled) {
65431               _rules[k].disable();
65432
65433               update();
65434             }
65435           };
65436
65437           features.disableAll = function () {
65438             var didDisable = false;
65439
65440             for (var k in _rules) {
65441               if (_rules[k].enabled) {
65442                 didDisable = true;
65443
65444                 _rules[k].disable();
65445               }
65446             }
65447
65448             if (didDisable) update();
65449           };
65450
65451           features.toggle = function (k) {
65452             if (_rules[k]) {
65453               (function (f) {
65454                 return f.enabled ? f.disable() : f.enable();
65455               })(_rules[k]);
65456
65457               update();
65458             }
65459           };
65460
65461           features.resetStats = function () {
65462             for (var i = 0; i < _keys.length; i++) {
65463               _rules[_keys[i]].count = 0;
65464             }
65465
65466             dispatch$1.call('change');
65467           };
65468
65469           features.gatherStats = function (d, resolver, dimensions) {
65470             var needsRedraw = false;
65471             var types = utilArrayGroupBy(d, 'type');
65472             var entities = [].concat(types.relation || [], types.way || [], types.node || []);
65473             var currHidden, geometry, matches, i, j;
65474
65475             for (i = 0; i < _keys.length; i++) {
65476               _rules[_keys[i]].count = 0;
65477             } // adjust the threshold for point/building culling based on viewport size..
65478             // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
65479
65480
65481             _cullFactor = dimensions[0] * dimensions[1] / 1000000;
65482
65483             for (i = 0; i < entities.length; i++) {
65484               geometry = entities[i].geometry(resolver);
65485               matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
65486
65487               for (j = 0; j < matches.length; j++) {
65488                 _rules[matches[j]].count++;
65489               }
65490             }
65491
65492             currHidden = features.hidden();
65493
65494             if (currHidden !== _hidden) {
65495               _hidden = currHidden;
65496               needsRedraw = true;
65497               dispatch$1.call('change');
65498             }
65499
65500             return needsRedraw;
65501           };
65502
65503           features.stats = function () {
65504             for (var i = 0; i < _keys.length; i++) {
65505               _stats[_keys[i]] = _rules[_keys[i]].count;
65506             }
65507
65508             return _stats;
65509           };
65510
65511           features.clear = function (d) {
65512             for (var i = 0; i < d.length; i++) {
65513               features.clearEntity(d[i]);
65514             }
65515           };
65516
65517           features.clearEntity = function (entity) {
65518             delete _cache[osmEntity.key(entity)];
65519           };
65520
65521           features.reset = function () {
65522             Array.from(_deferred).forEach(function (handle) {
65523               window.cancelIdleCallback(handle);
65524
65525               _deferred["delete"](handle);
65526             });
65527             _cache = {};
65528           }; // only certain relations are worth checking
65529
65530
65531           function relationShouldBeChecked(relation) {
65532             // multipolygon features have `area` geometry and aren't checked here
65533             return relation.tags.type === 'boundary';
65534           }
65535
65536           features.getMatches = function (entity, resolver, geometry) {
65537             if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
65538             var ent = osmEntity.key(entity);
65539
65540             if (!_cache[ent]) {
65541               _cache[ent] = {};
65542             }
65543
65544             if (!_cache[ent].matches) {
65545               var matches = {};
65546               var hasMatch = false;
65547
65548               for (var i = 0; i < _keys.length; i++) {
65549                 if (_keys[i] === 'others') {
65550                   if (hasMatch) continue; // If an entity...
65551                   //   1. is a way that hasn't matched other 'interesting' feature rules,
65552
65553                   if (entity.type === 'way') {
65554                     var parents = features.getParents(entity, resolver, geometry); //   2a. belongs only to a single multipolygon relation
65555
65556                     if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
65557                     parents.length > 0 && parents.every(function (parent) {
65558                       return parent.tags.type === 'boundary';
65559                     })) {
65560                       // ...then match whatever feature rules the parent relation has matched.
65561                       // see #2548, #2887
65562                       //
65563                       // IMPORTANT:
65564                       // For this to work, getMatches must be called on relations before ways.
65565                       //
65566                       var pkey = osmEntity.key(parents[0]);
65567
65568                       if (_cache[pkey] && _cache[pkey].matches) {
65569                         matches = Object.assign({}, _cache[pkey].matches); // shallow copy
65570
65571                         continue;
65572                       }
65573                     }
65574                   }
65575                 }
65576
65577                 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
65578                   matches[_keys[i]] = hasMatch = true;
65579                 }
65580               }
65581
65582               _cache[ent].matches = matches;
65583             }
65584
65585             return _cache[ent].matches;
65586           };
65587
65588           features.getParents = function (entity, resolver, geometry) {
65589             if (geometry === 'point') return [];
65590             var ent = osmEntity.key(entity);
65591
65592             if (!_cache[ent]) {
65593               _cache[ent] = {};
65594             }
65595
65596             if (!_cache[ent].parents) {
65597               var parents = [];
65598
65599               if (geometry === 'vertex') {
65600                 parents = resolver.parentWays(entity);
65601               } else {
65602                 // 'line', 'area', 'relation'
65603                 parents = resolver.parentRelations(entity);
65604               }
65605
65606               _cache[ent].parents = parents;
65607             }
65608
65609             return _cache[ent].parents;
65610           };
65611
65612           features.isHiddenPreset = function (preset, geometry) {
65613             if (!_hidden.length) return false;
65614             if (!preset.tags) return false;
65615             var test = preset.setTags({}, geometry);
65616
65617             for (var key in _rules) {
65618               if (_rules[key].filter(test, geometry)) {
65619                 if (_hidden.indexOf(key) !== -1) {
65620                   return key;
65621                 }
65622
65623                 return false;
65624               }
65625             }
65626
65627             return false;
65628           };
65629
65630           features.isHiddenFeature = function (entity, resolver, geometry) {
65631             if (!_hidden.length) return false;
65632             if (!entity.version) return false;
65633             if (_forceVisible[entity.id]) return false;
65634             var matches = Object.keys(features.getMatches(entity, resolver, geometry));
65635             return matches.length && matches.every(function (k) {
65636               return features.hidden(k);
65637             });
65638           };
65639
65640           features.isHiddenChild = function (entity, resolver, geometry) {
65641             if (!_hidden.length) return false;
65642             if (!entity.version || geometry === 'point') return false;
65643             if (_forceVisible[entity.id]) return false;
65644             var parents = features.getParents(entity, resolver, geometry);
65645             if (!parents.length) return false;
65646
65647             for (var i = 0; i < parents.length; i++) {
65648               if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
65649                 return false;
65650               }
65651             }
65652
65653             return true;
65654           };
65655
65656           features.hasHiddenConnections = function (entity, resolver) {
65657             if (!_hidden.length) return false;
65658             var childNodes, connections;
65659
65660             if (entity.type === 'midpoint') {
65661               childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
65662               connections = [];
65663             } else {
65664               childNodes = entity.nodes ? resolver.childNodes(entity) : [];
65665               connections = features.getParents(entity, resolver, entity.geometry(resolver));
65666             } // gather ways connected to child nodes..
65667
65668
65669             connections = childNodes.reduce(function (result, e) {
65670               return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
65671             }, connections);
65672             return connections.some(function (e) {
65673               return features.isHidden(e, resolver, e.geometry(resolver));
65674             });
65675           };
65676
65677           features.isHidden = function (entity, resolver, geometry) {
65678             if (!_hidden.length) return false;
65679             if (!entity.version) return false;
65680             var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
65681             return fn(entity, resolver, geometry);
65682           };
65683
65684           features.filter = function (d, resolver) {
65685             if (!_hidden.length) return d;
65686             var result = [];
65687
65688             for (var i = 0; i < d.length; i++) {
65689               var entity = d[i];
65690
65691               if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
65692                 result.push(entity);
65693               }
65694             }
65695
65696             return result;
65697           };
65698
65699           features.forceVisible = function (entityIDs) {
65700             if (!arguments.length) return Object.keys(_forceVisible);
65701             _forceVisible = {};
65702
65703             for (var i = 0; i < entityIDs.length; i++) {
65704               _forceVisible[entityIDs[i]] = true;
65705               var entity = context.hasEntity(entityIDs[i]);
65706
65707               if (entity && entity.type === 'relation') {
65708                 // also show relation members (one level deep)
65709                 for (var j in entity.members) {
65710                   _forceVisible[entity.members[j].id] = true;
65711                 }
65712               }
65713             }
65714
65715             return features;
65716           };
65717
65718           features.init = function () {
65719             var storage = corePreferences('disabled-features');
65720
65721             if (storage) {
65722               var storageDisabled = storage.replace(/;/g, ',').split(',');
65723               storageDisabled.forEach(features.disable);
65724             }
65725
65726             var hash = utilStringQs(window.location.hash);
65727
65728             if (hash.disable_features) {
65729               var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
65730               hashDisabled.forEach(features.disable);
65731             }
65732           }; // warm up the feature matching cache upon merging fetched data
65733
65734
65735           context.history().on('merge.features', function (newEntities) {
65736             if (!newEntities) return;
65737             var handle = window.requestIdleCallback(function () {
65738               var graph = context.graph();
65739               var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
65740
65741               var entities = [].concat(types.relation || [], types.way || [], types.node || []);
65742
65743               for (var i = 0; i < entities.length; i++) {
65744                 var geometry = entities[i].geometry(graph);
65745                 features.getMatches(entities[i], graph, geometry);
65746               }
65747             });
65748
65749             _deferred.add(handle);
65750           });
65751           return features;
65752         }
65753
65754         //
65755         // - the activeID - nope
65756         // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
65757         // - 2 away from the activeID - nope (would create a self intersecting segment)
65758         // - all others on a linear way - yes
65759         // - all others on a closed way - nope (would create a self intersecting polygon)
65760         //
65761         // returns
65762         // 0 = active vertex - no touch/connect
65763         // 1 = passive vertex - yes touch/connect
65764         // 2 = adjacent vertex - yes but pay attention segmenting a line here
65765         //
65766
65767         function svgPassiveVertex(node, graph, activeID) {
65768           if (!activeID) return 1;
65769           if (activeID === node.id) return 0;
65770           var parents = graph.parentWays(node);
65771           var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
65772
65773           for (i = 0; i < parents.length; i++) {
65774             nodes = parents[i].nodes;
65775             isClosed = parents[i].isClosed();
65776
65777             for (j = 0; j < nodes.length; j++) {
65778               // find this vertex, look nearby
65779               if (nodes[j] === node.id) {
65780                 ix1 = j - 2;
65781                 ix2 = j - 1;
65782                 ix3 = j + 1;
65783                 ix4 = j + 2;
65784
65785                 if (isClosed) {
65786                   // wraparound if needed
65787                   max = nodes.length - 1;
65788                   if (ix1 < 0) ix1 = max + ix1;
65789                   if (ix2 < 0) ix2 = max + ix2;
65790                   if (ix3 > max) ix3 = ix3 - max;
65791                   if (ix4 > max) ix4 = ix4 - max;
65792                 }
65793
65794                 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
65795                 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
65796                   else if (nodes[ix3] === activeID) return 2; // ok - adjacent
65797                     else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
65798                       else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
65799               }
65800             }
65801           }
65802
65803           return 1; // ok
65804         }
65805         function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
65806           return function (entity) {
65807             var i = 0;
65808             var offset = dt;
65809             var segments = [];
65810             var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
65811             var coordinates = graph.childNodes(entity).map(function (n) {
65812               return n.loc;
65813             });
65814             var a, b;
65815
65816             if (shouldReverse(entity)) {
65817               coordinates.reverse();
65818             }
65819
65820             d3_geoStream({
65821               type: 'LineString',
65822               coordinates: coordinates
65823             }, projection.stream(clip({
65824               lineStart: function lineStart() {},
65825               lineEnd: function lineEnd() {
65826                 a = null;
65827               },
65828               point: function point(x, y) {
65829                 b = [x, y];
65830
65831                 if (a) {
65832                   var span = geoVecLength(a, b) - offset;
65833
65834                   if (span >= 0) {
65835                     var heading = geoVecAngle(a, b);
65836                     var dx = dt * Math.cos(heading);
65837                     var dy = dt * Math.sin(heading);
65838                     var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
65839
65840                     var coord = [a, p];
65841
65842                     for (span -= dt; span >= 0; span -= dt) {
65843                       p = geoVecAdd(p, [dx, dy]);
65844                       coord.push(p);
65845                     }
65846
65847                     coord.push(b); // generate svg paths
65848
65849                     var segment = '';
65850                     var j;
65851
65852                     for (j = 0; j < coord.length; j++) {
65853                       segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
65854                     }
65855
65856                     segments.push({
65857                       id: entity.id,
65858                       index: i++,
65859                       d: segment
65860                     });
65861
65862                     if (bothDirections(entity)) {
65863                       segment = '';
65864
65865                       for (j = coord.length - 1; j >= 0; j--) {
65866                         segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
65867                       }
65868
65869                       segments.push({
65870                         id: entity.id,
65871                         index: i++,
65872                         d: segment
65873                       });
65874                     }
65875                   }
65876
65877                   offset = -span;
65878                 }
65879
65880                 a = b;
65881               }
65882             })));
65883             return segments;
65884           };
65885         }
65886         function svgPath(projection, graph, isArea) {
65887           // Explanation of magic numbers:
65888           // "padding" here allows space for strokes to extend beyond the viewport,
65889           // so that the stroke isn't drawn along the edge of the viewport when
65890           // the shape is clipped.
65891           //
65892           // When drawing lines, pad viewport by 5px.
65893           // When drawing areas, pad viewport by 65px in each direction to allow
65894           // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
65895           var cache = {};
65896           var padding = isArea ? 65 : 5;
65897           var viewport = projection.clipExtent();
65898           var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
65899           var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
65900           var project = projection.stream;
65901           var path = d3_geoPath().projection({
65902             stream: function stream(output) {
65903               return project(clip(output));
65904             }
65905           });
65906
65907           var svgpath = function svgpath(entity) {
65908             if (entity.id in cache) {
65909               return cache[entity.id];
65910             } else {
65911               return cache[entity.id] = path(entity.asGeoJSON(graph));
65912             }
65913           };
65914
65915           svgpath.geojson = function (d) {
65916             if (d.__featurehash__ !== undefined) {
65917               if (d.__featurehash__ in cache) {
65918                 return cache[d.__featurehash__];
65919               } else {
65920                 return cache[d.__featurehash__] = path(d);
65921               }
65922             } else {
65923               return path(d);
65924             }
65925           };
65926
65927           return svgpath;
65928         }
65929         function svgPointTransform(projection) {
65930           var svgpoint = function svgpoint(entity) {
65931             // http://jsperf.com/short-array-join
65932             var pt = projection(entity.loc);
65933             return 'translate(' + pt[0] + ',' + pt[1] + ')';
65934           };
65935
65936           svgpoint.geojson = function (d) {
65937             return svgpoint(d.properties.entity);
65938           };
65939
65940           return svgpoint;
65941         }
65942         function svgRelationMemberTags(graph) {
65943           return function (entity) {
65944             var tags = entity.tags;
65945             var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
65946             graph.parentRelations(entity).forEach(function (relation) {
65947               var type = relation.tags.type;
65948
65949               if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
65950                 tags = Object.assign({}, relation.tags, tags);
65951               }
65952             });
65953             return tags;
65954           };
65955         }
65956         function svgSegmentWay(way, graph, activeID) {
65957           // When there is no activeID, we can memoize this expensive computation
65958           if (activeID === undefined) {
65959             return graph["transient"](way, 'waySegments', getWaySegments);
65960           } else {
65961             return getWaySegments();
65962           }
65963
65964           function getWaySegments() {
65965             var isActiveWay = way.nodes.indexOf(activeID) !== -1;
65966             var features = {
65967               passive: [],
65968               active: []
65969             };
65970             var start = {};
65971             var end = {};
65972             var node, type;
65973
65974             for (var i = 0; i < way.nodes.length; i++) {
65975               node = graph.entity(way.nodes[i]);
65976               type = svgPassiveVertex(node, graph, activeID);
65977               end = {
65978                 node: node,
65979                 type: type
65980               };
65981
65982               if (start.type !== undefined) {
65983                 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
65984                   // one adjacent vertex
65985                   pushActive(start, end, i);
65986                 } else if (start.type === 0 && end.type === 0) {
65987                   // both active vertices
65988                   pushActive(start, end, i);
65989                 } else {
65990                   pushPassive(start, end, i);
65991                 }
65992               }
65993
65994               start = end;
65995             }
65996
65997             return features;
65998
65999             function pushActive(start, end, index) {
66000               features.active.push({
66001                 type: 'Feature',
66002                 id: way.id + '-' + index + '-nope',
66003                 properties: {
66004                   nope: true,
66005                   target: true,
66006                   entity: way,
66007                   nodes: [start.node, end.node],
66008                   index: index
66009                 },
66010                 geometry: {
66011                   type: 'LineString',
66012                   coordinates: [start.node.loc, end.node.loc]
66013                 }
66014               });
66015             }
66016
66017             function pushPassive(start, end, index) {
66018               features.passive.push({
66019                 type: 'Feature',
66020                 id: way.id + '-' + index,
66021                 properties: {
66022                   target: true,
66023                   entity: way,
66024                   nodes: [start.node, end.node],
66025                   index: index
66026                 },
66027                 geometry: {
66028                   type: 'LineString',
66029                   coordinates: [start.node.loc, end.node.loc]
66030                 }
66031               });
66032             }
66033           }
66034         }
66035
66036         function svgTagClasses() {
66037           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'];
66038           var statuses = [// nonexistent, might be built
66039           'proposed', 'planned', // under maintentance or between groundbreaking and opening
66040           'construction', // existent but not functional
66041           'disused', // dilapidated to nonexistent
66042           'abandoned', // nonexistent, still may appear in imagery
66043           'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
66044           'intermittent'];
66045           var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
66046
66047           var _tags = function _tags(entity) {
66048             return entity.tags;
66049           };
66050
66051           var tagClasses = function tagClasses(selection) {
66052             selection.each(function tagClassesEach(entity) {
66053               var value = this.className;
66054
66055               if (value.baseVal !== undefined) {
66056                 value = value.baseVal;
66057               }
66058
66059               var t = _tags(entity);
66060
66061               var computed = tagClasses.getClassesString(t, value);
66062
66063               if (computed !== value) {
66064                 select(this).attr('class', computed);
66065               }
66066             });
66067           };
66068
66069           tagClasses.getClassesString = function (t, value) {
66070             var primary, status;
66071             var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
66072
66073             var overrideGeometry;
66074
66075             if (/\bstroke\b/.test(value)) {
66076               if (!!t.barrier && t.barrier !== 'no') {
66077                 overrideGeometry = 'line';
66078               }
66079             } // preserve base classes (nothing with `tag-`)
66080
66081
66082             var classes = value.trim().split(/\s+/).filter(function (klass) {
66083               return klass.length && !/^tag-/.test(klass);
66084             }).map(function (klass) {
66085               // special overrides for some perimeter strokes
66086               return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
66087             }); // pick at most one primary classification tag..
66088
66089             for (i = 0; i < primaries.length; i++) {
66090               k = primaries[i];
66091               v = t[k];
66092               if (!v || v === 'no') continue;
66093
66094               if (k === 'piste:type') {
66095                 // avoid a ':' in the class name
66096                 k = 'piste';
66097               } else if (k === 'building:part') {
66098                 // avoid a ':' in the class name
66099                 k = 'building_part';
66100               }
66101
66102               primary = k;
66103
66104               if (statuses.indexOf(v) !== -1) {
66105                 // e.g. `railway=abandoned`
66106                 status = v;
66107                 classes.push('tag-' + k);
66108               } else {
66109                 classes.push('tag-' + k);
66110                 classes.push('tag-' + k + '-' + v);
66111               }
66112
66113               break;
66114             }
66115
66116             if (!primary) {
66117               for (i = 0; i < statuses.length; i++) {
66118                 for (j = 0; j < primaries.length; j++) {
66119                   k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
66120
66121                   v = t[k];
66122                   if (!v || v === 'no') continue;
66123                   status = statuses[i];
66124                   break;
66125                 }
66126               }
66127             } // add at most one status tag, only if relates to primary tag..
66128
66129
66130             if (!status) {
66131               for (i = 0; i < statuses.length; i++) {
66132                 k = statuses[i];
66133                 v = t[k];
66134                 if (!v || v === 'no') continue;
66135
66136                 if (v === 'yes') {
66137                   // e.g. `railway=rail + abandoned=yes`
66138                   status = k;
66139                 } else if (primary && primary === v) {
66140                   // e.g. `railway=rail + abandoned=railway`
66141                   status = k;
66142                 } else if (!primary && primaries.indexOf(v) !== -1) {
66143                   // e.g. `abandoned=railway`
66144                   status = k;
66145                   primary = v;
66146                   classes.push('tag-' + v);
66147                 } // else ignore e.g.  `highway=path + abandoned=railway`
66148
66149
66150                 if (status) break;
66151               }
66152             }
66153
66154             if (status) {
66155               classes.push('tag-status');
66156               classes.push('tag-status-' + status);
66157             } // add any secondary tags
66158
66159
66160             for (i = 0; i < secondaries.length; i++) {
66161               k = secondaries[i];
66162               v = t[k];
66163               if (!v || v === 'no' || k === primary) continue;
66164               classes.push('tag-' + k);
66165               classes.push('tag-' + k + '-' + v);
66166             } // For highways, look for surface tagging..
66167
66168
66169             if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
66170               var surface = t.highway === 'track' ? 'unpaved' : 'paved';
66171
66172               for (k in t) {
66173                 v = t[k];
66174
66175                 if (k in osmPavedTags) {
66176                   surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
66177                 }
66178
66179                 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
66180                   surface = 'semipaved';
66181                 }
66182               }
66183
66184               classes.push('tag-' + surface);
66185             } // If this is a wikidata-tagged item, add a class for that..
66186
66187
66188             if (t.wikidata || t['brand:wikidata']) {
66189               classes.push('tag-wikidata');
66190             }
66191
66192             return classes.join(' ').trim();
66193           };
66194
66195           tagClasses.tags = function (val) {
66196             if (!arguments.length) return _tags;
66197             _tags = val;
66198             return tagClasses;
66199           };
66200
66201           return tagClasses;
66202         }
66203
66204         // Patterns only work in Firefox when set directly on element.
66205         // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
66206         var patterns = {
66207           // tag - pattern name
66208           // -or-
66209           // tag - value - pattern name
66210           // -or-
66211           // tag - value - rules (optional tag-values, pattern name)
66212           // (matches earlier rules first, so fallback should be last entry)
66213           amenity: {
66214             grave_yard: 'cemetery',
66215             fountain: 'water_standing'
66216           },
66217           landuse: {
66218             cemetery: [{
66219               religion: 'christian',
66220               pattern: 'cemetery_christian'
66221             }, {
66222               religion: 'buddhist',
66223               pattern: 'cemetery_buddhist'
66224             }, {
66225               religion: 'muslim',
66226               pattern: 'cemetery_muslim'
66227             }, {
66228               religion: 'jewish',
66229               pattern: 'cemetery_jewish'
66230             }, {
66231               pattern: 'cemetery'
66232             }],
66233             construction: 'construction',
66234             farmland: 'farmland',
66235             farmyard: 'farmyard',
66236             forest: [{
66237               leaf_type: 'broadleaved',
66238               pattern: 'forest_broadleaved'
66239             }, {
66240               leaf_type: 'needleleaved',
66241               pattern: 'forest_needleleaved'
66242             }, {
66243               leaf_type: 'leafless',
66244               pattern: 'forest_leafless'
66245             }, {
66246               pattern: 'forest'
66247             } // same as 'leaf_type:mixed'
66248             ],
66249             grave_yard: 'cemetery',
66250             grass: [{
66251               golf: 'green',
66252               pattern: 'golf_green'
66253             }, {
66254               pattern: 'grass'
66255             }],
66256             landfill: 'landfill',
66257             meadow: 'meadow',
66258             military: 'construction',
66259             orchard: 'orchard',
66260             quarry: 'quarry',
66261             vineyard: 'vineyard'
66262           },
66263           natural: {
66264             beach: 'beach',
66265             grassland: 'grass',
66266             sand: 'beach',
66267             scrub: 'scrub',
66268             water: [{
66269               water: 'pond',
66270               pattern: 'pond'
66271             }, {
66272               water: 'reservoir',
66273               pattern: 'water_standing'
66274             }, {
66275               pattern: 'waves'
66276             }],
66277             wetland: [{
66278               wetland: 'marsh',
66279               pattern: 'wetland_marsh'
66280             }, {
66281               wetland: 'swamp',
66282               pattern: 'wetland_swamp'
66283             }, {
66284               wetland: 'bog',
66285               pattern: 'wetland_bog'
66286             }, {
66287               wetland: 'reedbed',
66288               pattern: 'wetland_reedbed'
66289             }, {
66290               pattern: 'wetland'
66291             }],
66292             wood: [{
66293               leaf_type: 'broadleaved',
66294               pattern: 'forest_broadleaved'
66295             }, {
66296               leaf_type: 'needleleaved',
66297               pattern: 'forest_needleleaved'
66298             }, {
66299               leaf_type: 'leafless',
66300               pattern: 'forest_leafless'
66301             }, {
66302               pattern: 'forest'
66303             } // same as 'leaf_type:mixed'
66304             ]
66305           },
66306           traffic_calming: {
66307             island: [{
66308               surface: 'grass',
66309               pattern: 'grass'
66310             }],
66311             chicane: [{
66312               surface: 'grass',
66313               pattern: 'grass'
66314             }],
66315             choker: [{
66316               surface: 'grass',
66317               pattern: 'grass'
66318             }]
66319           }
66320         };
66321         function svgTagPattern(tags) {
66322           // Skip pattern filling if this is a building (buildings don't get patterns applied)
66323           if (tags.building && tags.building !== 'no') {
66324             return null;
66325           }
66326
66327           for (var tag in patterns) {
66328             var entityValue = tags[tag];
66329             if (!entityValue) continue;
66330
66331             if (typeof patterns[tag] === 'string') {
66332               // extra short syntax (just tag) - pattern name
66333               return 'pattern-' + patterns[tag];
66334             } else {
66335               var values = patterns[tag];
66336
66337               for (var value in values) {
66338                 if (entityValue !== value) continue;
66339                 var rules = values[value];
66340
66341                 if (typeof rules === 'string') {
66342                   // short syntax - pattern name
66343                   return 'pattern-' + rules;
66344                 } // long syntax - rule array
66345
66346
66347                 for (var ruleKey in rules) {
66348                   var rule = rules[ruleKey];
66349                   var pass = true;
66350
66351                   for (var criterion in rule) {
66352                     if (criterion !== 'pattern') {
66353                       // reserved for pattern name
66354                       // The only rule is a required tag-value pair
66355                       var v = tags[criterion];
66356
66357                       if (!v || v !== rule[criterion]) {
66358                         pass = false;
66359                         break;
66360                       }
66361                     }
66362                   }
66363
66364                   if (pass) {
66365                     return 'pattern-' + rule.pattern;
66366                   }
66367                 }
66368               }
66369             }
66370           }
66371
66372           return null;
66373         }
66374
66375         function svgAreas(projection, context) {
66376           function getPatternStyle(tags) {
66377             var imageID = svgTagPattern(tags);
66378
66379             if (imageID) {
66380               return 'url("#ideditor-' + imageID + '")';
66381             }
66382
66383             return '';
66384           }
66385
66386           function drawTargets(selection, graph, entities, filter) {
66387             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
66388             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
66389             var getPath = svgPath(projection).geojson;
66390             var activeID = context.activeID();
66391             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
66392
66393             var data = {
66394               targets: [],
66395               nopes: []
66396             };
66397             entities.forEach(function (way) {
66398               var features = svgSegmentWay(way, graph, activeID);
66399               data.targets.push.apply(data.targets, features.passive);
66400               data.nopes.push.apply(data.nopes, features.active);
66401             }); // Targets allow hover and vertex snapping
66402
66403             var targetData = data.targets.filter(getPath);
66404             var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
66405               return filter(d.properties.entity);
66406             }).data(targetData, function key(d) {
66407               return d.id;
66408             }); // exit
66409
66410             targets.exit().remove();
66411
66412             var segmentWasEdited = function segmentWasEdited(d) {
66413               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
66414
66415               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
66416                 return false;
66417               }
66418
66419               return d.properties.nodes.some(function (n) {
66420                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
66421               });
66422             }; // enter/update
66423
66424
66425             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
66426               return 'way area target target-allowed ' + targetClass + d.id;
66427             }).classed('segment-edited', segmentWasEdited); // NOPE
66428
66429             var nopeData = data.nopes.filter(getPath);
66430             var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
66431               return filter(d.properties.entity);
66432             }).data(nopeData, function key(d) {
66433               return d.id;
66434             }); // exit
66435
66436             nopes.exit().remove(); // enter/update
66437
66438             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
66439               return 'way area target target-nope ' + nopeClass + d.id;
66440             }).classed('segment-edited', segmentWasEdited);
66441           }
66442
66443           function drawAreas(selection, graph, entities, filter) {
66444             var path = svgPath(projection, graph, true);
66445             var areas = {};
66446             var multipolygon;
66447             var base = context.history().base();
66448
66449             for (var i = 0; i < entities.length; i++) {
66450               var entity = entities[i];
66451               if (entity.geometry(graph) !== 'area') continue;
66452               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
66453
66454               if (multipolygon) {
66455                 areas[multipolygon.id] = {
66456                   entity: multipolygon.mergeTags(entity.tags),
66457                   area: Math.abs(entity.area(graph))
66458                 };
66459               } else if (!areas[entity.id]) {
66460                 areas[entity.id] = {
66461                   entity: entity,
66462                   area: Math.abs(entity.area(graph))
66463                 };
66464               }
66465             }
66466
66467             var fills = Object.values(areas).filter(function hasPath(a) {
66468               return path(a.entity);
66469             });
66470             fills.sort(function areaSort(a, b) {
66471               return b.area - a.area;
66472             });
66473             fills = fills.map(function (a) {
66474               return a.entity;
66475             });
66476             var strokes = fills.filter(function (area) {
66477               return area.type === 'way';
66478             });
66479             var data = {
66480               clip: fills,
66481               shadow: strokes,
66482               stroke: strokes,
66483               fill: fills
66484             };
66485             var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
66486             clipPaths.exit().remove();
66487             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
66488               return 'ideditor-' + entity.id + '-clippath';
66489             });
66490             clipPathsEnter.append('path');
66491             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
66492             var drawLayer = selection.selectAll('.layer-osm.areas');
66493             var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
66494
66495             var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
66496             areagroup = areagroup.enter().append('g').attr('class', function (d) {
66497               return 'areagroup area-' + d;
66498             }).merge(areagroup);
66499             var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
66500               return data[layer];
66501             }, osmEntity.key);
66502             paths.exit().remove();
66503             var fillpaths = selection.selectAll('.area-fill path.area').nodes();
66504             var bisect = d3_bisector(function (node) {
66505               return -node.__data__.area(graph);
66506             }).left;
66507
66508             function sortedByArea(entity) {
66509               if (this._parent.__data__ === 'fill') {
66510                 return fillpaths[bisect(fillpaths, -entity.area(graph))];
66511               }
66512             }
66513
66514             paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
66515               var layer = this.parentNode.__data__;
66516               this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
66517
66518               if (layer === 'fill') {
66519                 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
66520                 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
66521               }
66522             }).classed('added', function (d) {
66523               return !base.entities[d.id];
66524             }).classed('geometry-edited', function (d) {
66525               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
66526             }).classed('retagged', function (d) {
66527               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
66528             }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
66529
66530             touchLayer.call(drawTargets, graph, data.stroke, filter);
66531           }
66532
66533           return drawAreas;
66534         }
66535
66536         //[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]
66537         //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
66538         //[5]           Name       ::=          NameStartChar (NameChar)*
66539         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
66540
66541         var nameChar = new RegExp("[\\-\\.0-9" + nameStartChar.source.slice(1, -1) + "\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
66542         var tagNamePattern = new RegExp('^' + nameStartChar.source + nameChar.source + '*(?:\:' + nameStartChar.source + nameChar.source + '*)?$'); //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
66543         //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(',')
66544         //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
66545         //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
66546
66547         var S_TAG = 0; //tag name offerring
66548
66549         var S_ATTR = 1; //attr name offerring 
66550
66551         var S_ATTR_SPACE = 2; //attr name end and space offer
66552
66553         var S_EQ = 3; //=space?
66554
66555         var S_ATTR_NOQUOT_VALUE = 4; //attr value(no quot value only)
66556
66557         var S_ATTR_END = 5; //attr value end and no space(quot end)
66558
66559         var S_TAG_SPACE = 6; //(attr value end || tag end ) && (space offer)
66560
66561         var S_TAG_CLOSE = 7; //closed el<el />
66562
66563         function XMLReader() {}
66564
66565         XMLReader.prototype = {
66566           parse: function parse(source, defaultNSMap, entityMap) {
66567             var domBuilder = this.domBuilder;
66568             domBuilder.startDocument();
66569
66570             _copy(defaultNSMap, defaultNSMap = {});
66571
66572             _parse(source, defaultNSMap, entityMap, domBuilder, this.errorHandler);
66573
66574             domBuilder.endDocument();
66575           }
66576         };
66577
66578         function _parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
66579           function fixedFromCharCode(code) {
66580             // String.prototype.fromCharCode does not supports
66581             // > 2 bytes unicode chars directly
66582             if (code > 0xffff) {
66583               code -= 0x10000;
66584               var surrogate1 = 0xd800 + (code >> 10),
66585                   surrogate2 = 0xdc00 + (code & 0x3ff);
66586               return String.fromCharCode(surrogate1, surrogate2);
66587             } else {
66588               return String.fromCharCode(code);
66589             }
66590           }
66591
66592           function entityReplacer(a) {
66593             var k = a.slice(1, -1);
66594
66595             if (k in entityMap) {
66596               return entityMap[k];
66597             } else if (k.charAt(0) === '#') {
66598               return fixedFromCharCode(parseInt(k.substr(1).replace('x', '0x')));
66599             } else {
66600               errorHandler.error('entity not found:' + a);
66601               return a;
66602             }
66603           }
66604
66605           function appendText(end) {
66606             //has some bugs
66607             if (end > start) {
66608               var xt = source.substring(start, end).replace(/&#?\w+;/g, entityReplacer);
66609               locator && position(start);
66610               domBuilder.characters(xt, 0, end - start);
66611               start = end;
66612             }
66613           }
66614
66615           function position(p, m) {
66616             while (p >= lineEnd && (m = linePattern.exec(source))) {
66617               lineStart = m.index;
66618               lineEnd = lineStart + m[0].length;
66619               locator.lineNumber++; //console.log('line++:',locator,startPos,endPos)
66620             }
66621
66622             locator.columnNumber = p - lineStart + 1;
66623           }
66624
66625           var lineStart = 0;
66626           var lineEnd = 0;
66627           var linePattern = /.*(?:\r\n?|\n)|.*$/g;
66628           var locator = domBuilder.locator;
66629           var parseStack = [{
66630             currentNSMap: defaultNSMapCopy
66631           }];
66632           var closeMap = {};
66633           var start = 0;
66634
66635           while (true) {
66636             try {
66637               var tagStart = source.indexOf('<', start);
66638
66639               if (tagStart < 0) {
66640                 if (!source.substr(start).match(/^\s*$/)) {
66641                   var doc = domBuilder.doc;
66642                   var text = doc.createTextNode(source.substr(start));
66643                   doc.appendChild(text);
66644                   domBuilder.currentElement = text;
66645                 }
66646
66647                 return;
66648               }
66649
66650               if (tagStart > start) {
66651                 appendText(tagStart);
66652               }
66653
66654               switch (source.charAt(tagStart + 1)) {
66655                 case '/':
66656                   var end = source.indexOf('>', tagStart + 3);
66657                   var tagName = source.substring(tagStart + 2, end);
66658                   var config = parseStack.pop();
66659
66660                   if (end < 0) {
66661                     tagName = source.substring(tagStart + 2).replace(/[\s<].*/, ''); //console.error('#@@@@@@'+tagName)
66662
66663                     errorHandler.error("end tag name: " + tagName + ' is not complete:' + config.tagName);
66664                     end = tagStart + 1 + tagName.length;
66665                   } else if (tagName.match(/\s</)) {
66666                     tagName = tagName.replace(/[\s<].*/, '');
66667                     errorHandler.error("end tag name: " + tagName + ' maybe not complete');
66668                     end = tagStart + 1 + tagName.length;
66669                   } //console.error(parseStack.length,parseStack)
66670                   //console.error(config);
66671
66672
66673                   var localNSMap = config.localNSMap;
66674                   var endMatch = config.tagName == tagName;
66675                   var endIgnoreCaseMach = endMatch || config.tagName && config.tagName.toLowerCase() == tagName.toLowerCase();
66676
66677                   if (endIgnoreCaseMach) {
66678                     domBuilder.endElement(config.uri, config.localName, tagName);
66679
66680                     if (localNSMap) {
66681                       for (var prefix in localNSMap) {
66682                         domBuilder.endPrefixMapping(prefix);
66683                       }
66684                     }
66685
66686                     if (!endMatch) {
66687                       errorHandler.fatalError("end tag name: " + tagName + ' is not match the current start tagName:' + config.tagName);
66688                     }
66689                   } else {
66690                     parseStack.push(config);
66691                   }
66692
66693                   end++;
66694                   break;
66695                 // end elment
66696
66697                 case '?':
66698                   // <?...?>
66699                   locator && position(tagStart);
66700                   end = parseInstruction(source, tagStart, domBuilder);
66701                   break;
66702
66703                 case '!':
66704                   // <!doctype,<![CDATA,<!--
66705                   locator && position(tagStart);
66706                   end = parseDCC(source, tagStart, domBuilder, errorHandler);
66707                   break;
66708
66709                 default:
66710                   locator && position(tagStart);
66711                   var el = new ElementAttributes();
66712                   var currentNSMap = parseStack[parseStack.length - 1].currentNSMap; //elStartEnd
66713
66714                   var end = parseElementStartPart(source, tagStart, el, currentNSMap, entityReplacer, errorHandler);
66715                   var len = el.length;
66716
66717                   if (!el.closed && fixSelfClosed(source, end, el.tagName, closeMap)) {
66718                     el.closed = true;
66719
66720                     if (!entityMap.nbsp) {
66721                       errorHandler.warning('unclosed xml attribute');
66722                     }
66723                   }
66724
66725                   if (locator && len) {
66726                     var locator2 = copyLocator(locator, {}); //try{//attribute position fixed
66727
66728                     for (var i = 0; i < len; i++) {
66729                       var a = el[i];
66730                       position(a.offset);
66731                       a.locator = copyLocator(locator, {});
66732                     } //}catch(e){console.error('@@@@@'+e)}
66733
66734
66735                     domBuilder.locator = locator2;
66736
66737                     if (appendElement(el, domBuilder, currentNSMap)) {
66738                       parseStack.push(el);
66739                     }
66740
66741                     domBuilder.locator = locator;
66742                   } else {
66743                     if (appendElement(el, domBuilder, currentNSMap)) {
66744                       parseStack.push(el);
66745                     }
66746                   }
66747
66748                   if (el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed) {
66749                     end = parseHtmlSpecialContent(source, end, el.tagName, entityReplacer, domBuilder);
66750                   } else {
66751                     end++;
66752                   }
66753
66754               }
66755             } catch (e) {
66756               errorHandler.error('element parse error: ' + e); //errorHandler.error('element parse error: '+e);
66757
66758               end = -1; //throw e;
66759             }
66760
66761             if (end > start) {
66762               start = end;
66763             } else {
66764               //TODO: 这里有可能sax回退,有位置错误风险
66765               appendText(Math.max(tagStart, start) + 1);
66766             }
66767           }
66768         }
66769
66770         function copyLocator(f, t) {
66771           t.lineNumber = f.lineNumber;
66772           t.columnNumber = f.columnNumber;
66773           return t;
66774         }
66775         /**
66776          * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
66777          * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
66778          */
66779
66780
66781         function parseElementStartPart(source, start, el, currentNSMap, entityReplacer, errorHandler) {
66782           var attrName;
66783           var value;
66784           var p = ++start;
66785           var s = S_TAG; //status
66786
66787           while (true) {
66788             var c = source.charAt(p);
66789
66790             switch (c) {
66791               case '=':
66792                 if (s === S_ATTR) {
66793                   //attrName
66794                   attrName = source.slice(start, p);
66795                   s = S_EQ;
66796                 } else if (s === S_ATTR_SPACE) {
66797                   s = S_EQ;
66798                 } else {
66799                   //fatalError: equal must after attrName or space after attrName
66800                   throw new Error('attribute equal must after attrName');
66801                 }
66802
66803                 break;
66804
66805               case '\'':
66806               case '"':
66807                 if (s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
66808                 ) {
66809                     //equal
66810                     if (s === S_ATTR) {
66811                       errorHandler.warning('attribute value must after "="');
66812                       attrName = source.slice(start, p);
66813                     }
66814
66815                     start = p + 1;
66816                     p = source.indexOf(c, start);
66817
66818                     if (p > 0) {
66819                       value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
66820                       el.add(attrName, value, start - 1);
66821                       s = S_ATTR_END;
66822                     } else {
66823                       //fatalError: no end quot match
66824                       throw new Error('attribute value no end \'' + c + '\' match');
66825                     }
66826                   } else if (s == S_ATTR_NOQUOT_VALUE) {
66827                   value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer); //console.log(attrName,value,start,p)
66828
66829                   el.add(attrName, value, start); //console.dir(el)
66830
66831                   errorHandler.warning('attribute "' + attrName + '" missed start quot(' + c + ')!!');
66832                   start = p + 1;
66833                   s = S_ATTR_END;
66834                 } else {
66835                   //fatalError: no equal before
66836                   throw new Error('attribute value must after "="');
66837                 }
66838
66839                 break;
66840
66841               case '/':
66842                 switch (s) {
66843                   case S_TAG:
66844                     el.setTagName(source.slice(start, p));
66845
66846                   case S_ATTR_END:
66847                   case S_TAG_SPACE:
66848                   case S_TAG_CLOSE:
66849                     s = S_TAG_CLOSE;
66850                     el.closed = true;
66851
66852                   case S_ATTR_NOQUOT_VALUE:
66853                   case S_ATTR:
66854                   case S_ATTR_SPACE:
66855                     break;
66856                   //case S_EQ:
66857
66858                   default:
66859                     throw new Error("attribute invalid close char('/')");
66860                 }
66861
66862                 break;
66863
66864               case '':
66865                 //end document
66866                 //throw new Error('unexpected end of input')
66867                 errorHandler.error('unexpected end of input');
66868
66869                 if (s == S_TAG) {
66870                   el.setTagName(source.slice(start, p));
66871                 }
66872
66873                 return p;
66874
66875               case '>':
66876                 switch (s) {
66877                   case S_TAG:
66878                     el.setTagName(source.slice(start, p));
66879
66880                   case S_ATTR_END:
66881                   case S_TAG_SPACE:
66882                   case S_TAG_CLOSE:
66883                     break;
66884                   //normal
66885
66886                   case S_ATTR_NOQUOT_VALUE: //Compatible state
66887
66888                   case S_ATTR:
66889                     value = source.slice(start, p);
66890
66891                     if (value.slice(-1) === '/') {
66892                       el.closed = true;
66893                       value = value.slice(0, -1);
66894                     }
66895
66896                   case S_ATTR_SPACE:
66897                     if (s === S_ATTR_SPACE) {
66898                       value = attrName;
66899                     }
66900
66901                     if (s == S_ATTR_NOQUOT_VALUE) {
66902                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
66903                       el.add(attrName, value.replace(/&#?\w+;/g, entityReplacer), start);
66904                     } else {
66905                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)) {
66906                         errorHandler.warning('attribute "' + value + '" missed value!! "' + value + '" instead!!');
66907                       }
66908
66909                       el.add(value, value, start);
66910                     }
66911
66912                     break;
66913
66914                   case S_EQ:
66915                     throw new Error('attribute value missed!!');
66916                 } //                    console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
66917
66918
66919                 return p;
66920
66921               /*xml space '\x20' | #x9 | #xD | #xA; */
66922
66923               case "\x80":
66924                 c = ' ';
66925
66926               default:
66927                 if (c <= ' ') {
66928                   //space
66929                   switch (s) {
66930                     case S_TAG:
66931                       el.setTagName(source.slice(start, p)); //tagName
66932
66933                       s = S_TAG_SPACE;
66934                       break;
66935
66936                     case S_ATTR:
66937                       attrName = source.slice(start, p);
66938                       s = S_ATTR_SPACE;
66939                       break;
66940
66941                     case S_ATTR_NOQUOT_VALUE:
66942                       var value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
66943                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
66944                       el.add(attrName, value, start);
66945
66946                     case S_ATTR_END:
66947                       s = S_TAG_SPACE;
66948                       break;
66949                     //case S_TAG_SPACE:
66950                     //case S_EQ:
66951                     //case S_ATTR_SPACE:
66952                     //  void();break;
66953                     //case S_TAG_CLOSE:
66954                     //ignore warning
66955                   }
66956                 } else {
66957                   //not space
66958                   //S_TAG,      S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
66959                   //S_ATTR_SPACE,       S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
66960                   switch (s) {
66961                     //case S_TAG:void();break;
66962                     //case S_ATTR:void();break;
66963                     //case S_ATTR_NOQUOT_VALUE:void();break;
66964                     case S_ATTR_SPACE:
66965                       var tagName = el.tagName;
66966
66967                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
66968                         errorHandler.warning('attribute "' + attrName + '" missed value!! "' + attrName + '" instead2!!');
66969                       }
66970
66971                       el.add(attrName, attrName, start);
66972                       start = p;
66973                       s = S_ATTR;
66974                       break;
66975
66976                     case S_ATTR_END:
66977                       errorHandler.warning('attribute space is required"' + attrName + '"!!');
66978
66979                     case S_TAG_SPACE:
66980                       s = S_ATTR;
66981                       start = p;
66982                       break;
66983
66984                     case S_EQ:
66985                       s = S_ATTR_NOQUOT_VALUE;
66986                       start = p;
66987                       break;
66988
66989                     case S_TAG_CLOSE:
66990                       throw new Error("elements closed character '/' and '>' must be connected to");
66991                   }
66992                 }
66993
66994             } //end outer switch
66995             //console.log('p++',p)
66996
66997
66998             p++;
66999           }
67000         }
67001         /**
67002          * @return true if has new namespace define
67003          */
67004
67005
67006         function appendElement(el, domBuilder, currentNSMap) {
67007           var tagName = el.tagName;
67008           var localNSMap = null; //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
67009
67010           var i = el.length;
67011
67012           while (i--) {
67013             var a = el[i];
67014             var qName = a.qName;
67015             var value = a.value;
67016             var nsp = qName.indexOf(':');
67017
67018             if (nsp > 0) {
67019               var prefix = a.prefix = qName.slice(0, nsp);
67020               var localName = qName.slice(nsp + 1);
67021               var nsPrefix = prefix === 'xmlns' && localName;
67022             } else {
67023               localName = qName;
67024               prefix = null;
67025               nsPrefix = qName === 'xmlns' && '';
67026             } //can not set prefix,because prefix !== ''
67027
67028
67029             a.localName = localName; //prefix == null for no ns prefix attribute 
67030
67031             if (nsPrefix !== false) {
67032               //hack!!
67033               if (localNSMap == null) {
67034                 localNSMap = {}; //console.log(currentNSMap,0)
67035
67036                 _copy(currentNSMap, currentNSMap = {}); //console.log(currentNSMap,1)
67037
67038               }
67039
67040               currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
67041               a.uri = 'http://www.w3.org/2000/xmlns/';
67042               domBuilder.startPrefixMapping(nsPrefix, value);
67043             }
67044           }
67045
67046           var i = el.length;
67047
67048           while (i--) {
67049             a = el[i];
67050             var prefix = a.prefix;
67051
67052             if (prefix) {
67053               //no prefix attribute has no namespace
67054               if (prefix === 'xml') {
67055                 a.uri = 'http://www.w3.org/XML/1998/namespace';
67056               }
67057
67058               if (prefix !== 'xmlns') {
67059                 a.uri = currentNSMap[prefix || '']; //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
67060               }
67061             }
67062           }
67063
67064           var nsp = tagName.indexOf(':');
67065
67066           if (nsp > 0) {
67067             prefix = el.prefix = tagName.slice(0, nsp);
67068             localName = el.localName = tagName.slice(nsp + 1);
67069           } else {
67070             prefix = null; //important!!
67071
67072             localName = el.localName = tagName;
67073           } //no prefix element has default namespace
67074
67075
67076           var ns = el.uri = currentNSMap[prefix || ''];
67077           domBuilder.startElement(ns, localName, tagName, el); //endPrefixMapping and startPrefixMapping have not any help for dom builder
67078           //localNSMap = null
67079
67080           if (el.closed) {
67081             domBuilder.endElement(ns, localName, tagName);
67082
67083             if (localNSMap) {
67084               for (prefix in localNSMap) {
67085                 domBuilder.endPrefixMapping(prefix);
67086               }
67087             }
67088           } else {
67089             el.currentNSMap = currentNSMap;
67090             el.localNSMap = localNSMap; //parseStack.push(el);
67091
67092             return true;
67093           }
67094         }
67095
67096         function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
67097           if (/^(?:script|textarea)$/i.test(tagName)) {
67098             var elEndStart = source.indexOf('</' + tagName + '>', elStartEnd);
67099             var text = source.substring(elStartEnd + 1, elEndStart);
67100
67101             if (/[&<]/.test(text)) {
67102               if (/^script$/i.test(tagName)) {
67103                 //if(!/\]\]>/.test(text)){
67104                 //lexHandler.startCDATA();
67105                 domBuilder.characters(text, 0, text.length); //lexHandler.endCDATA();
67106
67107                 return elEndStart; //}
67108               } //}else{//text area
67109
67110
67111               text = text.replace(/&#?\w+;/g, entityReplacer);
67112               domBuilder.characters(text, 0, text.length);
67113               return elEndStart; //}
67114             }
67115           }
67116
67117           return elStartEnd + 1;
67118         }
67119
67120         function fixSelfClosed(source, elStartEnd, tagName, closeMap) {
67121           //if(tagName in closeMap){
67122           var pos = closeMap[tagName];
67123
67124           if (pos == null) {
67125             //console.log(tagName)
67126             pos = source.lastIndexOf('</' + tagName + '>');
67127
67128             if (pos < elStartEnd) {
67129               //忘记闭合
67130               pos = source.lastIndexOf('</' + tagName);
67131             }
67132
67133             closeMap[tagName] = pos;
67134           }
67135
67136           return pos < elStartEnd; //} 
67137         }
67138
67139         function _copy(source, target) {
67140           for (var n in source) {
67141             target[n] = source[n];
67142           }
67143         }
67144
67145         function parseDCC(source, start, domBuilder, errorHandler) {
67146           //sure start with '<!'
67147           var next = source.charAt(start + 2);
67148
67149           switch (next) {
67150             case '-':
67151               if (source.charAt(start + 3) === '-') {
67152                 var end = source.indexOf('-->', start + 4); //append comment source.substring(4,end)//<!--
67153
67154                 if (end > start) {
67155                   domBuilder.comment(source, start + 4, end - start - 4);
67156                   return end + 3;
67157                 } else {
67158                   errorHandler.error("Unclosed comment");
67159                   return -1;
67160                 }
67161               } else {
67162                 //error
67163                 return -1;
67164               }
67165
67166             default:
67167               if (source.substr(start + 3, 6) == 'CDATA[') {
67168                 var end = source.indexOf(']]>', start + 9);
67169                 domBuilder.startCDATA();
67170                 domBuilder.characters(source, start + 9, end - start - 9);
67171                 domBuilder.endCDATA();
67172                 return end + 3;
67173               } //<!DOCTYPE
67174               //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
67175
67176
67177               var matchs = split$1(source, start);
67178               var len = matchs.length;
67179
67180               if (len > 1 && /!doctype/i.test(matchs[0][0])) {
67181                 var name = matchs[1][0];
67182                 var pubid = len > 3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
67183                 var sysid = len > 4 && matchs[4][0];
67184                 var lastMatch = matchs[len - 1];
67185                 domBuilder.startDTD(name, pubid && pubid.replace(/^(['"])(.*?)\1$/, '$2'), sysid && sysid.replace(/^(['"])(.*?)\1$/, '$2'));
67186                 domBuilder.endDTD();
67187                 return lastMatch.index + lastMatch[0].length;
67188               }
67189
67190           }
67191
67192           return -1;
67193         }
67194
67195         function parseInstruction(source, start, domBuilder) {
67196           var end = source.indexOf('?>', start);
67197
67198           if (end) {
67199             var match = source.substring(start, end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
67200
67201             if (match) {
67202               var len = match[0].length;
67203               domBuilder.processingInstruction(match[1], match[2]);
67204               return end + 2;
67205             } else {
67206               //error
67207               return -1;
67208             }
67209           }
67210
67211           return -1;
67212         }
67213         /**
67214          * @param source
67215          */
67216
67217
67218         function ElementAttributes(source) {}
67219
67220         ElementAttributes.prototype = {
67221           setTagName: function setTagName(tagName) {
67222             if (!tagNamePattern.test(tagName)) {
67223               throw new Error('invalid tagName:' + tagName);
67224             }
67225
67226             this.tagName = tagName;
67227           },
67228           add: function add(qName, value, offset) {
67229             if (!tagNamePattern.test(qName)) {
67230               throw new Error('invalid attribute:' + qName);
67231             }
67232
67233             this[this.length++] = {
67234               qName: qName,
67235               value: value,
67236               offset: offset
67237             };
67238           },
67239           length: 0,
67240           getLocalName: function getLocalName(i) {
67241             return this[i].localName;
67242           },
67243           getLocator: function getLocator(i) {
67244             return this[i].locator;
67245           },
67246           getQName: function getQName(i) {
67247             return this[i].qName;
67248           },
67249           getURI: function getURI(i) {
67250             return this[i].uri;
67251           },
67252           getValue: function getValue(i) {
67253             return this[i].value;
67254           } //  ,getIndex:function(uri, localName)){
67255           //            if(localName){
67256           //                    
67257           //            }else{
67258           //                    var qName = uri
67259           //            }
67260           //    },
67261           //    getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
67262           //    getType:function(uri,localName){}
67263           //    getType:function(i){},
67264
67265         };
67266
67267         function _set_proto_(thiz, parent) {
67268           thiz.__proto__ = parent;
67269           return thiz;
67270         }
67271
67272         if (!(_set_proto_({}, _set_proto_.prototype) instanceof _set_proto_)) {
67273           _set_proto_ = function _set_proto_(thiz, parent) {
67274             function p() {}
67275             p.prototype = parent;
67276             p = new p();
67277
67278             for (parent in thiz) {
67279               p[parent] = thiz[parent];
67280             }
67281
67282             return p;
67283           };
67284         }
67285
67286         function split$1(source, start) {
67287           var match;
67288           var buf = [];
67289           var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
67290           reg.lastIndex = start;
67291           reg.exec(source); //skip <
67292
67293           while (match = reg.exec(source)) {
67294             buf.push(match);
67295             if (match[1]) return buf;
67296           }
67297         }
67298
67299         var XMLReader_1 = XMLReader;
67300         var sax = {
67301           XMLReader: XMLReader_1
67302         };
67303
67304         /*
67305          * DOM Level 2
67306          * Object DOMException
67307          * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
67308          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
67309          */
67310         function copy$1(src, dest) {
67311           for (var p in src) {
67312             dest[p] = src[p];
67313           }
67314         }
67315         /**
67316         ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
67317         ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
67318          */
67319
67320
67321         function _extends(Class, Super) {
67322           var pt = Class.prototype;
67323
67324           if (Object.create) {
67325             var ppt = Object.create(Super.prototype);
67326             pt.__proto__ = ppt;
67327           }
67328
67329           if (!(pt instanceof Super)) {
67330             var t = function t() {};
67331             t.prototype = Super.prototype;
67332             t = new t();
67333             copy$1(pt, t);
67334             Class.prototype = pt = t;
67335           }
67336
67337           if (pt.constructor != Class) {
67338             if (typeof Class != 'function') {
67339               console.error("unknow Class:" + Class);
67340             }
67341
67342             pt.constructor = Class;
67343           }
67344         }
67345
67346         var htmlns = 'http://www.w3.org/1999/xhtml'; // Node Types
67347
67348         var NodeType = {};
67349         var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
67350         var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
67351         var TEXT_NODE = NodeType.TEXT_NODE = 3;
67352         var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
67353         var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
67354         var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
67355         var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
67356         var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
67357         var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
67358         var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
67359         var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
67360         var NOTATION_NODE = NodeType.NOTATION_NODE = 12; // ExceptionCode
67361
67362         var ExceptionCode = {};
67363         var ExceptionMessage = {};
67364         var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = (ExceptionMessage[1] = "Index size error", 1);
67365         var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = (ExceptionMessage[2] = "DOMString size error", 2);
67366         var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = (ExceptionMessage[3] = "Hierarchy request error", 3);
67367         var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = (ExceptionMessage[4] = "Wrong document", 4);
67368         var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = (ExceptionMessage[5] = "Invalid character", 5);
67369         var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = (ExceptionMessage[6] = "No data allowed", 6);
67370         var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = (ExceptionMessage[7] = "No modification allowed", 7);
67371         var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = (ExceptionMessage[8] = "Not found", 8);
67372         var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = (ExceptionMessage[9] = "Not supported", 9);
67373         var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = (ExceptionMessage[10] = "Attribute in use", 10); //level2
67374
67375         var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = (ExceptionMessage[11] = "Invalid state", 11);
67376         var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = (ExceptionMessage[12] = "Syntax error", 12);
67377         var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = (ExceptionMessage[13] = "Invalid modification", 13);
67378         var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = (ExceptionMessage[14] = "Invalid namespace", 14);
67379         var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = (ExceptionMessage[15] = "Invalid access", 15);
67380
67381         function DOMException$2(code, message) {
67382           if (message instanceof Error) {
67383             var error = message;
67384           } else {
67385             error = this;
67386             Error.call(this, ExceptionMessage[code]);
67387             this.message = ExceptionMessage[code];
67388             if (Error.captureStackTrace) Error.captureStackTrace(this, DOMException$2);
67389           }
67390
67391           error.code = code;
67392           if (message) this.message = this.message + ": " + message;
67393           return error;
67394         }
67395         DOMException$2.prototype = Error.prototype;
67396         copy$1(ExceptionCode, DOMException$2);
67397         /**
67398          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
67399          * 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.
67400          * The items in the NodeList are accessible via an integral index, starting from 0.
67401          */
67402
67403         function NodeList() {}
67404         NodeList.prototype = {
67405           /**
67406            * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
67407            * @standard level1
67408            */
67409           length: 0,
67410
67411           /**
67412            * 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.
67413            * @standard level1
67414            * @param index  unsigned long 
67415            *   Index into the collection.
67416            * @return Node
67417            *    The node at the indexth position in the NodeList, or null if that is not a valid index. 
67418            */
67419           item: function item(index) {
67420             return this[index] || null;
67421           },
67422           toString: function toString(isHTML, nodeFilter) {
67423             for (var buf = [], i = 0; i < this.length; i++) {
67424               serializeToString(this[i], buf, isHTML, nodeFilter);
67425             }
67426
67427             return buf.join('');
67428           }
67429         };
67430
67431         function LiveNodeList(node, refresh) {
67432           this._node = node;
67433           this._refresh = refresh;
67434
67435           _updateLiveList(this);
67436         }
67437
67438         function _updateLiveList(list) {
67439           var inc = list._node._inc || list._node.ownerDocument._inc;
67440
67441           if (list._inc != inc) {
67442             var ls = list._refresh(list._node); //console.log(ls.length)
67443
67444
67445             __set__(list, 'length', ls.length);
67446
67447             copy$1(ls, list);
67448             list._inc = inc;
67449           }
67450         }
67451
67452         LiveNodeList.prototype.item = function (i) {
67453           _updateLiveList(this);
67454
67455           return this[i];
67456         };
67457
67458         _extends(LiveNodeList, NodeList);
67459         /**
67460          * 
67461          * 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.
67462          * NamedNodeMap objects in the DOM are live.
67463          * used for attributes or DocumentType entities 
67464          */
67465
67466
67467         function NamedNodeMap() {}
67468
67469         function _findNodeIndex(list, node) {
67470           var i = list.length;
67471
67472           while (i--) {
67473             if (list[i] === node) {
67474               return i;
67475             }
67476           }
67477         }
67478
67479         function _addNamedNode(el, list, newAttr, oldAttr) {
67480           if (oldAttr) {
67481             list[_findNodeIndex(list, oldAttr)] = newAttr;
67482           } else {
67483             list[list.length++] = newAttr;
67484           }
67485
67486           if (el) {
67487             newAttr.ownerElement = el;
67488             var doc = el.ownerDocument;
67489
67490             if (doc) {
67491               oldAttr && _onRemoveAttribute(doc, el, oldAttr);
67492
67493               _onAddAttribute(doc, el, newAttr);
67494             }
67495           }
67496         }
67497
67498         function _removeNamedNode(el, list, attr) {
67499           //console.log('remove attr:'+attr)
67500           var i = _findNodeIndex(list, attr);
67501
67502           if (i >= 0) {
67503             var lastIndex = list.length - 1;
67504
67505             while (i < lastIndex) {
67506               list[i] = list[++i];
67507             }
67508
67509             list.length = lastIndex;
67510
67511             if (el) {
67512               var doc = el.ownerDocument;
67513
67514               if (doc) {
67515                 _onRemoveAttribute(doc, el, attr);
67516
67517                 attr.ownerElement = null;
67518               }
67519             }
67520           } else {
67521             throw DOMException$2(NOT_FOUND_ERR, new Error(el.tagName + '@' + attr));
67522           }
67523         }
67524
67525         NamedNodeMap.prototype = {
67526           length: 0,
67527           item: NodeList.prototype.item,
67528           getNamedItem: function getNamedItem(key) {
67529             //          if(key.indexOf(':')>0 || key == 'xmlns'){
67530             //                  return null;
67531             //          }
67532             //console.log()
67533             var i = this.length;
67534
67535             while (i--) {
67536               var attr = this[i]; //console.log(attr.nodeName,key)
67537
67538               if (attr.nodeName == key) {
67539                 return attr;
67540               }
67541             }
67542           },
67543           setNamedItem: function setNamedItem(attr) {
67544             var el = attr.ownerElement;
67545
67546             if (el && el != this._ownerElement) {
67547               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
67548             }
67549
67550             var oldAttr = this.getNamedItem(attr.nodeName);
67551
67552             _addNamedNode(this._ownerElement, this, attr, oldAttr);
67553
67554             return oldAttr;
67555           },
67556
67557           /* returns Node */
67558           setNamedItemNS: function setNamedItemNS(attr) {
67559             // raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
67560             var el = attr.ownerElement,
67561                 oldAttr;
67562
67563             if (el && el != this._ownerElement) {
67564               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
67565             }
67566
67567             oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
67568
67569             _addNamedNode(this._ownerElement, this, attr, oldAttr);
67570
67571             return oldAttr;
67572           },
67573
67574           /* returns Node */
67575           removeNamedItem: function removeNamedItem(key) {
67576             var attr = this.getNamedItem(key);
67577
67578             _removeNamedNode(this._ownerElement, this, attr);
67579
67580             return attr;
67581           },
67582           // raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
67583           //for level2
67584           removeNamedItemNS: function removeNamedItemNS(namespaceURI, localName) {
67585             var attr = this.getNamedItemNS(namespaceURI, localName);
67586
67587             _removeNamedNode(this._ownerElement, this, attr);
67588
67589             return attr;
67590           },
67591           getNamedItemNS: function getNamedItemNS(namespaceURI, localName) {
67592             var i = this.length;
67593
67594             while (i--) {
67595               var node = this[i];
67596
67597               if (node.localName == localName && node.namespaceURI == namespaceURI) {
67598                 return node;
67599               }
67600             }
67601
67602             return null;
67603           }
67604         };
67605         /**
67606          * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
67607          */
67608
67609         function DOMImplementation(
67610         /* Object */
67611         features) {
67612           this._features = {};
67613
67614           if (features) {
67615             for (var feature in features) {
67616               this._features = features[feature];
67617             }
67618           }
67619         }
67620         DOMImplementation.prototype = {
67621           hasFeature: function hasFeature(
67622           /* string */
67623           feature,
67624           /* string */
67625           version) {
67626             var versions = this._features[feature.toLowerCase()];
67627
67628             if (versions && (!version || version in versions)) {
67629               return true;
67630             } else {
67631               return false;
67632             }
67633           },
67634           // Introduced in DOM Level 2:
67635           createDocument: function createDocument(namespaceURI, qualifiedName, doctype) {
67636             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
67637             var doc = new Document();
67638             doc.implementation = this;
67639             doc.childNodes = new NodeList();
67640             doc.doctype = doctype;
67641
67642             if (doctype) {
67643               doc.appendChild(doctype);
67644             }
67645
67646             if (qualifiedName) {
67647               var root = doc.createElementNS(namespaceURI, qualifiedName);
67648               doc.appendChild(root);
67649             }
67650
67651             return doc;
67652           },
67653           // Introduced in DOM Level 2:
67654           createDocumentType: function createDocumentType(qualifiedName, publicId, systemId) {
67655             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
67656             var node = new DocumentType();
67657             node.name = qualifiedName;
67658             node.nodeName = qualifiedName;
67659             node.publicId = publicId;
67660             node.systemId = systemId; // Introduced in DOM Level 2:
67661             //readonly attribute DOMString        internalSubset;
67662             //TODO:..
67663             //  readonly attribute NamedNodeMap     entities;
67664             //  readonly attribute NamedNodeMap     notations;
67665
67666             return node;
67667           }
67668         };
67669         /**
67670          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
67671          */
67672
67673         function Node() {}
67674         Node.prototype = {
67675           firstChild: null,
67676           lastChild: null,
67677           previousSibling: null,
67678           nextSibling: null,
67679           attributes: null,
67680           parentNode: null,
67681           childNodes: null,
67682           ownerDocument: null,
67683           nodeValue: null,
67684           namespaceURI: null,
67685           prefix: null,
67686           localName: null,
67687           // Modified in DOM Level 2:
67688           insertBefore: function insertBefore(newChild, refChild) {
67689             //raises 
67690             return _insertBefore(this, newChild, refChild);
67691           },
67692           replaceChild: function replaceChild(newChild, oldChild) {
67693             //raises 
67694             this.insertBefore(newChild, oldChild);
67695
67696             if (oldChild) {
67697               this.removeChild(oldChild);
67698             }
67699           },
67700           removeChild: function removeChild(oldChild) {
67701             return _removeChild(this, oldChild);
67702           },
67703           appendChild: function appendChild(newChild) {
67704             return this.insertBefore(newChild, null);
67705           },
67706           hasChildNodes: function hasChildNodes() {
67707             return this.firstChild != null;
67708           },
67709           cloneNode: function cloneNode(deep) {
67710             return _cloneNode(this.ownerDocument || this, this, deep);
67711           },
67712           // Modified in DOM Level 2:
67713           normalize: function normalize() {
67714             var child = this.firstChild;
67715
67716             while (child) {
67717               var next = child.nextSibling;
67718
67719               if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
67720                 this.removeChild(next);
67721                 child.appendData(next.data);
67722               } else {
67723                 child.normalize();
67724                 child = next;
67725               }
67726             }
67727           },
67728           // Introduced in DOM Level 2:
67729           isSupported: function isSupported(feature, version) {
67730             return this.ownerDocument.implementation.hasFeature(feature, version);
67731           },
67732           // Introduced in DOM Level 2:
67733           hasAttributes: function hasAttributes() {
67734             return this.attributes.length > 0;
67735           },
67736           lookupPrefix: function lookupPrefix(namespaceURI) {
67737             var el = this;
67738
67739             while (el) {
67740               var map = el._nsMap; //console.dir(map)
67741
67742               if (map) {
67743                 for (var n in map) {
67744                   if (map[n] == namespaceURI) {
67745                     return n;
67746                   }
67747                 }
67748               }
67749
67750               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
67751             }
67752
67753             return null;
67754           },
67755           // Introduced in DOM Level 3:
67756           lookupNamespaceURI: function lookupNamespaceURI(prefix) {
67757             var el = this;
67758
67759             while (el) {
67760               var map = el._nsMap; //console.dir(map)
67761
67762               if (map) {
67763                 if (prefix in map) {
67764                   return map[prefix];
67765                 }
67766               }
67767
67768               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
67769             }
67770
67771             return null;
67772           },
67773           // Introduced in DOM Level 3:
67774           isDefaultNamespace: function isDefaultNamespace(namespaceURI) {
67775             var prefix = this.lookupPrefix(namespaceURI);
67776             return prefix == null;
67777           }
67778         };
67779
67780         function _xmlEncoder(c) {
67781           return c == '<' && '&lt;' || c == '>' && '&gt;' || c == '&' && '&amp;' || c == '"' && '&quot;' || '&#' + c.charCodeAt() + ';';
67782         }
67783
67784         copy$1(NodeType, Node);
67785         copy$1(NodeType, Node.prototype);
67786         /**
67787          * @param callback return true for continue,false for break
67788          * @return boolean true: break visit;
67789          */
67790
67791         function _visitNode(node, callback) {
67792           if (callback(node)) {
67793             return true;
67794           }
67795
67796           if (node = node.firstChild) {
67797             do {
67798               if (_visitNode(node, callback)) {
67799                 return true;
67800               }
67801             } while (node = node.nextSibling);
67802           }
67803         }
67804
67805         function Document() {}
67806
67807         function _onAddAttribute(doc, el, newAttr) {
67808           doc && doc._inc++;
67809           var ns = newAttr.namespaceURI;
67810
67811           if (ns == 'http://www.w3.org/2000/xmlns/') {
67812             //update namespace
67813             el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
67814           }
67815         }
67816
67817         function _onRemoveAttribute(doc, el, newAttr, remove) {
67818           doc && doc._inc++;
67819           var ns = newAttr.namespaceURI;
67820
67821           if (ns == 'http://www.w3.org/2000/xmlns/') {
67822             //update namespace
67823             delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
67824           }
67825         }
67826
67827         function _onUpdateChild(doc, el, newChild) {
67828           if (doc && doc._inc) {
67829             doc._inc++; //update childNodes
67830
67831             var cs = el.childNodes;
67832
67833             if (newChild) {
67834               cs[cs.length++] = newChild;
67835             } else {
67836               //console.log(1)
67837               var child = el.firstChild;
67838               var i = 0;
67839
67840               while (child) {
67841                 cs[i++] = child;
67842                 child = child.nextSibling;
67843               }
67844
67845               cs.length = i;
67846             }
67847           }
67848         }
67849         /**
67850          * attributes;
67851          * children;
67852          * 
67853          * writeable properties:
67854          * nodeValue,Attr:value,CharacterData:data
67855          * prefix
67856          */
67857
67858
67859         function _removeChild(parentNode, child) {
67860           var previous = child.previousSibling;
67861           var next = child.nextSibling;
67862
67863           if (previous) {
67864             previous.nextSibling = next;
67865           } else {
67866             parentNode.firstChild = next;
67867           }
67868
67869           if (next) {
67870             next.previousSibling = previous;
67871           } else {
67872             parentNode.lastChild = previous;
67873           }
67874
67875           _onUpdateChild(parentNode.ownerDocument, parentNode);
67876
67877           return child;
67878         }
67879         /**
67880          * preformance key(refChild == null)
67881          */
67882
67883
67884         function _insertBefore(parentNode, newChild, nextChild) {
67885           var cp = newChild.parentNode;
67886
67887           if (cp) {
67888             cp.removeChild(newChild); //remove and update
67889           }
67890
67891           if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
67892             var newFirst = newChild.firstChild;
67893
67894             if (newFirst == null) {
67895               return newChild;
67896             }
67897
67898             var newLast = newChild.lastChild;
67899           } else {
67900             newFirst = newLast = newChild;
67901           }
67902
67903           var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
67904           newFirst.previousSibling = pre;
67905           newLast.nextSibling = nextChild;
67906
67907           if (pre) {
67908             pre.nextSibling = newFirst;
67909           } else {
67910             parentNode.firstChild = newFirst;
67911           }
67912
67913           if (nextChild == null) {
67914             parentNode.lastChild = newLast;
67915           } else {
67916             nextChild.previousSibling = newLast;
67917           }
67918
67919           do {
67920             newFirst.parentNode = parentNode;
67921           } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
67922
67923           _onUpdateChild(parentNode.ownerDocument || parentNode, parentNode); //console.log(parentNode.lastChild.nextSibling == null)
67924
67925
67926           if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
67927             newChild.firstChild = newChild.lastChild = null;
67928           }
67929
67930           return newChild;
67931         }
67932
67933         function _appendSingleChild(parentNode, newChild) {
67934           var cp = newChild.parentNode;
67935
67936           if (cp) {
67937             var pre = parentNode.lastChild;
67938             cp.removeChild(newChild); //remove and update
67939
67940             var pre = parentNode.lastChild;
67941           }
67942
67943           var pre = parentNode.lastChild;
67944           newChild.parentNode = parentNode;
67945           newChild.previousSibling = pre;
67946           newChild.nextSibling = null;
67947
67948           if (pre) {
67949             pre.nextSibling = newChild;
67950           } else {
67951             parentNode.firstChild = newChild;
67952           }
67953
67954           parentNode.lastChild = newChild;
67955
67956           _onUpdateChild(parentNode.ownerDocument, parentNode, newChild);
67957
67958           return newChild; //console.log("__aa",parentNode.lastChild.nextSibling == null)
67959         }
67960
67961         Document.prototype = {
67962           //implementation : null,
67963           nodeName: '#document',
67964           nodeType: DOCUMENT_NODE,
67965           doctype: null,
67966           documentElement: null,
67967           _inc: 1,
67968           insertBefore: function insertBefore(newChild, refChild) {
67969             //raises 
67970             if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
67971               var child = newChild.firstChild;
67972
67973               while (child) {
67974                 var next = child.nextSibling;
67975                 this.insertBefore(child, refChild);
67976                 child = next;
67977               }
67978
67979               return newChild;
67980             }
67981
67982             if (this.documentElement == null && newChild.nodeType == ELEMENT_NODE) {
67983               this.documentElement = newChild;
67984             }
67985
67986             return _insertBefore(this, newChild, refChild), newChild.ownerDocument = this, newChild;
67987           },
67988           removeChild: function removeChild(oldChild) {
67989             if (this.documentElement == oldChild) {
67990               this.documentElement = null;
67991             }
67992
67993             return _removeChild(this, oldChild);
67994           },
67995           // Introduced in DOM Level 2:
67996           importNode: function importNode(importedNode, deep) {
67997             return _importNode(this, importedNode, deep);
67998           },
67999           // Introduced in DOM Level 2:
68000           getElementById: function getElementById(id) {
68001             var rtv = null;
68002
68003             _visitNode(this.documentElement, function (node) {
68004               if (node.nodeType == ELEMENT_NODE) {
68005                 if (node.getAttribute('id') == id) {
68006                   rtv = node;
68007                   return true;
68008                 }
68009               }
68010             });
68011
68012             return rtv;
68013           },
68014           //document factory method:
68015           createElement: function createElement(tagName) {
68016             var node = new Element();
68017             node.ownerDocument = this;
68018             node.nodeName = tagName;
68019             node.tagName = tagName;
68020             node.childNodes = new NodeList();
68021             var attrs = node.attributes = new NamedNodeMap();
68022             attrs._ownerElement = node;
68023             return node;
68024           },
68025           createDocumentFragment: function createDocumentFragment() {
68026             var node = new DocumentFragment();
68027             node.ownerDocument = this;
68028             node.childNodes = new NodeList();
68029             return node;
68030           },
68031           createTextNode: function createTextNode(data) {
68032             var node = new Text();
68033             node.ownerDocument = this;
68034             node.appendData(data);
68035             return node;
68036           },
68037           createComment: function createComment(data) {
68038             var node = new Comment();
68039             node.ownerDocument = this;
68040             node.appendData(data);
68041             return node;
68042           },
68043           createCDATASection: function createCDATASection(data) {
68044             var node = new CDATASection();
68045             node.ownerDocument = this;
68046             node.appendData(data);
68047             return node;
68048           },
68049           createProcessingInstruction: function createProcessingInstruction(target, data) {
68050             var node = new ProcessingInstruction();
68051             node.ownerDocument = this;
68052             node.tagName = node.target = target;
68053             node.nodeValue = node.data = data;
68054             return node;
68055           },
68056           createAttribute: function createAttribute(name) {
68057             var node = new Attr();
68058             node.ownerDocument = this;
68059             node.name = name;
68060             node.nodeName = name;
68061             node.localName = name;
68062             node.specified = true;
68063             return node;
68064           },
68065           createEntityReference: function createEntityReference(name) {
68066             var node = new EntityReference();
68067             node.ownerDocument = this;
68068             node.nodeName = name;
68069             return node;
68070           },
68071           // Introduced in DOM Level 2:
68072           createElementNS: function createElementNS(namespaceURI, qualifiedName) {
68073             var node = new Element();
68074             var pl = qualifiedName.split(':');
68075             var attrs = node.attributes = new NamedNodeMap();
68076             node.childNodes = new NodeList();
68077             node.ownerDocument = this;
68078             node.nodeName = qualifiedName;
68079             node.tagName = qualifiedName;
68080             node.namespaceURI = namespaceURI;
68081
68082             if (pl.length == 2) {
68083               node.prefix = pl[0];
68084               node.localName = pl[1];
68085             } else {
68086               //el.prefix = null;
68087               node.localName = qualifiedName;
68088             }
68089
68090             attrs._ownerElement = node;
68091             return node;
68092           },
68093           // Introduced in DOM Level 2:
68094           createAttributeNS: function createAttributeNS(namespaceURI, qualifiedName) {
68095             var node = new Attr();
68096             var pl = qualifiedName.split(':');
68097             node.ownerDocument = this;
68098             node.nodeName = qualifiedName;
68099             node.name = qualifiedName;
68100             node.namespaceURI = namespaceURI;
68101             node.specified = true;
68102
68103             if (pl.length == 2) {
68104               node.prefix = pl[0];
68105               node.localName = pl[1];
68106             } else {
68107               //el.prefix = null;
68108               node.localName = qualifiedName;
68109             }
68110
68111             return node;
68112           }
68113         };
68114
68115         _extends(Document, Node);
68116
68117         function Element() {
68118           this._nsMap = {};
68119         }
68120         Element.prototype = {
68121           nodeType: ELEMENT_NODE,
68122           hasAttribute: function hasAttribute(name) {
68123             return this.getAttributeNode(name) != null;
68124           },
68125           getAttribute: function getAttribute(name) {
68126             var attr = this.getAttributeNode(name);
68127             return attr && attr.value || '';
68128           },
68129           getAttributeNode: function getAttributeNode(name) {
68130             return this.attributes.getNamedItem(name);
68131           },
68132           setAttribute: function setAttribute(name, value) {
68133             var attr = this.ownerDocument.createAttribute(name);
68134             attr.value = attr.nodeValue = "" + value;
68135             this.setAttributeNode(attr);
68136           },
68137           removeAttribute: function removeAttribute(name) {
68138             var attr = this.getAttributeNode(name);
68139             attr && this.removeAttributeNode(attr);
68140           },
68141           //four real opeartion method
68142           appendChild: function appendChild(newChild) {
68143             if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
68144               return this.insertBefore(newChild, null);
68145             } else {
68146               return _appendSingleChild(this, newChild);
68147             }
68148           },
68149           setAttributeNode: function setAttributeNode(newAttr) {
68150             return this.attributes.setNamedItem(newAttr);
68151           },
68152           setAttributeNodeNS: function setAttributeNodeNS(newAttr) {
68153             return this.attributes.setNamedItemNS(newAttr);
68154           },
68155           removeAttributeNode: function removeAttributeNode(oldAttr) {
68156             //console.log(this == oldAttr.ownerElement)
68157             return this.attributes.removeNamedItem(oldAttr.nodeName);
68158           },
68159           //get real attribute name,and remove it by removeAttributeNode
68160           removeAttributeNS: function removeAttributeNS(namespaceURI, localName) {
68161             var old = this.getAttributeNodeNS(namespaceURI, localName);
68162             old && this.removeAttributeNode(old);
68163           },
68164           hasAttributeNS: function hasAttributeNS(namespaceURI, localName) {
68165             return this.getAttributeNodeNS(namespaceURI, localName) != null;
68166           },
68167           getAttributeNS: function getAttributeNS(namespaceURI, localName) {
68168             var attr = this.getAttributeNodeNS(namespaceURI, localName);
68169             return attr && attr.value || '';
68170           },
68171           setAttributeNS: function setAttributeNS(namespaceURI, qualifiedName, value) {
68172             var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
68173             attr.value = attr.nodeValue = "" + value;
68174             this.setAttributeNode(attr);
68175           },
68176           getAttributeNodeNS: function getAttributeNodeNS(namespaceURI, localName) {
68177             return this.attributes.getNamedItemNS(namespaceURI, localName);
68178           },
68179           getElementsByTagName: function getElementsByTagName(tagName) {
68180             return new LiveNodeList(this, function (base) {
68181               var ls = [];
68182
68183               _visitNode(base, function (node) {
68184                 if (node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)) {
68185                   ls.push(node);
68186                 }
68187               });
68188
68189               return ls;
68190             });
68191           },
68192           getElementsByTagNameNS: function getElementsByTagNameNS(namespaceURI, localName) {
68193             return new LiveNodeList(this, function (base) {
68194               var ls = [];
68195
68196               _visitNode(base, function (node) {
68197                 if (node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)) {
68198                   ls.push(node);
68199                 }
68200               });
68201
68202               return ls;
68203             });
68204           }
68205         };
68206         Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
68207         Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
68208
68209         _extends(Element, Node);
68210
68211         function Attr() {}
68212         Attr.prototype.nodeType = ATTRIBUTE_NODE;
68213
68214         _extends(Attr, Node);
68215
68216         function CharacterData() {}
68217         CharacterData.prototype = {
68218           data: '',
68219           substringData: function substringData(offset, count) {
68220             return this.data.substring(offset, offset + count);
68221           },
68222           appendData: function appendData(text) {
68223             text = this.data + text;
68224             this.nodeValue = this.data = text;
68225             this.length = text.length;
68226           },
68227           insertData: function insertData(offset, text) {
68228             this.replaceData(offset, 0, text);
68229           },
68230           appendChild: function appendChild(newChild) {
68231             throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]);
68232           },
68233           deleteData: function deleteData(offset, count) {
68234             this.replaceData(offset, count, "");
68235           },
68236           replaceData: function replaceData(offset, count, text) {
68237             var start = this.data.substring(0, offset);
68238             var end = this.data.substring(offset + count);
68239             text = start + text + end;
68240             this.nodeValue = this.data = text;
68241             this.length = text.length;
68242           }
68243         };
68244
68245         _extends(CharacterData, Node);
68246
68247         function Text() {}
68248         Text.prototype = {
68249           nodeName: "#text",
68250           nodeType: TEXT_NODE,
68251           splitText: function splitText(offset) {
68252             var text = this.data;
68253             var newText = text.substring(offset);
68254             text = text.substring(0, offset);
68255             this.data = this.nodeValue = text;
68256             this.length = text.length;
68257             var newNode = this.ownerDocument.createTextNode(newText);
68258
68259             if (this.parentNode) {
68260               this.parentNode.insertBefore(newNode, this.nextSibling);
68261             }
68262
68263             return newNode;
68264           }
68265         };
68266
68267         _extends(Text, CharacterData);
68268
68269         function Comment() {}
68270         Comment.prototype = {
68271           nodeName: "#comment",
68272           nodeType: COMMENT_NODE
68273         };
68274
68275         _extends(Comment, CharacterData);
68276
68277         function CDATASection() {}
68278         CDATASection.prototype = {
68279           nodeName: "#cdata-section",
68280           nodeType: CDATA_SECTION_NODE
68281         };
68282
68283         _extends(CDATASection, CharacterData);
68284
68285         function DocumentType() {}
68286         DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
68287
68288         _extends(DocumentType, Node);
68289
68290         function Notation() {}
68291         Notation.prototype.nodeType = NOTATION_NODE;
68292
68293         _extends(Notation, Node);
68294
68295         function Entity() {}
68296         Entity.prototype.nodeType = ENTITY_NODE;
68297
68298         _extends(Entity, Node);
68299
68300         function EntityReference() {}
68301         EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
68302
68303         _extends(EntityReference, Node);
68304
68305         function DocumentFragment() {}
68306         DocumentFragment.prototype.nodeName = "#document-fragment";
68307         DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
68308
68309         _extends(DocumentFragment, Node);
68310
68311         function ProcessingInstruction() {}
68312
68313         ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
68314
68315         _extends(ProcessingInstruction, Node);
68316
68317         function XMLSerializer$1() {}
68318
68319         XMLSerializer$1.prototype.serializeToString = function (node, isHtml, nodeFilter) {
68320           return nodeSerializeToString.call(node, isHtml, nodeFilter);
68321         };
68322
68323         Node.prototype.toString = nodeSerializeToString;
68324
68325         function nodeSerializeToString(isHtml, nodeFilter) {
68326           var buf = [];
68327           var refNode = this.nodeType == 9 ? this.documentElement : this;
68328           var prefix = refNode.prefix;
68329           var uri = refNode.namespaceURI;
68330
68331           if (uri && prefix == null) {
68332             //console.log(prefix)
68333             var prefix = refNode.lookupPrefix(uri);
68334
68335             if (prefix == null) {
68336               //isHTML = true;
68337               var visibleNamespaces = [{
68338                 namespace: uri,
68339                 prefix: null
68340               } //{namespace:uri,prefix:''}
68341               ];
68342             }
68343           }
68344
68345           serializeToString(this, buf, isHtml, nodeFilter, visibleNamespaces); //console.log('###',this.nodeType,uri,prefix,buf.join(''))
68346
68347           return buf.join('');
68348         }
68349
68350         function needNamespaceDefine(node, isHTML, visibleNamespaces) {
68351           var prefix = node.prefix || '';
68352           var uri = node.namespaceURI;
68353
68354           if (!prefix && !uri) {
68355             return false;
68356           }
68357
68358           if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" || uri == 'http://www.w3.org/2000/xmlns/') {
68359             return false;
68360           }
68361
68362           var i = visibleNamespaces.length; //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
68363
68364           while (i--) {
68365             var ns = visibleNamespaces[i]; // get namespace prefix
68366             //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
68367
68368             if (ns.prefix == prefix) {
68369               return ns.namespace != uri;
68370             }
68371           } //console.log(isHTML,uri,prefix=='')
68372           //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
68373           //    return false;
68374           //}
68375           //node.flag = '11111'
68376           //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
68377
68378
68379           return true;
68380         }
68381
68382         function serializeToString(node, buf, isHTML, nodeFilter, visibleNamespaces) {
68383           if (nodeFilter) {
68384             node = nodeFilter(node);
68385
68386             if (node) {
68387               if (typeof node == 'string') {
68388                 buf.push(node);
68389                 return;
68390               }
68391             } else {
68392               return;
68393             } //buf.sort.apply(attrs, attributeSorter);
68394
68395           }
68396
68397           switch (node.nodeType) {
68398             case ELEMENT_NODE:
68399               if (!visibleNamespaces) visibleNamespaces = [];
68400               var startVisibleNamespaces = visibleNamespaces.length;
68401               var attrs = node.attributes;
68402               var len = attrs.length;
68403               var child = node.firstChild;
68404               var nodeName = node.tagName;
68405               isHTML = htmlns === node.namespaceURI || isHTML;
68406               buf.push('<', nodeName);
68407
68408               for (var i = 0; i < len; i++) {
68409                 // add namespaces for attributes
68410                 var attr = attrs.item(i);
68411
68412                 if (attr.prefix == 'xmlns') {
68413                   visibleNamespaces.push({
68414                     prefix: attr.localName,
68415                     namespace: attr.value
68416                   });
68417                 } else if (attr.nodeName == 'xmlns') {
68418                   visibleNamespaces.push({
68419                     prefix: '',
68420                     namespace: attr.value
68421                   });
68422                 }
68423               }
68424
68425               for (var i = 0; i < len; i++) {
68426                 var attr = attrs.item(i);
68427
68428                 if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
68429                   var prefix = attr.prefix || '';
68430                   var uri = attr.namespaceURI;
68431                   var ns = prefix ? ' xmlns:' + prefix : " xmlns";
68432                   buf.push(ns, '="', uri, '"');
68433                   visibleNamespaces.push({
68434                     prefix: prefix,
68435                     namespace: uri
68436                   });
68437                 }
68438
68439                 serializeToString(attr, buf, isHTML, nodeFilter, visibleNamespaces);
68440               } // add namespace for current node               
68441
68442
68443               if (needNamespaceDefine(node, isHTML, visibleNamespaces)) {
68444                 var prefix = node.prefix || '';
68445                 var uri = node.namespaceURI;
68446                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
68447                 buf.push(ns, '="', uri, '"');
68448                 visibleNamespaces.push({
68449                   prefix: prefix,
68450                   namespace: uri
68451                 });
68452               }
68453
68454               if (child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)) {
68455                 buf.push('>'); //if is cdata child node
68456
68457                 if (isHTML && /^script$/i.test(nodeName)) {
68458                   while (child) {
68459                     if (child.data) {
68460                       buf.push(child.data);
68461                     } else {
68462                       serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
68463                     }
68464
68465                     child = child.nextSibling;
68466                   }
68467                 } else {
68468                   while (child) {
68469                     serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
68470                     child = child.nextSibling;
68471                   }
68472                 }
68473
68474                 buf.push('</', nodeName, '>');
68475               } else {
68476                 buf.push('/>');
68477               } // remove added visible namespaces
68478               //visibleNamespaces.length = startVisibleNamespaces;
68479
68480
68481               return;
68482
68483             case DOCUMENT_NODE:
68484             case DOCUMENT_FRAGMENT_NODE:
68485               var child = node.firstChild;
68486
68487               while (child) {
68488                 serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
68489                 child = child.nextSibling;
68490               }
68491
68492               return;
68493
68494             case ATTRIBUTE_NODE:
68495               return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g, _xmlEncoder), '"');
68496
68497             case TEXT_NODE:
68498               return buf.push(node.data.replace(/[<&]/g, _xmlEncoder));
68499
68500             case CDATA_SECTION_NODE:
68501               return buf.push('<![CDATA[', node.data, ']]>');
68502
68503             case COMMENT_NODE:
68504               return buf.push("<!--", node.data, "-->");
68505
68506             case DOCUMENT_TYPE_NODE:
68507               var pubid = node.publicId;
68508               var sysid = node.systemId;
68509               buf.push('<!DOCTYPE ', node.name);
68510
68511               if (pubid) {
68512                 buf.push(' PUBLIC "', pubid);
68513
68514                 if (sysid && sysid != '.') {
68515                   buf.push('" "', sysid);
68516                 }
68517
68518                 buf.push('">');
68519               } else if (sysid && sysid != '.') {
68520                 buf.push(' SYSTEM "', sysid, '">');
68521               } else {
68522                 var sub = node.internalSubset;
68523
68524                 if (sub) {
68525                   buf.push(" [", sub, "]");
68526                 }
68527
68528                 buf.push(">");
68529               }
68530
68531               return;
68532
68533             case PROCESSING_INSTRUCTION_NODE:
68534               return buf.push("<?", node.target, " ", node.data, "?>");
68535
68536             case ENTITY_REFERENCE_NODE:
68537               return buf.push('&', node.nodeName, ';');
68538             //case ENTITY_NODE:
68539             //case NOTATION_NODE:
68540
68541             default:
68542               buf.push('??', node.nodeName);
68543           }
68544         }
68545
68546         function _importNode(doc, node, deep) {
68547           var node2;
68548
68549           switch (node.nodeType) {
68550             case ELEMENT_NODE:
68551               node2 = node.cloneNode(false);
68552               node2.ownerDocument = doc;
68553             //var attrs = node2.attributes;
68554             //var len = attrs.length;
68555             //for(var i=0;i<len;i++){
68556             //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
68557             //}
68558
68559             case DOCUMENT_FRAGMENT_NODE:
68560               break;
68561
68562             case ATTRIBUTE_NODE:
68563               deep = true;
68564               break;
68565             //case ENTITY_REFERENCE_NODE:
68566             //case PROCESSING_INSTRUCTION_NODE:
68567             ////case TEXT_NODE:
68568             //case CDATA_SECTION_NODE:
68569             //case COMMENT_NODE:
68570             //  deep = false;
68571             //  break;
68572             //case DOCUMENT_NODE:
68573             //case DOCUMENT_TYPE_NODE:
68574             //cannot be imported.
68575             //case ENTITY_NODE:
68576             //case NOTATION_NODE:
68577             //can not hit in level3
68578             //default:throw e;
68579           }
68580
68581           if (!node2) {
68582             node2 = node.cloneNode(false); //false
68583           }
68584
68585           node2.ownerDocument = doc;
68586           node2.parentNode = null;
68587
68588           if (deep) {
68589             var child = node.firstChild;
68590
68591             while (child) {
68592               node2.appendChild(_importNode(doc, child, deep));
68593               child = child.nextSibling;
68594             }
68595           }
68596
68597           return node2;
68598         } //
68599         //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
68600         //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
68601
68602
68603         function _cloneNode(doc, node, deep) {
68604           var node2 = new node.constructor();
68605
68606           for (var n in node) {
68607             var v = node[n];
68608
68609             if (_typeof(v) != 'object') {
68610               if (v != node2[n]) {
68611                 node2[n] = v;
68612               }
68613             }
68614           }
68615
68616           if (node.childNodes) {
68617             node2.childNodes = new NodeList();
68618           }
68619
68620           node2.ownerDocument = doc;
68621
68622           switch (node2.nodeType) {
68623             case ELEMENT_NODE:
68624               var attrs = node.attributes;
68625               var attrs2 = node2.attributes = new NamedNodeMap();
68626               var len = attrs.length;
68627               attrs2._ownerElement = node2;
68628
68629               for (var i = 0; i < len; i++) {
68630                 node2.setAttributeNode(_cloneNode(doc, attrs.item(i), true));
68631               }
68632
68633               break;
68634
68635             case ATTRIBUTE_NODE:
68636               deep = true;
68637           }
68638
68639           if (deep) {
68640             var child = node.firstChild;
68641
68642             while (child) {
68643               node2.appendChild(_cloneNode(doc, child, deep));
68644               child = child.nextSibling;
68645             }
68646           }
68647
68648           return node2;
68649         }
68650
68651         function __set__(object, key, value) {
68652           object[key] = value;
68653         } //do dynamic
68654
68655
68656         try {
68657           if (Object.defineProperty) {
68658             var getTextContent = function getTextContent(node) {
68659               switch (node.nodeType) {
68660                 case ELEMENT_NODE:
68661                 case DOCUMENT_FRAGMENT_NODE:
68662                   var buf = [];
68663                   node = node.firstChild;
68664
68665                   while (node) {
68666                     if (node.nodeType !== 7 && node.nodeType !== 8) {
68667                       buf.push(getTextContent(node));
68668                     }
68669
68670                     node = node.nextSibling;
68671                   }
68672
68673                   return buf.join('');
68674
68675                 default:
68676                   return node.nodeValue;
68677               }
68678             };
68679
68680             Object.defineProperty(LiveNodeList.prototype, 'length', {
68681               get: function get() {
68682                 _updateLiveList(this);
68683
68684                 return this.$$length;
68685               }
68686             });
68687             Object.defineProperty(Node.prototype, 'textContent', {
68688               get: function get() {
68689                 return getTextContent(this);
68690               },
68691               set: function set(data) {
68692                 switch (this.nodeType) {
68693                   case ELEMENT_NODE:
68694                   case DOCUMENT_FRAGMENT_NODE:
68695                     while (this.firstChild) {
68696                       this.removeChild(this.firstChild);
68697                     }
68698
68699                     if (data || String(data)) {
68700                       this.appendChild(this.ownerDocument.createTextNode(data));
68701                     }
68702
68703                     break;
68704
68705                   default:
68706                     //TODO:
68707                     this.data = data;
68708                     this.value = data;
68709                     this.nodeValue = data;
68710                 }
68711               }
68712             });
68713
68714             __set__ = function __set__(object, key, value) {
68715               //console.log(value)
68716               object['$$' + key] = value;
68717             };
68718           }
68719         } catch (e) {//ie8
68720         } //if(typeof require == 'function'){
68721
68722
68723         var DOMImplementation_1 = DOMImplementation;
68724         var XMLSerializer_1 = XMLSerializer$1; //}
68725
68726         var dom = {
68727           DOMImplementation: DOMImplementation_1,
68728           XMLSerializer: XMLSerializer_1
68729         };
68730
68731         var domParser = createCommonjsModule(function (module, exports) {
68732           function DOMParser(options) {
68733             this.options = options || {
68734               locator: {}
68735             };
68736           }
68737
68738           DOMParser.prototype.parseFromString = function (source, mimeType) {
68739             var options = this.options;
68740             var sax = new XMLReader();
68741             var domBuilder = options.domBuilder || new DOMHandler(); //contentHandler and LexicalHandler
68742
68743             var errorHandler = options.errorHandler;
68744             var locator = options.locator;
68745             var defaultNSMap = options.xmlns || {};
68746             var entityMap = {
68747               'lt': '<',
68748               'gt': '>',
68749               'amp': '&',
68750               'quot': '"',
68751               'apos': "'"
68752             };
68753
68754             if (locator) {
68755               domBuilder.setDocumentLocator(locator);
68756             }
68757
68758             sax.errorHandler = buildErrorHandler(errorHandler, domBuilder, locator);
68759             sax.domBuilder = options.domBuilder || domBuilder;
68760
68761             if (/\/x?html?$/.test(mimeType)) {
68762               entityMap.nbsp = '\xa0';
68763               entityMap.copy = '\xa9';
68764               defaultNSMap[''] = 'http://www.w3.org/1999/xhtml';
68765             }
68766
68767             defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
68768
68769             if (source) {
68770               sax.parse(source, defaultNSMap, entityMap);
68771             } else {
68772               sax.errorHandler.error("invalid doc source");
68773             }
68774
68775             return domBuilder.doc;
68776           };
68777
68778           function buildErrorHandler(errorImpl, domBuilder, locator) {
68779             if (!errorImpl) {
68780               if (domBuilder instanceof DOMHandler) {
68781                 return domBuilder;
68782               }
68783
68784               errorImpl = domBuilder;
68785             }
68786
68787             var errorHandler = {};
68788             var isCallback = errorImpl instanceof Function;
68789             locator = locator || {};
68790
68791             function build(key) {
68792               var fn = errorImpl[key];
68793
68794               if (!fn && isCallback) {
68795                 fn = errorImpl.length == 2 ? function (msg) {
68796                   errorImpl(key, msg);
68797                 } : errorImpl;
68798               }
68799
68800               errorHandler[key] = fn && function (msg) {
68801                 fn('[xmldom ' + key + ']\t' + msg + _locator(locator));
68802               } || function () {};
68803             }
68804
68805             build('warning');
68806             build('error');
68807             build('fatalError');
68808             return errorHandler;
68809           } //console.log('#\n\n\n\n\n\n\n####')
68810
68811           /**
68812            * +ContentHandler+ErrorHandler
68813            * +LexicalHandler+EntityResolver2
68814            * -DeclHandler-DTDHandler 
68815            * 
68816            * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
68817            * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
68818            * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
68819            */
68820
68821
68822           function DOMHandler() {
68823             this.cdata = false;
68824           }
68825
68826           function position(locator, node) {
68827             node.lineNumber = locator.lineNumber;
68828             node.columnNumber = locator.columnNumber;
68829           }
68830           /**
68831            * @see org.xml.sax.ContentHandler#startDocument
68832            * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
68833            */
68834
68835
68836           DOMHandler.prototype = {
68837             startDocument: function startDocument() {
68838               this.doc = new DOMImplementation().createDocument(null, null, null);
68839
68840               if (this.locator) {
68841                 this.doc.documentURI = this.locator.systemId;
68842               }
68843             },
68844             startElement: function startElement(namespaceURI, localName, qName, attrs) {
68845               var doc = this.doc;
68846               var el = doc.createElementNS(namespaceURI, qName || localName);
68847               var len = attrs.length;
68848               appendElement(this, el);
68849               this.currentElement = el;
68850               this.locator && position(this.locator, el);
68851
68852               for (var i = 0; i < len; i++) {
68853                 var namespaceURI = attrs.getURI(i);
68854                 var value = attrs.getValue(i);
68855                 var qName = attrs.getQName(i);
68856                 var attr = doc.createAttributeNS(namespaceURI, qName);
68857                 this.locator && position(attrs.getLocator(i), attr);
68858                 attr.value = attr.nodeValue = value;
68859                 el.setAttributeNode(attr);
68860               }
68861             },
68862             endElement: function endElement(namespaceURI, localName, qName) {
68863               var current = this.currentElement;
68864               var tagName = current.tagName;
68865               this.currentElement = current.parentNode;
68866             },
68867             startPrefixMapping: function startPrefixMapping(prefix, uri) {},
68868             endPrefixMapping: function endPrefixMapping(prefix) {},
68869             processingInstruction: function processingInstruction(target, data) {
68870               var ins = this.doc.createProcessingInstruction(target, data);
68871               this.locator && position(this.locator, ins);
68872               appendElement(this, ins);
68873             },
68874             ignorableWhitespace: function ignorableWhitespace(ch, start, length) {},
68875             characters: function characters(chars, start, length) {
68876               chars = _toString.apply(this, arguments); //console.log(chars)
68877
68878               if (chars) {
68879                 if (this.cdata) {
68880                   var charNode = this.doc.createCDATASection(chars);
68881                 } else {
68882                   var charNode = this.doc.createTextNode(chars);
68883                 }
68884
68885                 if (this.currentElement) {
68886                   this.currentElement.appendChild(charNode);
68887                 } else if (/^\s*$/.test(chars)) {
68888                   this.doc.appendChild(charNode); //process xml
68889                 }
68890
68891                 this.locator && position(this.locator, charNode);
68892               }
68893             },
68894             skippedEntity: function skippedEntity(name) {},
68895             endDocument: function endDocument() {
68896               this.doc.normalize();
68897             },
68898             setDocumentLocator: function setDocumentLocator(locator) {
68899               if (this.locator = locator) {
68900                 // && !('lineNumber' in locator)){
68901                 locator.lineNumber = 0;
68902               }
68903             },
68904             //LexicalHandler
68905             comment: function comment(chars, start, length) {
68906               chars = _toString.apply(this, arguments);
68907               var comm = this.doc.createComment(chars);
68908               this.locator && position(this.locator, comm);
68909               appendElement(this, comm);
68910             },
68911             startCDATA: function startCDATA() {
68912               //used in characters() methods
68913               this.cdata = true;
68914             },
68915             endCDATA: function endCDATA() {
68916               this.cdata = false;
68917             },
68918             startDTD: function startDTD(name, publicId, systemId) {
68919               var impl = this.doc.implementation;
68920
68921               if (impl && impl.createDocumentType) {
68922                 var dt = impl.createDocumentType(name, publicId, systemId);
68923                 this.locator && position(this.locator, dt);
68924                 appendElement(this, dt);
68925               }
68926             },
68927
68928             /**
68929              * @see org.xml.sax.ErrorHandler
68930              * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
68931              */
68932             warning: function warning(error) {
68933               console.warn('[xmldom warning]\t' + error, _locator(this.locator));
68934             },
68935             error: function error(_error) {
68936               console.error('[xmldom error]\t' + _error, _locator(this.locator));
68937             },
68938             fatalError: function fatalError(error) {
68939               console.error('[xmldom fatalError]\t' + error, _locator(this.locator));
68940               throw error;
68941             }
68942           };
68943
68944           function _locator(l) {
68945             if (l) {
68946               return '\n@' + (l.systemId || '') + '#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']';
68947             }
68948           }
68949
68950           function _toString(chars, start, length) {
68951             if (typeof chars == 'string') {
68952               return chars.substr(start, length);
68953             } else {
68954               //java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
68955               if (chars.length >= start + length || start) {
68956                 return new java.lang.String(chars, start, length) + '';
68957               }
68958
68959               return chars;
68960             }
68961           }
68962           /*
68963            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
68964            * used method of org.xml.sax.ext.LexicalHandler:
68965            *  #comment(chars, start, length)
68966            *  #startCDATA()
68967            *  #endCDATA()
68968            *  #startDTD(name, publicId, systemId)
68969            *
68970            *
68971            * IGNORED method of org.xml.sax.ext.LexicalHandler:
68972            *  #endDTD()
68973            *  #startEntity(name)
68974            *  #endEntity(name)
68975            *
68976            *
68977            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
68978            * IGNORED method of org.xml.sax.ext.DeclHandler
68979            *    #attributeDecl(eName, aName, type, mode, value)
68980            *  #elementDecl(name, model)
68981            *  #externalEntityDecl(name, publicId, systemId)
68982            *  #internalEntityDecl(name, value)
68983            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
68984            * IGNORED method of org.xml.sax.EntityResolver2
68985            *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
68986            *  #resolveEntity(publicId, systemId)
68987            *  #getExternalSubset(name, baseURI)
68988            * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
68989            * IGNORED method of org.xml.sax.DTDHandler
68990            *  #notationDecl(name, publicId, systemId) {};
68991            *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
68992            */
68993
68994
68995           "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g, function (key) {
68996             DOMHandler.prototype[key] = function () {
68997               return null;
68998             };
68999           });
69000           /* 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 */
69001
69002           function appendElement(hander, node) {
69003             if (!hander.currentElement) {
69004               hander.doc.appendChild(node);
69005             } else {
69006               hander.currentElement.appendChild(node);
69007             }
69008           } //appendChild and setAttributeNS are preformance key
69009           //if(typeof require == 'function'){
69010
69011
69012           var XMLReader = sax.XMLReader;
69013           var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
69014           exports.XMLSerializer = dom.XMLSerializer;
69015           exports.DOMParser = DOMParser; //}
69016         });
69017
69018         var togeojson = createCommonjsModule(function (module, exports) {
69019           var toGeoJSON = function () {
69020
69021             var removeSpace = /\s*/g,
69022                 trimSpace = /^\s*|\s*$/g,
69023                 splitSpace = /\s+/; // generate a short, numeric hash of a string
69024
69025             function okhash(x) {
69026               if (!x || !x.length) return 0;
69027
69028               for (var i = 0, h = 0; i < x.length; i++) {
69029                 h = (h << 5) - h + x.charCodeAt(i) | 0;
69030               }
69031
69032               return h;
69033             } // all Y children of X
69034
69035
69036             function get(x, y) {
69037               return x.getElementsByTagName(y);
69038             }
69039
69040             function attr(x, y) {
69041               return x.getAttribute(y);
69042             }
69043
69044             function attrf(x, y) {
69045               return parseFloat(attr(x, y));
69046             } // one Y child of X, if any, otherwise null
69047
69048
69049             function get1(x, y) {
69050               var n = get(x, y);
69051               return n.length ? n[0] : null;
69052             } // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
69053
69054
69055             function norm(el) {
69056               if (el.normalize) {
69057                 el.normalize();
69058               }
69059
69060               return el;
69061             } // cast array x into numbers
69062
69063
69064             function numarray(x) {
69065               for (var j = 0, o = []; j < x.length; j++) {
69066                 o[j] = parseFloat(x[j]);
69067               }
69068
69069               return o;
69070             } // get the content of a text node, if any
69071
69072
69073             function nodeVal(x) {
69074               if (x) {
69075                 norm(x);
69076               }
69077
69078               return x && x.textContent || '';
69079             } // get the contents of multiple text nodes, if present
69080
69081
69082             function getMulti(x, ys) {
69083               var o = {},
69084                   n,
69085                   k;
69086
69087               for (k = 0; k < ys.length; k++) {
69088                 n = get1(x, ys[k]);
69089                 if (n) o[ys[k]] = nodeVal(n);
69090               }
69091
69092               return o;
69093             } // add properties of Y to X, overwriting if present in both
69094
69095
69096             function extend(x, y) {
69097               for (var k in y) {
69098                 x[k] = y[k];
69099               }
69100             } // get one coordinate from a coordinate array, if any
69101
69102
69103             function coord1(v) {
69104               return numarray(v.replace(removeSpace, '').split(','));
69105             } // get all coordinates from a coordinate array as [[],[]]
69106
69107
69108             function coord(v) {
69109               var coords = v.replace(trimSpace, '').split(splitSpace),
69110                   o = [];
69111
69112               for (var i = 0; i < coords.length; i++) {
69113                 o.push(coord1(coords[i]));
69114               }
69115
69116               return o;
69117             }
69118
69119             function coordPair(x) {
69120               var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
69121                   ele = get1(x, 'ele'),
69122                   // handle namespaced attribute in browser
69123               heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
69124                   time = get1(x, 'time'),
69125                   e;
69126
69127               if (ele) {
69128                 e = parseFloat(nodeVal(ele));
69129
69130                 if (!isNaN(e)) {
69131                   ll.push(e);
69132                 }
69133               }
69134
69135               return {
69136                 coordinates: ll,
69137                 time: time ? nodeVal(time) : null,
69138                 heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
69139               };
69140             } // create a new feature collection parent object
69141
69142
69143             function fc() {
69144               return {
69145                 type: 'FeatureCollection',
69146                 features: []
69147               };
69148             }
69149
69150             var serializer;
69151
69152             if (typeof XMLSerializer !== 'undefined') {
69153               /* istanbul ignore next */
69154               serializer = new XMLSerializer(); // only require xmldom in a node environment
69155             } else if ( (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && !process.browser) {
69156               serializer = new domParser.XMLSerializer();
69157             }
69158
69159             function xml2str(str) {
69160               // IE9 will create a new XMLSerializer but it'll crash immediately.
69161               // This line is ignored because we don't run coverage tests in IE9
69162
69163               /* istanbul ignore next */
69164               if (str.xml !== undefined) return str.xml;
69165               return serializer.serializeToString(str);
69166             }
69167
69168             var t = {
69169               kml: function kml(doc) {
69170                 var gj = fc(),
69171                     // styleindex keeps track of hashed styles in order to match features
69172                 styleIndex = {},
69173                     styleByHash = {},
69174                     // stylemapindex keeps track of style maps to expose in properties
69175                 styleMapIndex = {},
69176                     // atomic geospatial types supported by KML - MultiGeometry is
69177                 // handled separately
69178                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
69179                     // all root placemarks in the file
69180                 placemarks = get(doc, 'Placemark'),
69181                     styles = get(doc, 'Style'),
69182                     styleMaps = get(doc, 'StyleMap');
69183
69184                 for (var k = 0; k < styles.length; k++) {
69185                   var hash = okhash(xml2str(styles[k])).toString(16);
69186                   styleIndex['#' + attr(styles[k], 'id')] = hash;
69187                   styleByHash[hash] = styles[k];
69188                 }
69189
69190                 for (var l = 0; l < styleMaps.length; l++) {
69191                   styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
69192                   var pairs = get(styleMaps[l], 'Pair');
69193                   var pairsMap = {};
69194
69195                   for (var m = 0; m < pairs.length; m++) {
69196                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
69197                   }
69198
69199                   styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
69200                 }
69201
69202                 for (var j = 0; j < placemarks.length; j++) {
69203                   gj.features = gj.features.concat(getPlacemark(placemarks[j]));
69204                 }
69205
69206                 function kmlColor(v) {
69207                   var color, opacity;
69208                   v = v || '';
69209
69210                   if (v.substr(0, 1) === '#') {
69211                     v = v.substr(1);
69212                   }
69213
69214                   if (v.length === 6 || v.length === 3) {
69215                     color = v;
69216                   }
69217
69218                   if (v.length === 8) {
69219                     opacity = parseInt(v.substr(0, 2), 16) / 255;
69220                     color = '#' + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
69221                   }
69222
69223                   return [color, isNaN(opacity) ? undefined : opacity];
69224                 }
69225
69226                 function gxCoord(v) {
69227                   return numarray(v.split(' '));
69228                 }
69229
69230                 function gxCoords(root) {
69231                   var elems = get(root, 'coord'),
69232                       coords = [],
69233                       times = [];
69234                   if (elems.length === 0) elems = get(root, 'gx:coord');
69235
69236                   for (var i = 0; i < elems.length; i++) {
69237                     coords.push(gxCoord(nodeVal(elems[i])));
69238                   }
69239
69240                   var timeElems = get(root, 'when');
69241
69242                   for (var j = 0; j < timeElems.length; j++) {
69243                     times.push(nodeVal(timeElems[j]));
69244                   }
69245
69246                   return {
69247                     coords: coords,
69248                     times: times
69249                   };
69250                 }
69251
69252                 function getGeometry(root) {
69253                   var geomNode,
69254                       geomNodes,
69255                       i,
69256                       j,
69257                       k,
69258                       geoms = [],
69259                       coordTimes = [];
69260
69261                   if (get1(root, 'MultiGeometry')) {
69262                     return getGeometry(get1(root, 'MultiGeometry'));
69263                   }
69264
69265                   if (get1(root, 'MultiTrack')) {
69266                     return getGeometry(get1(root, 'MultiTrack'));
69267                   }
69268
69269                   if (get1(root, 'gx:MultiTrack')) {
69270                     return getGeometry(get1(root, 'gx:MultiTrack'));
69271                   }
69272
69273                   for (i = 0; i < geotypes.length; i++) {
69274                     geomNodes = get(root, geotypes[i]);
69275
69276                     if (geomNodes) {
69277                       for (j = 0; j < geomNodes.length; j++) {
69278                         geomNode = geomNodes[j];
69279
69280                         if (geotypes[i] === 'Point') {
69281                           geoms.push({
69282                             type: 'Point',
69283                             coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
69284                           });
69285                         } else if (geotypes[i] === 'LineString') {
69286                           geoms.push({
69287                             type: 'LineString',
69288                             coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
69289                           });
69290                         } else if (geotypes[i] === 'Polygon') {
69291                           var rings = get(geomNode, 'LinearRing'),
69292                               coords = [];
69293
69294                           for (k = 0; k < rings.length; k++) {
69295                             coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
69296                           }
69297
69298                           geoms.push({
69299                             type: 'Polygon',
69300                             coordinates: coords
69301                           });
69302                         } else if (geotypes[i] === 'Track' || geotypes[i] === 'gx:Track') {
69303                           var track = gxCoords(geomNode);
69304                           geoms.push({
69305                             type: 'LineString',
69306                             coordinates: track.coords
69307                           });
69308                           if (track.times.length) coordTimes.push(track.times);
69309                         }
69310                       }
69311                     }
69312                   }
69313
69314                   return {
69315                     geoms: geoms,
69316                     coordTimes: coordTimes
69317                   };
69318                 }
69319
69320                 function getPlacemark(root) {
69321                   var geomsAndTimes = getGeometry(root),
69322                       i,
69323                       properties = {},
69324                       name = nodeVal(get1(root, 'name')),
69325                       address = nodeVal(get1(root, 'address')),
69326                       styleUrl = nodeVal(get1(root, 'styleUrl')),
69327                       description = nodeVal(get1(root, 'description')),
69328                       timeSpan = get1(root, 'TimeSpan'),
69329                       timeStamp = get1(root, 'TimeStamp'),
69330                       extendedData = get1(root, 'ExtendedData'),
69331                       lineStyle = get1(root, 'LineStyle'),
69332                       polyStyle = get1(root, 'PolyStyle'),
69333                       visibility = get1(root, 'visibility');
69334                   if (!geomsAndTimes.geoms.length) return [];
69335                   if (name) properties.name = name;
69336                   if (address) properties.address = address;
69337
69338                   if (styleUrl) {
69339                     if (styleUrl[0] !== '#') {
69340                       styleUrl = '#' + styleUrl;
69341                     }
69342
69343                     properties.styleUrl = styleUrl;
69344
69345                     if (styleIndex[styleUrl]) {
69346                       properties.styleHash = styleIndex[styleUrl];
69347                     }
69348
69349                     if (styleMapIndex[styleUrl]) {
69350                       properties.styleMapHash = styleMapIndex[styleUrl];
69351                       properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
69352                     } // Try to populate the lineStyle or polyStyle since we got the style hash
69353
69354
69355                     var style = styleByHash[properties.styleHash];
69356
69357                     if (style) {
69358                       if (!lineStyle) lineStyle = get1(style, 'LineStyle');
69359                       if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
69360                     }
69361                   }
69362
69363                   if (description) properties.description = description;
69364
69365                   if (timeSpan) {
69366                     var begin = nodeVal(get1(timeSpan, 'begin'));
69367                     var end = nodeVal(get1(timeSpan, 'end'));
69368                     properties.timespan = {
69369                       begin: begin,
69370                       end: end
69371                     };
69372                   }
69373
69374                   if (timeStamp) {
69375                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
69376                   }
69377
69378                   if (lineStyle) {
69379                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
69380                         color = linestyles[0],
69381                         opacity = linestyles[1],
69382                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
69383                     if (color) properties.stroke = color;
69384                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
69385                     if (!isNaN(width)) properties['stroke-width'] = width;
69386                   }
69387
69388                   if (polyStyle) {
69389                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
69390                         pcolor = polystyles[0],
69391                         popacity = polystyles[1],
69392                         fill = nodeVal(get1(polyStyle, 'fill')),
69393                         outline = nodeVal(get1(polyStyle, 'outline'));
69394                     if (pcolor) properties.fill = pcolor;
69395                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
69396                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
69397                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
69398                   }
69399
69400                   if (extendedData) {
69401                     var datas = get(extendedData, 'Data'),
69402                         simpleDatas = get(extendedData, 'SimpleData');
69403
69404                     for (i = 0; i < datas.length; i++) {
69405                       properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
69406                     }
69407
69408                     for (i = 0; i < simpleDatas.length; i++) {
69409                       properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
69410                     }
69411                   }
69412
69413                   if (visibility) {
69414                     properties.visibility = nodeVal(visibility);
69415                   }
69416
69417                   if (geomsAndTimes.coordTimes.length) {
69418                     properties.coordTimes = geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
69419                   }
69420
69421                   var feature = {
69422                     type: 'Feature',
69423                     geometry: geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
69424                       type: 'GeometryCollection',
69425                       geometries: geomsAndTimes.geoms
69426                     },
69427                     properties: properties
69428                   };
69429                   if (attr(root, 'id')) feature.id = attr(root, 'id');
69430                   return [feature];
69431                 }
69432
69433                 return gj;
69434               },
69435               gpx: function gpx(doc) {
69436                 var i,
69437                     tracks = get(doc, 'trk'),
69438                     routes = get(doc, 'rte'),
69439                     waypoints = get(doc, 'wpt'),
69440                     // a feature collection
69441                 gj = fc(),
69442                     feature;
69443
69444                 for (i = 0; i < tracks.length; i++) {
69445                   feature = getTrack(tracks[i]);
69446                   if (feature) gj.features.push(feature);
69447                 }
69448
69449                 for (i = 0; i < routes.length; i++) {
69450                   feature = getRoute(routes[i]);
69451                   if (feature) gj.features.push(feature);
69452                 }
69453
69454                 for (i = 0; i < waypoints.length; i++) {
69455                   gj.features.push(getPoint(waypoints[i]));
69456                 }
69457
69458                 function getPoints(node, pointname) {
69459                   var pts = get(node, pointname),
69460                       line = [],
69461                       times = [],
69462                       heartRates = [],
69463                       l = pts.length;
69464                   if (l < 2) return {}; // Invalid line in GeoJSON
69465
69466                   for (var i = 0; i < l; i++) {
69467                     var c = coordPair(pts[i]);
69468                     line.push(c.coordinates);
69469                     if (c.time) times.push(c.time);
69470                     if (c.heartRate) heartRates.push(c.heartRate);
69471                   }
69472
69473                   return {
69474                     line: line,
69475                     times: times,
69476                     heartRates: heartRates
69477                   };
69478                 }
69479
69480                 function getTrack(node) {
69481                   var segments = get(node, 'trkseg'),
69482                       track = [],
69483                       times = [],
69484                       heartRates = [],
69485                       line;
69486
69487                   for (var i = 0; i < segments.length; i++) {
69488                     line = getPoints(segments[i], 'trkpt');
69489
69490                     if (line) {
69491                       if (line.line) track.push(line.line);
69492                       if (line.times && line.times.length) times.push(line.times);
69493                       if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
69494                     }
69495                   }
69496
69497                   if (track.length === 0) return;
69498                   var properties = getProperties(node);
69499                   extend(properties, getLineStyle(get1(node, 'extensions')));
69500                   if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
69501                   if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
69502                   return {
69503                     type: 'Feature',
69504                     properties: properties,
69505                     geometry: {
69506                       type: track.length === 1 ? 'LineString' : 'MultiLineString',
69507                       coordinates: track.length === 1 ? track[0] : track
69508                     }
69509                   };
69510                 }
69511
69512                 function getRoute(node) {
69513                   var line = getPoints(node, 'rtept');
69514                   if (!line.line) return;
69515                   var prop = getProperties(node);
69516                   extend(prop, getLineStyle(get1(node, 'extensions')));
69517                   var routeObj = {
69518                     type: 'Feature',
69519                     properties: prop,
69520                     geometry: {
69521                       type: 'LineString',
69522                       coordinates: line.line
69523                     }
69524                   };
69525                   return routeObj;
69526                 }
69527
69528                 function getPoint(node) {
69529                   var prop = getProperties(node);
69530                   extend(prop, getMulti(node, ['sym']));
69531                   return {
69532                     type: 'Feature',
69533                     properties: prop,
69534                     geometry: {
69535                       type: 'Point',
69536                       coordinates: coordPair(node).coordinates
69537                     }
69538                   };
69539                 }
69540
69541                 function getLineStyle(extensions) {
69542                   var style = {};
69543
69544                   if (extensions) {
69545                     var lineStyle = get1(extensions, 'line');
69546
69547                     if (lineStyle) {
69548                       var color = nodeVal(get1(lineStyle, 'color')),
69549                           opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
69550                           width = parseFloat(nodeVal(get1(lineStyle, 'width')));
69551                       if (color) style.stroke = color;
69552                       if (!isNaN(opacity)) style['stroke-opacity'] = opacity; // GPX width is in mm, convert to px with 96 px per inch
69553
69554                       if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
69555                     }
69556                   }
69557
69558                   return style;
69559                 }
69560
69561                 function getProperties(node) {
69562                   var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
69563                       links = get(node, 'link');
69564                   if (links.length) prop.links = [];
69565
69566                   for (var i = 0, link; i < links.length; i++) {
69567                     link = {
69568                       href: attr(links[i], 'href')
69569                     };
69570                     extend(link, getMulti(links[i], ['text', 'type']));
69571                     prop.links.push(link);
69572                   }
69573
69574                   return prop;
69575                 }
69576
69577                 return gj;
69578               }
69579             };
69580             return t;
69581           }();
69582
69583           module.exports = toGeoJSON;
69584         });
69585
69586         var _initialized = false;
69587         var _enabled = false;
69588
69589         var _geojson;
69590
69591         function svgData(projection, context, dispatch) {
69592           var throttledRedraw = throttle(function () {
69593             dispatch.call('change');
69594           }, 1000);
69595
69596           var _showLabels = true;
69597           var detected = utilDetect();
69598           var layer = select(null);
69599
69600           var _vtService;
69601
69602           var _fileList;
69603
69604           var _template;
69605
69606           var _src;
69607
69608           function init() {
69609             if (_initialized) return; // run once
69610
69611             _geojson = {};
69612             _enabled = true;
69613
69614             function over(d3_event) {
69615               d3_event.stopPropagation();
69616               d3_event.preventDefault();
69617               d3_event.dataTransfer.dropEffect = 'copy';
69618             }
69619
69620             context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
69621               d3_event.stopPropagation();
69622               d3_event.preventDefault();
69623               if (!detected.filedrop) return;
69624               drawData.fileList(d3_event.dataTransfer.files);
69625             }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
69626             _initialized = true;
69627           }
69628
69629           function getService() {
69630             if (services.vectorTile && !_vtService) {
69631               _vtService = services.vectorTile;
69632
69633               _vtService.event.on('loadedData', throttledRedraw);
69634             } else if (!services.vectorTile && _vtService) {
69635               _vtService = null;
69636             }
69637
69638             return _vtService;
69639           }
69640
69641           function showLayer() {
69642             layerOn();
69643             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
69644               dispatch.call('change');
69645             });
69646           }
69647
69648           function hideLayer() {
69649             throttledRedraw.cancel();
69650             layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
69651           }
69652
69653           function layerOn() {
69654             layer.style('display', 'block');
69655           }
69656
69657           function layerOff() {
69658             layer.selectAll('.viewfield-group').remove();
69659             layer.style('display', 'none');
69660           } // ensure that all geojson features in a collection have IDs
69661
69662
69663           function ensureIDs(gj) {
69664             if (!gj) return null;
69665
69666             if (gj.type === 'FeatureCollection') {
69667               for (var i = 0; i < gj.features.length; i++) {
69668                 ensureFeatureID(gj.features[i]);
69669               }
69670             } else {
69671               ensureFeatureID(gj);
69672             }
69673
69674             return gj;
69675           } // ensure that each single Feature object has a unique ID
69676
69677
69678           function ensureFeatureID(feature) {
69679             if (!feature) return;
69680             feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
69681             return feature;
69682           } // Prefer an array of Features instead of a FeatureCollection
69683
69684
69685           function getFeatures(gj) {
69686             if (!gj) return [];
69687
69688             if (gj.type === 'FeatureCollection') {
69689               return gj.features;
69690             } else {
69691               return [gj];
69692             }
69693           }
69694
69695           function featureKey(d) {
69696             return d.__featurehash__;
69697           }
69698
69699           function isPolygon(d) {
69700             return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
69701           }
69702
69703           function clipPathID(d) {
69704             return 'ideditor-data-' + d.__featurehash__ + '-clippath';
69705           }
69706
69707           function featureClasses(d) {
69708             return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
69709           }
69710
69711           function drawData(selection) {
69712             var vtService = getService();
69713             var getPath = svgPath(projection).geojson;
69714             var getAreaPath = svgPath(projection, null, true).geojson;
69715             var hasData = drawData.hasData();
69716             layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
69717             layer.exit().remove();
69718             layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
69719             var surface = context.surface();
69720             if (!surface || surface.empty()) return; // not ready to draw yet, starting up
69721             // Gather data
69722
69723             var geoData, polygonData;
69724
69725             if (_template && vtService) {
69726               // fetch data from vector tile service
69727               var sourceID = _template;
69728               vtService.loadTiles(sourceID, _template, projection);
69729               geoData = vtService.data(sourceID, projection);
69730             } else {
69731               geoData = getFeatures(_geojson);
69732             }
69733
69734             geoData = geoData.filter(getPath);
69735             polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
69736
69737             var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
69738             clipPaths.exit().remove();
69739             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
69740             clipPathsEnter.append('path');
69741             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
69742
69743             var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
69744             datagroups = datagroups.enter().append('g').attr('class', function (d) {
69745               return 'datagroup datagroup-' + d;
69746             }).merge(datagroups); // Draw paths
69747
69748             var pathData = {
69749               fill: polygonData,
69750               shadow: geoData,
69751               stroke: geoData
69752             };
69753             var paths = datagroups.selectAll('path').data(function (layer) {
69754               return pathData[layer];
69755             }, featureKey); // exit
69756
69757             paths.exit().remove(); // enter/update
69758
69759             paths = paths.enter().append('path').attr('class', function (d) {
69760               var datagroup = this.parentNode.__data__;
69761               return 'pathdata ' + datagroup + ' ' + featureClasses(d);
69762             }).attr('clip-path', function (d) {
69763               var datagroup = this.parentNode.__data__;
69764               return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
69765             }).merge(paths).attr('d', function (d) {
69766               var datagroup = this.parentNode.__data__;
69767               return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
69768             }); // Draw labels
69769
69770             layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
69771
69772             function drawLabels(selection, textClass, data) {
69773               var labelPath = d3_geoPath(projection);
69774               var labelData = data.filter(function (d) {
69775                 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
69776               });
69777               var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
69778
69779               labels.exit().remove(); // enter/update
69780
69781               labels = labels.enter().append('text').attr('class', function (d) {
69782                 return textClass + ' ' + featureClasses(d);
69783               }).merge(labels).text(function (d) {
69784                 return d.properties.desc || d.properties.name;
69785               }).attr('x', function (d) {
69786                 var centroid = labelPath.centroid(d);
69787                 return centroid[0] + 11;
69788               }).attr('y', function (d) {
69789                 var centroid = labelPath.centroid(d);
69790                 return centroid[1];
69791               });
69792             }
69793           }
69794
69795           function getExtension(fileName) {
69796             if (!fileName) return;
69797             var re = /\.(gpx|kml|(geo)?json)$/i;
69798             var match = fileName.toLowerCase().match(re);
69799             return match && match.length && match[0];
69800           }
69801
69802           function xmlToDom(textdata) {
69803             return new DOMParser().parseFromString(textdata, 'text/xml');
69804           }
69805
69806           drawData.setFile = function (extension, data) {
69807             _template = null;
69808             _fileList = null;
69809             _geojson = null;
69810             _src = null;
69811             var gj;
69812
69813             switch (extension) {
69814               case '.gpx':
69815                 gj = togeojson.gpx(xmlToDom(data));
69816                 break;
69817
69818               case '.kml':
69819                 gj = togeojson.kml(xmlToDom(data));
69820                 break;
69821
69822               case '.geojson':
69823               case '.json':
69824                 gj = JSON.parse(data);
69825                 break;
69826             }
69827
69828             gj = gj || {};
69829
69830             if (Object.keys(gj).length) {
69831               _geojson = ensureIDs(gj);
69832               _src = extension + ' data file';
69833               this.fitZoom();
69834             }
69835
69836             dispatch.call('change');
69837             return this;
69838           };
69839
69840           drawData.showLabels = function (val) {
69841             if (!arguments.length) return _showLabels;
69842             _showLabels = val;
69843             return this;
69844           };
69845
69846           drawData.enabled = function (val) {
69847             if (!arguments.length) return _enabled;
69848             _enabled = val;
69849
69850             if (_enabled) {
69851               showLayer();
69852             } else {
69853               hideLayer();
69854             }
69855
69856             dispatch.call('change');
69857             return this;
69858           };
69859
69860           drawData.hasData = function () {
69861             var gj = _geojson || {};
69862             return !!(_template || Object.keys(gj).length);
69863           };
69864
69865           drawData.template = function (val, src) {
69866             if (!arguments.length) return _template; // test source against OSM imagery blocklists..
69867
69868             var osm = context.connection();
69869
69870             if (osm) {
69871               var blocklists = osm.imageryBlocklists();
69872               var fail = false;
69873               var tested = 0;
69874               var regex;
69875
69876               for (var i = 0; i < blocklists.length; i++) {
69877                 regex = blocklists[i];
69878                 fail = regex.test(val);
69879                 tested++;
69880                 if (fail) break;
69881               } // ensure at least one test was run.
69882
69883
69884               if (!tested) {
69885                 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
69886                 fail = regex.test(val);
69887               }
69888             }
69889
69890             _template = val;
69891             _fileList = null;
69892             _geojson = null; // strip off the querystring/hash from the template,
69893             // it often includes the access token
69894
69895             _src = src || 'vectortile:' + val.split(/[?#]/)[0];
69896             dispatch.call('change');
69897             return this;
69898           };
69899
69900           drawData.geojson = function (gj, src) {
69901             if (!arguments.length) return _geojson;
69902             _template = null;
69903             _fileList = null;
69904             _geojson = null;
69905             _src = null;
69906             gj = gj || {};
69907
69908             if (Object.keys(gj).length) {
69909               _geojson = ensureIDs(gj);
69910               _src = src || 'unknown.geojson';
69911             }
69912
69913             dispatch.call('change');
69914             return this;
69915           };
69916
69917           drawData.fileList = function (fileList) {
69918             if (!arguments.length) return _fileList;
69919             _template = null;
69920             _fileList = fileList;
69921             _geojson = null;
69922             _src = null;
69923             if (!fileList || !fileList.length) return this;
69924             var f = fileList[0];
69925             var extension = getExtension(f.name);
69926             var reader = new FileReader();
69927
69928             reader.onload = function () {
69929               return function (e) {
69930                 drawData.setFile(extension, e.target.result);
69931               };
69932             }();
69933
69934             reader.readAsText(f);
69935             return this;
69936           };
69937
69938           drawData.url = function (url, defaultExtension) {
69939             _template = null;
69940             _fileList = null;
69941             _geojson = null;
69942             _src = null; // strip off any querystring/hash from the url before checking extension
69943
69944             var testUrl = url.split(/[?#]/)[0];
69945             var extension = getExtension(testUrl) || defaultExtension;
69946
69947             if (extension) {
69948               _template = null;
69949               d3_text(url).then(function (data) {
69950                 drawData.setFile(extension, data);
69951               })["catch"](function () {
69952                 /* ignore */
69953               });
69954             } else {
69955               drawData.template(url);
69956             }
69957
69958             return this;
69959           };
69960
69961           drawData.getSrc = function () {
69962             return _src || '';
69963           };
69964
69965           drawData.fitZoom = function () {
69966             var features = getFeatures(_geojson);
69967             if (!features.length) return;
69968             var map = context.map();
69969             var viewport = map.trimmedExtent().polygon();
69970             var coords = features.reduce(function (coords, feature) {
69971               var geom = feature.geometry;
69972               if (!geom) return coords;
69973               var c = geom.coordinates;
69974               /* eslint-disable no-fallthrough */
69975
69976               switch (geom.type) {
69977                 case 'Point':
69978                   c = [c];
69979
69980                 case 'MultiPoint':
69981                 case 'LineString':
69982                   break;
69983
69984                 case 'MultiPolygon':
69985                   c = utilArrayFlatten(c);
69986
69987                 case 'Polygon':
69988                 case 'MultiLineString':
69989                   c = utilArrayFlatten(c);
69990                   break;
69991               }
69992               /* eslint-enable no-fallthrough */
69993
69994
69995               return utilArrayUnion(coords, c);
69996             }, []);
69997
69998             if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
69999               var extent = geoExtent(d3_geoBounds({
70000                 type: 'LineString',
70001                 coordinates: coords
70002               }));
70003               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
70004             }
70005
70006             return this;
70007           };
70008
70009           init();
70010           return drawData;
70011         }
70012
70013         function svgDebug(projection, context) {
70014           function drawDebug(selection) {
70015             var showTile = context.getDebug('tile');
70016             var showCollision = context.getDebug('collision');
70017             var showImagery = context.getDebug('imagery');
70018             var showTouchTargets = context.getDebug('target');
70019             var showDownloaded = context.getDebug('downloaded');
70020             var debugData = [];
70021
70022             if (showTile) {
70023               debugData.push({
70024                 "class": 'red',
70025                 label: 'tile'
70026               });
70027             }
70028
70029             if (showCollision) {
70030               debugData.push({
70031                 "class": 'yellow',
70032                 label: 'collision'
70033               });
70034             }
70035
70036             if (showImagery) {
70037               debugData.push({
70038                 "class": 'orange',
70039                 label: 'imagery'
70040               });
70041             }
70042
70043             if (showTouchTargets) {
70044               debugData.push({
70045                 "class": 'pink',
70046                 label: 'touchTargets'
70047               });
70048             }
70049
70050             if (showDownloaded) {
70051               debugData.push({
70052                 "class": 'purple',
70053                 label: 'downloaded'
70054               });
70055             }
70056
70057             var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
70058             legend.exit().remove();
70059             legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
70060             var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
70061               return d.label;
70062             });
70063             legendItems.exit().remove();
70064             legendItems.enter().append('span').attr('class', function (d) {
70065               return "debug-legend-item ".concat(d["class"]);
70066             }).text(function (d) {
70067               return d.label;
70068             });
70069             var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
70070             layer.exit().remove();
70071             layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
70072
70073             var extent = context.map().extent();
70074             _mainFileFetcher.get('imagery').then(function (d) {
70075               var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
70076               var features = hits.map(function (d) {
70077                 return d.features[d.id];
70078               });
70079               var imagery = layer.selectAll('path.debug-imagery').data(features);
70080               imagery.exit().remove();
70081               imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
70082             })["catch"](function () {
70083               /* ignore */
70084             }); // downloaded
70085
70086             var osm = context.connection();
70087             var dataDownloaded = [];
70088
70089             if (osm && showDownloaded) {
70090               var rtree = osm.caches('get').tile.rtree;
70091               dataDownloaded = rtree.all().map(function (bbox) {
70092                 return {
70093                   type: 'Feature',
70094                   properties: {
70095                     id: bbox.id
70096                   },
70097                   geometry: {
70098                     type: 'Polygon',
70099                     coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
70100                   }
70101                 };
70102               });
70103             }
70104
70105             var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
70106             downloaded.exit().remove();
70107             downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
70108
70109             layer.selectAll('path').attr('d', svgPath(projection).geojson);
70110           } // This looks strange because `enabled` methods on other layers are
70111           // chainable getter/setters, and this one is just a getter.
70112
70113
70114           drawDebug.enabled = function () {
70115             if (!arguments.length) {
70116               return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
70117             } else {
70118               return this;
70119             }
70120           };
70121
70122           return drawDebug;
70123         }
70124
70125         /*
70126             A standalone SVG element that contains only a `defs` sub-element. To be
70127             used once globally, since defs IDs must be unique within a document.
70128         */
70129
70130         function svgDefs(context) {
70131           var _defsSelection = select(null);
70132
70133           var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
70134
70135           function drawDefs(selection) {
70136             _defsSelection = selection.append('defs'); // add markers
70137
70138             _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
70139             // (they can't inherit it from the line they're attached to),
70140             // so we need to manually define markers for each color of tag
70141             // (also, it's slightly nicer if we can control the
70142             // positioning for different tags)
70143
70144
70145             function addSidedMarker(name, color, offset) {
70146               _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);
70147             }
70148
70149             addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
70150             // the water side, so let's color them blue (with a gap) to
70151             // give a stronger indication
70152
70153             addSidedMarker('coastline', '#77dede', 1);
70154             addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
70155             // from the line visually suits that
70156
70157             addSidedMarker('barrier', '#ddd', 1);
70158             addSidedMarker('man_made', '#fff', 0);
70159
70160             _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');
70161
70162             _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
70163
70164
70165             var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
70166             ['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) {
70167               return 'ideditor-pattern-' + d[0];
70168             }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
70169
70170             patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
70171               return 'pattern-color-' + d[0];
70172             });
70173             patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
70174               return context.imagePath('pattern/' + d[1] + '.png');
70175             }); // add clip paths
70176
70177             _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
70178               return 'ideditor-clip-square-' + d;
70179             }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
70180               return d;
70181             }).attr('height', function (d) {
70182               return d;
70183             }); // add symbol spritesheets
70184
70185
70186             addSprites(_spritesheetIds, true);
70187           }
70188
70189           function addSprites(ids, overrideColors) {
70190             _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
70191
70192             var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
70193
70194             spritesheets.enter().append('g').attr('class', function (d) {
70195               return 'spritesheet spritesheet-' + d;
70196             }).each(function (d) {
70197               var url = context.imagePath(d + '.svg');
70198               var node = select(this).node();
70199               svg(url).then(function (svg) {
70200                 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
70201
70202                 if (overrideColors && d !== 'iD-sprite') {
70203                   // allow icon colors to be overridden..
70204                   select(node).selectAll('path').attr('fill', 'currentColor');
70205                 }
70206               })["catch"](function () {
70207                 /* ignore */
70208               });
70209             });
70210             spritesheets.exit().remove();
70211           }
70212
70213           drawDefs.addSprites = addSprites;
70214           return drawDefs;
70215         }
70216
70217         var _layerEnabled = false;
70218
70219         var _qaService;
70220
70221         function svgKeepRight(projection, context, dispatch) {
70222           var throttledRedraw = throttle(function () {
70223             return dispatch.call('change');
70224           }, 1000);
70225
70226           var minZoom = 12;
70227           var touchLayer = select(null);
70228           var drawLayer = select(null);
70229           var layerVisible = false;
70230
70231           function markerPath(selection, klass) {
70232             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');
70233           } // Loosely-coupled keepRight service for fetching issues.
70234
70235
70236           function getService() {
70237             if (services.keepRight && !_qaService) {
70238               _qaService = services.keepRight;
70239
70240               _qaService.on('loaded', throttledRedraw);
70241             } else if (!services.keepRight && _qaService) {
70242               _qaService = null;
70243             }
70244
70245             return _qaService;
70246           } // Show the markers
70247
70248
70249           function editOn() {
70250             if (!layerVisible) {
70251               layerVisible = true;
70252               drawLayer.style('display', 'block');
70253             }
70254           } // Immediately remove the markers and their touch targets
70255
70256
70257           function editOff() {
70258             if (layerVisible) {
70259               layerVisible = false;
70260               drawLayer.style('display', 'none');
70261               drawLayer.selectAll('.qaItem.keepRight').remove();
70262               touchLayer.selectAll('.qaItem.keepRight').remove();
70263             }
70264           } // Enable the layer.  This shows the markers and transitions them to visible.
70265
70266
70267           function layerOn() {
70268             editOn();
70269             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
70270               return dispatch.call('change');
70271             });
70272           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
70273
70274
70275           function layerOff() {
70276             throttledRedraw.cancel();
70277             drawLayer.interrupt();
70278             touchLayer.selectAll('.qaItem.keepRight').remove();
70279             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
70280               editOff();
70281               dispatch.call('change');
70282             });
70283           } // Update the issue markers
70284
70285
70286           function updateMarkers() {
70287             if (!layerVisible || !_layerEnabled) return;
70288             var service = getService();
70289             var selectedID = context.selectedErrorID();
70290             var data = service ? service.getItems(projection) : [];
70291             var getTransform = svgPointTransform(projection); // Draw markers..
70292
70293             var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
70294               return d.id;
70295             }); // exit
70296
70297             markers.exit().remove(); // enter
70298
70299             var markersEnter = markers.enter().append('g').attr('class', function (d) {
70300               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
70301             });
70302             markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
70303             markersEnter.append('path').call(markerPath, 'shadow');
70304             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
70305
70306             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
70307               return d.id === selectedID;
70308             }).attr('transform', getTransform); // Draw targets..
70309
70310             if (touchLayer.empty()) return;
70311             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
70312             var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
70313               return d.id;
70314             }); // exit
70315
70316             targets.exit().remove(); // enter/update
70317
70318             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
70319               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
70320             }).attr('transform', getTransform);
70321
70322             function sortY(a, b) {
70323               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];
70324             }
70325           } // Draw the keepRight layer and schedule loading issues and updating markers.
70326
70327
70328           function drawKeepRight(selection) {
70329             var service = getService();
70330             var surface = context.surface();
70331
70332             if (surface && !surface.empty()) {
70333               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
70334             }
70335
70336             drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
70337             drawLayer.exit().remove();
70338             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
70339
70340             if (_layerEnabled) {
70341               if (service && ~~context.map().zoom() >= minZoom) {
70342                 editOn();
70343                 service.loadIssues(projection);
70344                 updateMarkers();
70345               } else {
70346                 editOff();
70347               }
70348             }
70349           } // Toggles the layer on and off
70350
70351
70352           drawKeepRight.enabled = function (val) {
70353             if (!arguments.length) return _layerEnabled;
70354             _layerEnabled = val;
70355
70356             if (_layerEnabled) {
70357               layerOn();
70358             } else {
70359               layerOff();
70360
70361               if (context.selectedErrorID()) {
70362                 context.enter(modeBrowse(context));
70363               }
70364             }
70365
70366             dispatch.call('change');
70367             return this;
70368           };
70369
70370           drawKeepRight.supported = function () {
70371             return !!getService();
70372           };
70373
70374           return drawKeepRight;
70375         }
70376
70377         function svgGeolocate(projection) {
70378           var layer = select(null);
70379
70380           var _position;
70381
70382           function init() {
70383             if (svgGeolocate.initialized) return; // run once
70384
70385             svgGeolocate.enabled = false;
70386             svgGeolocate.initialized = true;
70387           }
70388
70389           function showLayer() {
70390             layer.style('display', 'block');
70391           }
70392
70393           function hideLayer() {
70394             layer.transition().duration(250).style('opacity', 0);
70395           }
70396
70397           function layerOn() {
70398             layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
70399           }
70400
70401           function layerOff() {
70402             layer.style('display', 'none');
70403           }
70404
70405           function transform(d) {
70406             return svgPointTransform(projection)(d);
70407           }
70408
70409           function accuracy(accuracy, loc) {
70410             // converts accuracy to pixels...
70411             var degreesRadius = geoMetersToLat(accuracy),
70412                 tangentLoc = [loc[0], loc[1] + degreesRadius],
70413                 projectedTangent = projection(tangentLoc),
70414                 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
70415
70416             return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
70417           }
70418
70419           function update() {
70420             var geolocation = {
70421               loc: [_position.coords.longitude, _position.coords.latitude]
70422             };
70423             var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
70424             groups.exit().remove();
70425             var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
70426             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');
70427             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');
70428             groups.merge(pointsEnter).attr('transform', transform);
70429             layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
70430           }
70431
70432           function drawLocation(selection) {
70433             var enabled = svgGeolocate.enabled;
70434             layer = selection.selectAll('.layer-geolocate').data([0]);
70435             layer.exit().remove();
70436             var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
70437             layerEnter.append('g').attr('class', 'geolocations');
70438             layer = layerEnter.merge(layer);
70439
70440             if (enabled) {
70441               update();
70442             } else {
70443               layerOff();
70444             }
70445           }
70446
70447           drawLocation.enabled = function (position, enabled) {
70448             if (!arguments.length) return svgGeolocate.enabled;
70449             _position = position;
70450             svgGeolocate.enabled = enabled;
70451
70452             if (svgGeolocate.enabled) {
70453               showLayer();
70454               layerOn();
70455             } else {
70456               hideLayer();
70457             }
70458
70459             return this;
70460           };
70461
70462           init();
70463           return drawLocation;
70464         }
70465
70466         function svgLabels(projection, context) {
70467           var path = d3_geoPath(projection);
70468           var detected = utilDetect();
70469           var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
70470
70471           var _rdrawn = new RBush();
70472
70473           var _rskipped = new RBush();
70474
70475           var _textWidthCache = {};
70476           var _entitybboxes = {}; // Listed from highest to lowest priority
70477
70478           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]];
70479
70480           function shouldSkipIcon(preset) {
70481             var noIcons = ['building', 'landuse', 'natural'];
70482             return noIcons.some(function (s) {
70483               return preset.id.indexOf(s) >= 0;
70484             });
70485           }
70486
70487           function get(array, prop) {
70488             return function (d, i) {
70489               return array[i][prop];
70490             };
70491           }
70492
70493           function textWidth(text, size, elem) {
70494             var c = _textWidthCache[size];
70495             if (!c) c = _textWidthCache[size] = {};
70496
70497             if (c[text]) {
70498               return c[text];
70499             } else if (elem) {
70500               c[text] = elem.getComputedTextLength();
70501               return c[text];
70502             } else {
70503               var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
70504
70505               if (str === null) {
70506                 return size / 3 * 2 * text.length;
70507               } else {
70508                 return size / 3 * (2 * text.length + str.length);
70509               }
70510             }
70511           }
70512
70513           function drawLinePaths(selection, entities, filter, classes, labels) {
70514             var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
70515
70516             paths.exit().remove(); // enter/update
70517
70518             paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
70519               return 'ideditor-labelpath-' + d.id;
70520             }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
70521           }
70522
70523           function drawLineLabels(selection, entities, filter, classes, labels) {
70524             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
70525
70526             texts.exit().remove(); // enter
70527
70528             texts.enter().append('text').attr('class', function (d, i) {
70529               return classes + ' ' + labels[i].classes + ' ' + d.id;
70530             }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
70531
70532             selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
70533               return '#ideditor-labelpath-' + d.id;
70534             }).text(utilDisplayNameForPath);
70535           }
70536
70537           function drawPointLabels(selection, entities, filter, classes, labels) {
70538             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
70539
70540             texts.exit().remove(); // enter/update
70541
70542             texts.enter().append('text').attr('class', function (d, i) {
70543               return classes + ' ' + labels[i].classes + ' ' + d.id;
70544             }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
70545               textWidth(utilDisplayName(d), labels[i].height, this);
70546             });
70547           }
70548
70549           function drawAreaLabels(selection, entities, filter, classes, labels) {
70550             entities = entities.filter(hasText);
70551             labels = labels.filter(hasText);
70552             drawPointLabels(selection, entities, filter, classes, labels);
70553
70554             function hasText(d, i) {
70555               return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
70556             }
70557           }
70558
70559           function drawAreaIcons(selection, entities, filter, classes, labels) {
70560             var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
70561
70562             icons.exit().remove(); // enter/update
70563
70564             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) {
70565               var preset = _mainPresetIndex.match(d, context.graph());
70566               var picon = preset && preset.icon;
70567
70568               if (!picon) {
70569                 return '';
70570               } else {
70571                 var isMaki = /^maki-/.test(picon);
70572                 return '#' + picon + (isMaki ? '-15' : '');
70573               }
70574             });
70575           }
70576
70577           function drawCollisionBoxes(selection, rtree, which) {
70578             var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
70579             var gj = [];
70580
70581             if (context.getDebug('collision')) {
70582               gj = rtree.all().map(function (d) {
70583                 return {
70584                   type: 'Polygon',
70585                   coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
70586                 };
70587               });
70588             }
70589
70590             var boxes = selection.selectAll('.' + which).data(gj); // exit
70591
70592             boxes.exit().remove(); // enter/update
70593
70594             boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
70595           }
70596
70597           function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
70598             var wireframe = context.surface().classed('fill-wireframe');
70599             var zoom = geoScaleToZoom(projection.scale());
70600             var labelable = [];
70601             var renderNodeAs = {};
70602             var i, j, k, entity, geometry;
70603
70604             for (i = 0; i < labelStack.length; i++) {
70605               labelable.push([]);
70606             }
70607
70608             if (fullRedraw) {
70609               _rdrawn.clear();
70610
70611               _rskipped.clear();
70612
70613               _entitybboxes = {};
70614             } else {
70615               for (i = 0; i < entities.length; i++) {
70616                 entity = entities[i];
70617                 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
70618
70619                 for (j = 0; j < toRemove.length; j++) {
70620                   _rdrawn.remove(toRemove[j]);
70621
70622                   _rskipped.remove(toRemove[j]);
70623                 }
70624               }
70625             } // Loop through all the entities to do some preprocessing
70626
70627
70628             for (i = 0; i < entities.length; i++) {
70629               entity = entities[i];
70630               geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
70631
70632               if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
70633                 var hasDirections = entity.directions(graph, projection).length;
70634                 var markerPadding;
70635
70636                 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
70637                   renderNodeAs[entity.id] = 'point';
70638                   markerPadding = 20; // extra y for marker height
70639                 } else {
70640                   renderNodeAs[entity.id] = 'vertex';
70641                   markerPadding = 0;
70642                 }
70643
70644                 var coord = projection(entity.loc);
70645                 var nodePadding = 10;
70646                 var bbox = {
70647                   minX: coord[0] - nodePadding,
70648                   minY: coord[1] - nodePadding - markerPadding,
70649                   maxX: coord[0] + nodePadding,
70650                   maxY: coord[1] + nodePadding
70651                 };
70652                 doInsert(bbox, entity.id + 'P');
70653               } // From here on, treat vertices like points
70654
70655
70656               if (geometry === 'vertex') {
70657                 geometry = 'point';
70658               } // Determine which entities are label-able
70659
70660
70661               var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
70662               var icon = preset && !shouldSkipIcon(preset) && preset.icon;
70663               if (!icon && !utilDisplayName(entity)) continue;
70664
70665               for (k = 0; k < labelStack.length; k++) {
70666                 var matchGeom = labelStack[k][0];
70667                 var matchKey = labelStack[k][1];
70668                 var matchVal = labelStack[k][2];
70669                 var hasVal = entity.tags[matchKey];
70670
70671                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
70672                   labelable[k].push(entity);
70673                   break;
70674                 }
70675               }
70676             }
70677
70678             var positions = {
70679               point: [],
70680               line: [],
70681               area: []
70682             };
70683             var labelled = {
70684               point: [],
70685               line: [],
70686               area: []
70687             }; // Try and find a valid label for labellable entities
70688
70689             for (k = 0; k < labelable.length; k++) {
70690               var fontSize = labelStack[k][3];
70691
70692               for (i = 0; i < labelable[k].length; i++) {
70693                 entity = labelable[k][i];
70694                 geometry = entity.geometry(graph);
70695                 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
70696                 var name = getName(entity);
70697                 var width = name && textWidth(name, fontSize);
70698                 var p = null;
70699
70700                 if (geometry === 'point' || geometry === 'vertex') {
70701                   // no point or vertex labels in wireframe mode
70702                   // no vertex labels at low zooms (vertices have no icons)
70703                   if (wireframe) continue;
70704                   var renderAs = renderNodeAs[entity.id];
70705                   if (renderAs === 'vertex' && zoom < 17) continue;
70706                   p = getPointLabel(entity, width, fontSize, renderAs);
70707                 } else if (geometry === 'line') {
70708                   p = getLineLabel(entity, width, fontSize);
70709                 } else if (geometry === 'area') {
70710                   p = getAreaLabel(entity, width, fontSize);
70711                 }
70712
70713                 if (p) {
70714                   if (geometry === 'vertex') {
70715                     geometry = 'point';
70716                   } // treat vertex like point
70717
70718
70719                   p.classes = geometry + ' tag-' + labelStack[k][1];
70720                   positions[geometry].push(p);
70721                   labelled[geometry].push(entity);
70722                 }
70723               }
70724             }
70725
70726             function isInterestingVertex(entity) {
70727               var selectedIDs = context.selectedIDs();
70728               return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
70729                 return selectedIDs.indexOf(parent.id) !== -1;
70730               });
70731             }
70732
70733             function getPointLabel(entity, width, height, geometry) {
70734               var y = geometry === 'point' ? -12 : 0;
70735               var pointOffsets = {
70736                 ltr: [15, y, 'start'],
70737                 rtl: [-15, y, 'end']
70738               };
70739               var textDirection = _mainLocalizer.textDirection();
70740               var coord = projection(entity.loc);
70741               var textPadding = 2;
70742               var offset = pointOffsets[textDirection];
70743               var p = {
70744                 height: height,
70745                 width: width,
70746                 x: coord[0] + offset[0],
70747                 y: coord[1] + offset[1],
70748                 textAnchor: offset[2]
70749               }; // insert a collision box for the text label..
70750
70751               var bbox;
70752
70753               if (textDirection === 'rtl') {
70754                 bbox = {
70755                   minX: p.x - width - textPadding,
70756                   minY: p.y - height / 2 - textPadding,
70757                   maxX: p.x + textPadding,
70758                   maxY: p.y + height / 2 + textPadding
70759                 };
70760               } else {
70761                 bbox = {
70762                   minX: p.x - textPadding,
70763                   minY: p.y - height / 2 - textPadding,
70764                   maxX: p.x + width + textPadding,
70765                   maxY: p.y + height / 2 + textPadding
70766                 };
70767               }
70768
70769               if (tryInsert([bbox], entity.id, true)) {
70770                 return p;
70771               }
70772             }
70773
70774             function getLineLabel(entity, width, height) {
70775               var viewport = geoExtent(context.projection.clipExtent()).polygon();
70776               var points = graph.childNodes(entity).map(function (node) {
70777                 return projection(node.loc);
70778               });
70779               var length = geoPathLength(points);
70780               if (length < width + 20) return; // % along the line to attempt to place the label
70781
70782               var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
70783               var padding = 3;
70784
70785               for (var i = 0; i < lineOffsets.length; i++) {
70786                 var offset = lineOffsets[i];
70787                 var middle = offset / 100 * length;
70788                 var start = middle - width / 2;
70789                 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
70790
70791                 var sub = subpath(points, start, start + width);
70792
70793                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
70794                   continue;
70795                 }
70796
70797                 var isReverse = reverse(sub);
70798
70799                 if (isReverse) {
70800                   sub = sub.reverse();
70801                 }
70802
70803                 var bboxes = [];
70804                 var boxsize = (height + 2) / 2;
70805
70806                 for (var j = 0; j < sub.length - 1; j++) {
70807                   var a = sub[j];
70808                   var b = sub[j + 1]; // split up the text into small collision boxes
70809
70810                   var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
70811
70812                   for (var box = 0; box < num; box++) {
70813                     var p = geoVecInterp(a, b, box / num);
70814                     var x0 = p[0] - boxsize - padding;
70815                     var y0 = p[1] - boxsize - padding;
70816                     var x1 = p[0] + boxsize + padding;
70817                     var y1 = p[1] + boxsize + padding;
70818                     bboxes.push({
70819                       minX: Math.min(x0, x1),
70820                       minY: Math.min(y0, y1),
70821                       maxX: Math.max(x0, x1),
70822                       maxY: Math.max(y0, y1)
70823                     });
70824                   }
70825                 }
70826
70827                 if (tryInsert(bboxes, entity.id, false)) {
70828                   // accept this one
70829                   return {
70830                     'font-size': height + 2,
70831                     lineString: lineString(sub),
70832                     startOffset: offset + '%'
70833                   };
70834                 }
70835               }
70836
70837               function reverse(p) {
70838                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
70839                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
70840               }
70841
70842               function lineString(points) {
70843                 return 'M' + points.join('L');
70844               }
70845
70846               function subpath(points, from, to) {
70847                 var sofar = 0;
70848                 var start, end, i0, i1;
70849
70850                 for (var i = 0; i < points.length - 1; i++) {
70851                   var a = points[i];
70852                   var b = points[i + 1];
70853                   var current = geoVecLength(a, b);
70854                   var portion;
70855
70856                   if (!start && sofar + current >= from) {
70857                     portion = (from - sofar) / current;
70858                     start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
70859                     i0 = i + 1;
70860                   }
70861
70862                   if (!end && sofar + current >= to) {
70863                     portion = (to - sofar) / current;
70864                     end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
70865                     i1 = i + 1;
70866                   }
70867
70868                   sofar += current;
70869                 }
70870
70871                 var result = points.slice(i0, i1);
70872                 result.unshift(start);
70873                 result.push(end);
70874                 return result;
70875               }
70876             }
70877
70878             function getAreaLabel(entity, width, height) {
70879               var centroid = path.centroid(entity.asGeoJSON(graph, true));
70880               var extent = entity.extent(graph);
70881               var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
70882               if (isNaN(centroid[0]) || areaWidth < 20) return;
70883               var preset = _mainPresetIndex.match(entity, context.graph());
70884               var picon = preset && preset.icon;
70885               var iconSize = 17;
70886               var padding = 2;
70887               var p = {};
70888
70889               if (picon) {
70890                 // icon and label..
70891                 if (addIcon()) {
70892                   addLabel(iconSize + padding);
70893                   return p;
70894                 }
70895               } else {
70896                 // label only..
70897                 if (addLabel(0)) {
70898                   return p;
70899                 }
70900               }
70901
70902               function addIcon() {
70903                 var iconX = centroid[0] - iconSize / 2;
70904                 var iconY = centroid[1] - iconSize / 2;
70905                 var bbox = {
70906                   minX: iconX,
70907                   minY: iconY,
70908                   maxX: iconX + iconSize,
70909                   maxY: iconY + iconSize
70910                 };
70911
70912                 if (tryInsert([bbox], entity.id + 'I', true)) {
70913                   p.transform = 'translate(' + iconX + ',' + iconY + ')';
70914                   return true;
70915                 }
70916
70917                 return false;
70918               }
70919
70920               function addLabel(yOffset) {
70921                 if (width && areaWidth >= width + 20) {
70922                   var labelX = centroid[0];
70923                   var labelY = centroid[1] + yOffset;
70924                   var bbox = {
70925                     minX: labelX - width / 2 - padding,
70926                     minY: labelY - height / 2 - padding,
70927                     maxX: labelX + width / 2 + padding,
70928                     maxY: labelY + height / 2 + padding
70929                   };
70930
70931                   if (tryInsert([bbox], entity.id, true)) {
70932                     p.x = labelX;
70933                     p.y = labelY;
70934                     p.textAnchor = 'middle';
70935                     p.height = height;
70936                     return true;
70937                   }
70938                 }
70939
70940                 return false;
70941               }
70942             } // force insert a singular bounding box
70943             // singular box only, no array, id better be unique
70944
70945
70946             function doInsert(bbox, id) {
70947               bbox.id = id;
70948               var oldbox = _entitybboxes[id];
70949
70950               if (oldbox) {
70951                 _rdrawn.remove(oldbox);
70952               }
70953
70954               _entitybboxes[id] = bbox;
70955
70956               _rdrawn.insert(bbox);
70957             }
70958
70959             function tryInsert(bboxes, id, saveSkipped) {
70960               var skipped = false;
70961
70962               for (var i = 0; i < bboxes.length; i++) {
70963                 var bbox = bboxes[i];
70964                 bbox.id = id; // Check that label is visible
70965
70966                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
70967                   skipped = true;
70968                   break;
70969                 }
70970
70971                 if (_rdrawn.collides(bbox)) {
70972                   skipped = true;
70973                   break;
70974                 }
70975               }
70976
70977               _entitybboxes[id] = bboxes;
70978
70979               if (skipped) {
70980                 if (saveSkipped) {
70981                   _rskipped.load(bboxes);
70982                 }
70983               } else {
70984                 _rdrawn.load(bboxes);
70985               }
70986
70987               return !skipped;
70988             }
70989
70990             var layer = selection.selectAll('.layer-osm.labels');
70991             layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
70992               return 'labels-group ' + d;
70993             });
70994             var halo = layer.selectAll('.labels-group.halo');
70995             var label = layer.selectAll('.labels-group.label');
70996             var debug = layer.selectAll('.labels-group.debug'); // points
70997
70998             drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
70999             drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
71000
71001             drawLinePaths(layer, labelled.line, filter, '', positions.line);
71002             drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
71003             drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
71004
71005             drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
71006             drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
71007             drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
71008             drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
71009
71010             drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
71011             drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
71012             layer.call(filterLabels);
71013           }
71014
71015           function filterLabels(selection) {
71016             var drawLayer = selection.selectAll('.layer-osm.labels');
71017             var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
71018             layers.selectAll('.nolabel').classed('nolabel', false);
71019             var mouse = context.map().mouse();
71020             var graph = context.graph();
71021             var selectedIDs = context.selectedIDs();
71022             var ids = [];
71023             var pad, bbox; // hide labels near the mouse
71024
71025             if (mouse) {
71026               pad = 20;
71027               bbox = {
71028                 minX: mouse[0] - pad,
71029                 minY: mouse[1] - pad,
71030                 maxX: mouse[0] + pad,
71031                 maxY: mouse[1] + pad
71032               };
71033
71034               var nearMouse = _rdrawn.search(bbox).map(function (entity) {
71035                 return entity.id;
71036               });
71037
71038               ids.push.apply(ids, nearMouse);
71039             } // hide labels on selected nodes (they look weird when dragging / haloed)
71040
71041
71042             for (var i = 0; i < selectedIDs.length; i++) {
71043               var entity = graph.hasEntity(selectedIDs[i]);
71044
71045               if (entity && entity.type === 'node') {
71046                 ids.push(selectedIDs[i]);
71047               }
71048             }
71049
71050             layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
71051
71052             var debug = selection.selectAll('.labels-group.debug');
71053             var gj = [];
71054
71055             if (context.getDebug('collision')) {
71056               gj = bbox ? [{
71057                 type: 'Polygon',
71058                 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
71059               }] : [];
71060             }
71061
71062             var box = debug.selectAll('.debug-mouse').data(gj); // exit
71063
71064             box.exit().remove(); // enter/update
71065
71066             box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
71067           }
71068
71069           var throttleFilterLabels = throttle(filterLabels, 100);
71070
71071           drawLabels.observe = function (selection) {
71072             var listener = function listener() {
71073               throttleFilterLabels(selection);
71074             };
71075
71076             selection.on('mousemove.hidelabels', listener);
71077             context.on('enter.hidelabels', listener);
71078           };
71079
71080           drawLabels.off = function (selection) {
71081             throttleFilterLabels.cancel();
71082             selection.on('mousemove.hidelabels', null);
71083             context.on('enter.hidelabels', null);
71084           };
71085
71086           return drawLabels;
71087         }
71088
71089         var _layerEnabled$1 = false;
71090
71091         var _qaService$1;
71092
71093         function svgImproveOSM(projection, context, dispatch) {
71094           var throttledRedraw = throttle(function () {
71095             return dispatch.call('change');
71096           }, 1000);
71097
71098           var minZoom = 12;
71099           var touchLayer = select(null);
71100           var drawLayer = select(null);
71101           var layerVisible = false;
71102
71103           function markerPath(selection, klass) {
71104             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');
71105           } // Loosely-coupled improveOSM service for fetching issues
71106
71107
71108           function getService() {
71109             if (services.improveOSM && !_qaService$1) {
71110               _qaService$1 = services.improveOSM;
71111
71112               _qaService$1.on('loaded', throttledRedraw);
71113             } else if (!services.improveOSM && _qaService$1) {
71114               _qaService$1 = null;
71115             }
71116
71117             return _qaService$1;
71118           } // Show the markers
71119
71120
71121           function editOn() {
71122             if (!layerVisible) {
71123               layerVisible = true;
71124               drawLayer.style('display', 'block');
71125             }
71126           } // Immediately remove the markers and their touch targets
71127
71128
71129           function editOff() {
71130             if (layerVisible) {
71131               layerVisible = false;
71132               drawLayer.style('display', 'none');
71133               drawLayer.selectAll('.qaItem.improveOSM').remove();
71134               touchLayer.selectAll('.qaItem.improveOSM').remove();
71135             }
71136           } // Enable the layer.  This shows the markers and transitions them to visible.
71137
71138
71139           function layerOn() {
71140             editOn();
71141             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
71142               return dispatch.call('change');
71143             });
71144           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
71145
71146
71147           function layerOff() {
71148             throttledRedraw.cancel();
71149             drawLayer.interrupt();
71150             touchLayer.selectAll('.qaItem.improveOSM').remove();
71151             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
71152               editOff();
71153               dispatch.call('change');
71154             });
71155           } // Update the issue markers
71156
71157
71158           function updateMarkers() {
71159             if (!layerVisible || !_layerEnabled$1) return;
71160             var service = getService();
71161             var selectedID = context.selectedErrorID();
71162             var data = service ? service.getItems(projection) : [];
71163             var getTransform = svgPointTransform(projection); // Draw markers..
71164
71165             var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
71166               return d.id;
71167             }); // exit
71168
71169             markers.exit().remove(); // enter
71170
71171             var markersEnter = markers.enter().append('g').attr('class', function (d) {
71172               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
71173             });
71174             markersEnter.append('polygon').call(markerPath, 'shadow');
71175             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
71176             markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
71177             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
71178               var picon = d.icon;
71179
71180               if (!picon) {
71181                 return '';
71182               } else {
71183                 var isMaki = /^maki-/.test(picon);
71184                 return "#".concat(picon).concat(isMaki ? '-11' : '');
71185               }
71186             }); // update
71187
71188             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
71189               return d.id === selectedID;
71190             }).attr('transform', getTransform); // Draw targets..
71191
71192             if (touchLayer.empty()) return;
71193             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
71194             var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
71195               return d.id;
71196             }); // exit
71197
71198             targets.exit().remove(); // enter/update
71199
71200             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
71201               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
71202             }).attr('transform', getTransform);
71203
71204             function sortY(a, b) {
71205               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
71206             }
71207           } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
71208
71209
71210           function drawImproveOSM(selection) {
71211             var service = getService();
71212             var surface = context.surface();
71213
71214             if (surface && !surface.empty()) {
71215               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
71216             }
71217
71218             drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
71219             drawLayer.exit().remove();
71220             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
71221
71222             if (_layerEnabled$1) {
71223               if (service && ~~context.map().zoom() >= minZoom) {
71224                 editOn();
71225                 service.loadIssues(projection);
71226                 updateMarkers();
71227               } else {
71228                 editOff();
71229               }
71230             }
71231           } // Toggles the layer on and off
71232
71233
71234           drawImproveOSM.enabled = function (val) {
71235             if (!arguments.length) return _layerEnabled$1;
71236             _layerEnabled$1 = val;
71237
71238             if (_layerEnabled$1) {
71239               layerOn();
71240             } else {
71241               layerOff();
71242
71243               if (context.selectedErrorID()) {
71244                 context.enter(modeBrowse(context));
71245               }
71246             }
71247
71248             dispatch.call('change');
71249             return this;
71250           };
71251
71252           drawImproveOSM.supported = function () {
71253             return !!getService();
71254           };
71255
71256           return drawImproveOSM;
71257         }
71258
71259         var _layerEnabled$2 = false;
71260
71261         var _qaService$2;
71262
71263         function svgOsmose(projection, context, dispatch) {
71264           var throttledRedraw = throttle(function () {
71265             return dispatch.call('change');
71266           }, 1000);
71267
71268           var minZoom = 12;
71269           var touchLayer = select(null);
71270           var drawLayer = select(null);
71271           var layerVisible = false;
71272
71273           function markerPath(selection, klass) {
71274             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');
71275           } // Loosely-coupled osmose service for fetching issues
71276
71277
71278           function getService() {
71279             if (services.osmose && !_qaService$2) {
71280               _qaService$2 = services.osmose;
71281
71282               _qaService$2.on('loaded', throttledRedraw);
71283             } else if (!services.osmose && _qaService$2) {
71284               _qaService$2 = null;
71285             }
71286
71287             return _qaService$2;
71288           } // Show the markers
71289
71290
71291           function editOn() {
71292             if (!layerVisible) {
71293               layerVisible = true;
71294               drawLayer.style('display', 'block');
71295             }
71296           } // Immediately remove the markers and their touch targets
71297
71298
71299           function editOff() {
71300             if (layerVisible) {
71301               layerVisible = false;
71302               drawLayer.style('display', 'none');
71303               drawLayer.selectAll('.qaItem.osmose').remove();
71304               touchLayer.selectAll('.qaItem.osmose').remove();
71305             }
71306           } // Enable the layer.  This shows the markers and transitions them to visible.
71307
71308
71309           function layerOn() {
71310             editOn();
71311             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
71312               return dispatch.call('change');
71313             });
71314           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
71315
71316
71317           function layerOff() {
71318             throttledRedraw.cancel();
71319             drawLayer.interrupt();
71320             touchLayer.selectAll('.qaItem.osmose').remove();
71321             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
71322               editOff();
71323               dispatch.call('change');
71324             });
71325           } // Update the issue markers
71326
71327
71328           function updateMarkers() {
71329             if (!layerVisible || !_layerEnabled$2) return;
71330             var service = getService();
71331             var selectedID = context.selectedErrorID();
71332             var data = service ? service.getItems(projection) : [];
71333             var getTransform = svgPointTransform(projection); // Draw markers..
71334
71335             var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
71336               return d.id;
71337             }); // exit
71338
71339             markers.exit().remove(); // enter
71340
71341             var markersEnter = markers.enter().append('g').attr('class', function (d) {
71342               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
71343             });
71344             markersEnter.append('polygon').call(markerPath, 'shadow');
71345             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
71346             markersEnter.append('polygon').attr('fill', function (d) {
71347               return service.getColor(d.item);
71348             }).call(markerPath, 'qaItem-fill');
71349             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
71350               var picon = d.icon;
71351
71352               if (!picon) {
71353                 return '';
71354               } else {
71355                 var isMaki = /^maki-/.test(picon);
71356                 return "#".concat(picon).concat(isMaki ? '-11' : '');
71357               }
71358             }); // update
71359
71360             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
71361               return d.id === selectedID;
71362             }).attr('transform', getTransform); // Draw targets..
71363
71364             if (touchLayer.empty()) return;
71365             var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
71366             var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
71367               return d.id;
71368             }); // exit
71369
71370             targets.exit().remove(); // enter/update
71371
71372             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
71373               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
71374             }).attr('transform', getTransform);
71375
71376             function sortY(a, b) {
71377               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
71378             }
71379           } // Draw the Osmose layer and schedule loading issues and updating markers.
71380
71381
71382           function drawOsmose(selection) {
71383             var service = getService();
71384             var surface = context.surface();
71385
71386             if (surface && !surface.empty()) {
71387               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
71388             }
71389
71390             drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
71391             drawLayer.exit().remove();
71392             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
71393
71394             if (_layerEnabled$2) {
71395               if (service && ~~context.map().zoom() >= minZoom) {
71396                 editOn();
71397                 service.loadIssues(projection);
71398                 updateMarkers();
71399               } else {
71400                 editOff();
71401               }
71402             }
71403           } // Toggles the layer on and off
71404
71405
71406           drawOsmose.enabled = function (val) {
71407             if (!arguments.length) return _layerEnabled$2;
71408             _layerEnabled$2 = val;
71409
71410             if (_layerEnabled$2) {
71411               // Strings supplied by Osmose fetched before showing layer for first time
71412               // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
71413               // Also, If layer is toggled quickly multiple requests are sent
71414               getService().loadStrings().then(layerOn)["catch"](function (err) {
71415                 console.log(err); // eslint-disable-line no-console
71416               });
71417             } else {
71418               layerOff();
71419
71420               if (context.selectedErrorID()) {
71421                 context.enter(modeBrowse(context));
71422               }
71423             }
71424
71425             dispatch.call('change');
71426             return this;
71427           };
71428
71429           drawOsmose.supported = function () {
71430             return !!getService();
71431           };
71432
71433           return drawOsmose;
71434         }
71435
71436         function svgStreetside(projection, context, dispatch) {
71437           var throttledRedraw = throttle(function () {
71438             dispatch.call('change');
71439           }, 1000);
71440
71441           var minZoom = 14;
71442           var minMarkerZoom = 16;
71443           var minViewfieldZoom = 18;
71444           var layer = select(null);
71445           var _viewerYaw = 0;
71446           var _selectedSequence = null;
71447
71448           var _streetside;
71449           /**
71450            * init().
71451            */
71452
71453
71454           function init() {
71455             if (svgStreetside.initialized) return; // run once
71456
71457             svgStreetside.enabled = false;
71458             svgStreetside.initialized = true;
71459           }
71460           /**
71461            * getService().
71462            */
71463
71464
71465           function getService() {
71466             if (services.streetside && !_streetside) {
71467               _streetside = services.streetside;
71468
71469               _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
71470             } else if (!services.streetside && _streetside) {
71471               _streetside = null;
71472             }
71473
71474             return _streetside;
71475           }
71476           /**
71477            * showLayer().
71478            */
71479
71480
71481           function showLayer() {
71482             var service = getService();
71483             if (!service) return;
71484             editOn();
71485             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
71486               dispatch.call('change');
71487             });
71488           }
71489           /**
71490            * hideLayer().
71491            */
71492
71493
71494           function hideLayer() {
71495             throttledRedraw.cancel();
71496             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
71497           }
71498           /**
71499            * editOn().
71500            */
71501
71502
71503           function editOn() {
71504             layer.style('display', 'block');
71505           }
71506           /**
71507            * editOff().
71508            */
71509
71510
71511           function editOff() {
71512             layer.selectAll('.viewfield-group').remove();
71513             layer.style('display', 'none');
71514           }
71515           /**
71516            * click() Handles 'bubble' point click event.
71517            */
71518
71519
71520           function click(d3_event, d) {
71521             var service = getService();
71522             if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
71523
71524             if (d.sequenceKey !== _selectedSequence) {
71525               _viewerYaw = 0; // reset
71526             }
71527
71528             _selectedSequence = d.sequenceKey;
71529             service.ensureViewerLoaded(context).then(function () {
71530               service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
71531             });
71532             context.map().centerEase(d.loc);
71533           }
71534           /**
71535            * mouseover().
71536            */
71537
71538
71539           function mouseover(d3_event, d) {
71540             var service = getService();
71541             if (service) service.setStyles(context, d);
71542           }
71543           /**
71544            * mouseout().
71545            */
71546
71547
71548           function mouseout() {
71549             var service = getService();
71550             if (service) service.setStyles(context, null);
71551           }
71552           /**
71553            * transform().
71554            */
71555
71556
71557           function transform(d) {
71558             var t = svgPointTransform(projection)(d);
71559             var rot = d.ca + _viewerYaw;
71560
71561             if (rot) {
71562               t += ' rotate(' + Math.floor(rot) + ',0,0)';
71563             }
71564
71565             return t;
71566           }
71567
71568           function viewerChanged() {
71569             var service = getService();
71570             if (!service) return;
71571             var viewer = service.viewer();
71572             if (!viewer) return; // update viewfield rotation
71573
71574             _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
71575             // e.g. during drags or easing.
71576
71577             if (context.map().isTransformed()) return;
71578             layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
71579           }
71580
71581           function filterBubbles(bubbles) {
71582             var fromDate = context.photos().fromDate();
71583             var toDate = context.photos().toDate();
71584             var usernames = context.photos().usernames();
71585
71586             if (fromDate) {
71587               var fromTimestamp = new Date(fromDate).getTime();
71588               bubbles = bubbles.filter(function (bubble) {
71589                 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
71590               });
71591             }
71592
71593             if (toDate) {
71594               var toTimestamp = new Date(toDate).getTime();
71595               bubbles = bubbles.filter(function (bubble) {
71596                 return new Date(bubble.captured_at).getTime() <= toTimestamp;
71597               });
71598             }
71599
71600             if (usernames) {
71601               bubbles = bubbles.filter(function (bubble) {
71602                 return usernames.indexOf(bubble.captured_by) !== -1;
71603               });
71604             }
71605
71606             return bubbles;
71607           }
71608
71609           function filterSequences(sequences) {
71610             var fromDate = context.photos().fromDate();
71611             var toDate = context.photos().toDate();
71612             var usernames = context.photos().usernames();
71613
71614             if (fromDate) {
71615               var fromTimestamp = new Date(fromDate).getTime();
71616               sequences = sequences.filter(function (sequences) {
71617                 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
71618               });
71619             }
71620
71621             if (toDate) {
71622               var toTimestamp = new Date(toDate).getTime();
71623               sequences = sequences.filter(function (sequences) {
71624                 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
71625               });
71626             }
71627
71628             if (usernames) {
71629               sequences = sequences.filter(function (sequences) {
71630                 return usernames.indexOf(sequences.properties.captured_by) !== -1;
71631               });
71632             }
71633
71634             return sequences;
71635           }
71636           /**
71637            * update().
71638            */
71639
71640
71641           function update() {
71642             var viewer = context.container().select('.photoviewer');
71643             var selected = viewer.empty() ? undefined : viewer.datum();
71644             var z = ~~context.map().zoom();
71645             var showMarkers = z >= minMarkerZoom;
71646             var showViewfields = z >= minViewfieldZoom;
71647             var service = getService();
71648             var sequences = [];
71649             var bubbles = [];
71650
71651             if (context.photos().showsPanoramic()) {
71652               sequences = service ? service.sequences(projection) : [];
71653               bubbles = service && showMarkers ? service.bubbles(projection) : [];
71654               sequences = filterSequences(sequences);
71655               bubbles = filterBubbles(bubbles);
71656             }
71657
71658             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
71659               return d.properties.key;
71660             }); // exit
71661
71662             traces.exit().remove(); // enter/update
71663
71664             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
71665             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
71666               // force reenter once bubbles are attached to a sequence
71667               return d.key + (d.sequenceKey ? 'v1' : 'v0');
71668             }); // exit
71669
71670             groups.exit().remove(); // enter
71671
71672             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
71673             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
71674
71675             var markers = groups.merge(groupsEnter).sort(function (a, b) {
71676               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
71677             }).attr('transform', transform).select('.viewfield-scale');
71678             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
71679             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
71680             viewfields.exit().remove(); // viewfields may or may not be drawn...
71681             // but if they are, draw below the circles
71682
71683             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
71684
71685             function viewfieldPath() {
71686               var d = this.parentNode.__data__;
71687
71688               if (d.pano) {
71689                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
71690               } else {
71691                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
71692               }
71693             }
71694           }
71695           /**
71696            * drawImages()
71697            * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
71698            * 'svgStreetside()' is called from index.js
71699            */
71700
71701
71702           function drawImages(selection) {
71703             var enabled = svgStreetside.enabled;
71704             var service = getService();
71705             layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
71706             layer.exit().remove();
71707             var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
71708             layerEnter.append('g').attr('class', 'sequences');
71709             layerEnter.append('g').attr('class', 'markers');
71710             layer = layerEnter.merge(layer);
71711
71712             if (enabled) {
71713               if (service && ~~context.map().zoom() >= minZoom) {
71714                 editOn();
71715                 update();
71716                 service.loadBubbles(projection);
71717               } else {
71718                 editOff();
71719               }
71720             }
71721           }
71722           /**
71723            * drawImages.enabled().
71724            */
71725
71726
71727           drawImages.enabled = function (_) {
71728             if (!arguments.length) return svgStreetside.enabled;
71729             svgStreetside.enabled = _;
71730
71731             if (svgStreetside.enabled) {
71732               showLayer();
71733               context.photos().on('change.streetside', update);
71734             } else {
71735               hideLayer();
71736               context.photos().on('change.streetside', null);
71737             }
71738
71739             dispatch.call('change');
71740             return this;
71741           };
71742           /**
71743            * drawImages.supported().
71744            */
71745
71746
71747           drawImages.supported = function () {
71748             return !!getService();
71749           };
71750
71751           init();
71752           return drawImages;
71753         }
71754
71755         function svgMapillaryImages(projection, context, dispatch) {
71756           var throttledRedraw = throttle(function () {
71757             dispatch.call('change');
71758           }, 1000);
71759
71760           var minZoom = 12;
71761           var minMarkerZoom = 16;
71762           var minViewfieldZoom = 18;
71763           var layer = select(null);
71764
71765           var _mapillary;
71766
71767           var viewerCompassAngle;
71768
71769           function init() {
71770             if (svgMapillaryImages.initialized) return; // run once
71771
71772             svgMapillaryImages.enabled = false;
71773             svgMapillaryImages.initialized = true;
71774           }
71775
71776           function getService() {
71777             if (services.mapillary && !_mapillary) {
71778               _mapillary = services.mapillary;
71779
71780               _mapillary.event.on('loadedImages', throttledRedraw);
71781             } else if (!services.mapillary && _mapillary) {
71782               _mapillary = null;
71783             }
71784
71785             return _mapillary;
71786           }
71787
71788           function showLayer() {
71789             var service = getService();
71790             if (!service) return;
71791             editOn();
71792             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
71793               dispatch.call('change');
71794             });
71795           }
71796
71797           function hideLayer() {
71798             throttledRedraw.cancel();
71799             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
71800           }
71801
71802           function editOn() {
71803             layer.style('display', 'block');
71804           }
71805
71806           function editOff() {
71807             layer.selectAll('.viewfield-group').remove();
71808             layer.style('display', 'none');
71809           }
71810
71811           function click(d3_event, d) {
71812             var service = getService();
71813             if (!service) return;
71814             service.ensureViewerLoaded(context).then(function () {
71815               service.selectImage(context, d.key).showViewer(context);
71816             });
71817             context.map().centerEase(d.loc);
71818           }
71819
71820           function mouseover(d) {
71821             var service = getService();
71822             if (service) service.setStyles(context, d);
71823           }
71824
71825           function mouseout() {
71826             var service = getService();
71827             if (service) service.setStyles(context, null);
71828           }
71829
71830           function transform(d) {
71831             var t = svgPointTransform(projection)(d);
71832
71833             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
71834               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
71835             } else if (d.ca) {
71836               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
71837             }
71838
71839             return t;
71840           }
71841
71842           function filterImages(images) {
71843             var showsPano = context.photos().showsPanoramic();
71844             var showsFlat = context.photos().showsFlat();
71845             var fromDate = context.photos().fromDate();
71846             var toDate = context.photos().toDate();
71847             var usernames = context.photos().usernames();
71848
71849             if (!showsPano || !showsFlat) {
71850               images = images.filter(function (image) {
71851                 if (image.pano) return showsPano;
71852                 return showsFlat;
71853               });
71854             }
71855
71856             if (fromDate) {
71857               var fromTimestamp = new Date(fromDate).getTime();
71858               images = images.filter(function (image) {
71859                 return new Date(image.captured_at).getTime() >= fromTimestamp;
71860               });
71861             }
71862
71863             if (toDate) {
71864               var toTimestamp = new Date(toDate).getTime();
71865               images = images.filter(function (image) {
71866                 return new Date(image.captured_at).getTime() <= toTimestamp;
71867               });
71868             }
71869
71870             if (usernames) {
71871               images = images.filter(function (image) {
71872                 return usernames.indexOf(image.captured_by) !== -1;
71873               });
71874             }
71875
71876             return images;
71877           }
71878
71879           function filterSequences(sequences, service) {
71880             var showsPano = context.photos().showsPanoramic();
71881             var showsFlat = context.photos().showsFlat();
71882             var fromDate = context.photos().fromDate();
71883             var toDate = context.photos().toDate();
71884             var usernames = context.photos().usernames();
71885
71886             if (!showsPano || !showsFlat) {
71887               sequences = sequences.filter(function (sequence) {
71888                 if (sequence.properties.hasOwnProperty('pano')) {
71889                   if (sequence.properties.pano) return showsPano;
71890                   return showsFlat;
71891                 } else {
71892                   // if the sequence doesn't specify pano or not, search its images
71893                   var cProps = sequence.properties.coordinateProperties;
71894
71895                   if (cProps && cProps.image_keys && cProps.image_keys.length > 0) {
71896                     for (var index in cProps.image_keys) {
71897                       var imageKey = cProps.image_keys[index];
71898                       var image = service.cachedImage(imageKey);
71899
71900                       if (image && image.hasOwnProperty('pano')) {
71901                         if (image.pano) return showsPano;
71902                         return showsFlat;
71903                       }
71904                     }
71905                   }
71906                 }
71907
71908                 return false;
71909               });
71910             }
71911
71912             if (fromDate) {
71913               var fromTimestamp = new Date(fromDate).getTime();
71914               sequences = sequences.filter(function (sequence) {
71915                 return new Date(sequence.properties.captured_at).getTime() >= fromTimestamp;
71916               });
71917             }
71918
71919             if (toDate) {
71920               var toTimestamp = new Date(toDate).getTime();
71921               sequences = sequences.filter(function (sequence) {
71922                 return new Date(sequence.properties.captured_at).getTime() <= toTimestamp;
71923               });
71924             }
71925
71926             if (usernames) {
71927               sequences = sequences.filter(function (sequence) {
71928                 return usernames.indexOf(sequence.properties.username) !== -1;
71929               });
71930             }
71931
71932             return sequences;
71933           }
71934
71935           function update() {
71936             var z = ~~context.map().zoom();
71937             var showMarkers = z >= minMarkerZoom;
71938             var showViewfields = z >= minViewfieldZoom;
71939             var service = getService();
71940             var sequences = service ? service.sequences(projection) : [];
71941             var images = service && showMarkers ? service.images(projection) : [];
71942             images = filterImages(images);
71943             sequences = filterSequences(sequences, service);
71944             service.filterViewer(context);
71945             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
71946               return d.properties.key;
71947             }); // exit
71948
71949             traces.exit().remove(); // enter/update
71950
71951             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
71952             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
71953               return d.key;
71954             }); // exit
71955
71956             groups.exit().remove(); // enter
71957
71958             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
71959             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
71960
71961             var markers = groups.merge(groupsEnter).sort(function (a, b) {
71962               return b.loc[1] - a.loc[1]; // sort Y
71963             }).attr('transform', transform).select('.viewfield-scale');
71964             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
71965             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
71966             viewfields.exit().remove();
71967             viewfields.enter() // viewfields may or may not be drawn...
71968             .insert('path', 'circle') // but if they are, draw below the circles
71969             .attr('class', 'viewfield').classed('pano', function () {
71970               return this.parentNode.__data__.pano;
71971             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
71972
71973             function viewfieldPath() {
71974               var d = this.parentNode.__data__;
71975
71976               if (d.pano) {
71977                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
71978               } else {
71979                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
71980               }
71981             }
71982           }
71983
71984           function drawImages(selection) {
71985             var enabled = svgMapillaryImages.enabled;
71986             var service = getService();
71987             layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
71988             layer.exit().remove();
71989             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
71990             layerEnter.append('g').attr('class', 'sequences');
71991             layerEnter.append('g').attr('class', 'markers');
71992             layer = layerEnter.merge(layer);
71993
71994             if (enabled) {
71995               if (service && ~~context.map().zoom() >= minZoom) {
71996                 editOn();
71997                 update();
71998                 service.loadImages(projection);
71999               } else {
72000                 editOff();
72001               }
72002             }
72003           }
72004
72005           drawImages.enabled = function (_) {
72006             if (!arguments.length) return svgMapillaryImages.enabled;
72007             svgMapillaryImages.enabled = _;
72008
72009             if (svgMapillaryImages.enabled) {
72010               showLayer();
72011               context.photos().on('change.mapillary_images', update);
72012             } else {
72013               hideLayer();
72014               context.photos().on('change.mapillary_images', null);
72015             }
72016
72017             dispatch.call('change');
72018             return this;
72019           };
72020
72021           drawImages.supported = function () {
72022             return !!getService();
72023           };
72024
72025           init();
72026           return drawImages;
72027         }
72028
72029         function svgMapillaryPosition(projection, context) {
72030           var throttledRedraw = throttle(function () {
72031             update();
72032           }, 1000);
72033
72034           var minZoom = 12;
72035           var minViewfieldZoom = 18;
72036           var layer = select(null);
72037
72038           var _mapillary;
72039
72040           var viewerCompassAngle;
72041
72042           function init() {
72043             if (svgMapillaryPosition.initialized) return; // run once
72044
72045             svgMapillaryPosition.initialized = true;
72046           }
72047
72048           function getService() {
72049             if (services.mapillary && !_mapillary) {
72050               _mapillary = services.mapillary;
72051
72052               _mapillary.event.on('nodeChanged', throttledRedraw);
72053
72054               _mapillary.event.on('bearingChanged', function (e) {
72055                 viewerCompassAngle = e;
72056                 if (context.map().isTransformed()) return;
72057                 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
72058                   return d.pano;
72059                 }).attr('transform', transform);
72060               });
72061             } else if (!services.mapillary && _mapillary) {
72062               _mapillary = null;
72063             }
72064
72065             return _mapillary;
72066           }
72067
72068           function editOn() {
72069             layer.style('display', 'block');
72070           }
72071
72072           function editOff() {
72073             layer.selectAll('.viewfield-group').remove();
72074             layer.style('display', 'none');
72075           }
72076
72077           function transform(d) {
72078             var t = svgPointTransform(projection)(d);
72079
72080             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
72081               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
72082             } else if (d.ca) {
72083               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72084             }
72085
72086             return t;
72087           }
72088
72089           function update() {
72090             var z = ~~context.map().zoom();
72091             var showViewfields = z >= minViewfieldZoom;
72092             var service = getService();
72093             var node = service && service.getActiveImage();
72094             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(node ? [node] : [], function (d) {
72095               return d.key;
72096             }); // exit
72097
72098             groups.exit().remove(); // enter
72099
72100             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
72101             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72102
72103             var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
72104             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72105             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72106             viewfields.exit().remove();
72107             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').classed('pano', function () {
72108               return this.parentNode.__data__.pano;
72109             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72110
72111             function viewfieldPath() {
72112               var d = this.parentNode.__data__;
72113
72114               if (d.pano) {
72115                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72116               } else {
72117                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72118               }
72119             }
72120           }
72121
72122           function drawImages(selection) {
72123             var service = getService();
72124             layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
72125             layer.exit().remove();
72126             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
72127             layerEnter.append('g').attr('class', 'markers');
72128             layer = layerEnter.merge(layer);
72129
72130             if (service && ~~context.map().zoom() >= minZoom) {
72131               editOn();
72132               update();
72133             } else {
72134               editOff();
72135             }
72136           }
72137
72138           drawImages.enabled = function () {
72139             update();
72140             return this;
72141           };
72142
72143           drawImages.supported = function () {
72144             return !!getService();
72145           };
72146
72147           init();
72148           return drawImages;
72149         }
72150
72151         function svgMapillarySigns(projection, context, dispatch) {
72152           var throttledRedraw = throttle(function () {
72153             dispatch.call('change');
72154           }, 1000);
72155
72156           var minZoom = 12;
72157           var layer = select(null);
72158
72159           var _mapillary;
72160
72161           function init() {
72162             if (svgMapillarySigns.initialized) return; // run once
72163
72164             svgMapillarySigns.enabled = false;
72165             svgMapillarySigns.initialized = true;
72166           }
72167
72168           function getService() {
72169             if (services.mapillary && !_mapillary) {
72170               _mapillary = services.mapillary;
72171
72172               _mapillary.event.on('loadedSigns', throttledRedraw);
72173             } else if (!services.mapillary && _mapillary) {
72174               _mapillary = null;
72175             }
72176
72177             return _mapillary;
72178           }
72179
72180           function showLayer() {
72181             var service = getService();
72182             if (!service) return;
72183             service.loadSignResources(context);
72184             editOn();
72185           }
72186
72187           function hideLayer() {
72188             throttledRedraw.cancel();
72189             editOff();
72190           }
72191
72192           function editOn() {
72193             layer.style('display', 'block');
72194           }
72195
72196           function editOff() {
72197             layer.selectAll('.icon-sign').remove();
72198             layer.style('display', 'none');
72199           }
72200
72201           function click(d3_event, d) {
72202             var service = getService();
72203             if (!service) return;
72204             context.map().centerEase(d.loc);
72205             var selectedImageKey = service.getSelectedImageKey();
72206             var imageKey;
72207             var highlightedDetection; // Pick one of the images the sign was detected in,
72208             // preference given to an image already selected.
72209
72210             d.detections.forEach(function (detection) {
72211               if (!imageKey || selectedImageKey === detection.image_key) {
72212                 imageKey = detection.image_key;
72213                 highlightedDetection = detection;
72214               }
72215             });
72216
72217             if (imageKey === selectedImageKey) {
72218               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
72219             } else {
72220               service.ensureViewerLoaded(context).then(function () {
72221                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
72222               });
72223             }
72224           }
72225
72226           function filterData(detectedFeatures) {
72227             var service = getService();
72228             var fromDate = context.photos().fromDate();
72229             var toDate = context.photos().toDate();
72230             var usernames = context.photos().usernames();
72231
72232             if (fromDate) {
72233               var fromTimestamp = new Date(fromDate).getTime();
72234               detectedFeatures = detectedFeatures.filter(function (feature) {
72235                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
72236               });
72237             }
72238
72239             if (toDate) {
72240               var toTimestamp = new Date(toDate).getTime();
72241               detectedFeatures = detectedFeatures.filter(function (feature) {
72242                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
72243               });
72244             }
72245
72246             if (usernames && service) {
72247               detectedFeatures = detectedFeatures.filter(function (feature) {
72248                 return feature.detections.some(function (detection) {
72249                   var imageKey = detection.image_key;
72250                   var image = service.cachedImage(imageKey);
72251                   return image && usernames.indexOf(image.captured_by) !== -1;
72252                 });
72253               });
72254             }
72255
72256             return detectedFeatures;
72257           }
72258
72259           function update() {
72260             var service = getService();
72261             var data = service ? service.signs(projection) : [];
72262             data = filterData(data);
72263             var selectedImageKey = service.getSelectedImageKey();
72264             var transform = svgPointTransform(projection);
72265             var signs = layer.selectAll('.icon-sign').data(data, function (d) {
72266               return d.key;
72267             }); // exit
72268
72269             signs.exit().remove(); // enter
72270
72271             var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
72272             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
72273               return '#' + d.value;
72274             });
72275             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
72276
72277             signs.merge(enter).attr('transform', transform).classed('currentView', function (d) {
72278               return d.detections.some(function (detection) {
72279                 return detection.image_key === selectedImageKey;
72280               });
72281             }).sort(function (a, b) {
72282               var aSelected = a.detections.some(function (detection) {
72283                 return detection.image_key === selectedImageKey;
72284               });
72285               var bSelected = b.detections.some(function (detection) {
72286                 return detection.image_key === selectedImageKey;
72287               });
72288
72289               if (aSelected === bSelected) {
72290                 return b.loc[1] - a.loc[1]; // sort Y
72291               } else if (aSelected) {
72292                 return 1;
72293               }
72294
72295               return -1;
72296             });
72297           }
72298
72299           function drawSigns(selection) {
72300             var enabled = svgMapillarySigns.enabled;
72301             var service = getService();
72302             layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
72303             layer.exit().remove();
72304             layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
72305
72306             if (enabled) {
72307               if (service && ~~context.map().zoom() >= minZoom) {
72308                 editOn();
72309                 update();
72310                 service.loadSigns(projection);
72311                 service.showSignDetections(true);
72312               } else {
72313                 editOff();
72314               }
72315             } else if (service) {
72316               service.showSignDetections(false);
72317             }
72318           }
72319
72320           drawSigns.enabled = function (_) {
72321             if (!arguments.length) return svgMapillarySigns.enabled;
72322             svgMapillarySigns.enabled = _;
72323
72324             if (svgMapillarySigns.enabled) {
72325               showLayer();
72326               context.photos().on('change.mapillary_signs', update);
72327             } else {
72328               hideLayer();
72329               context.photos().on('change.mapillary_signs', null);
72330             }
72331
72332             dispatch.call('change');
72333             return this;
72334           };
72335
72336           drawSigns.supported = function () {
72337             return !!getService();
72338           };
72339
72340           init();
72341           return drawSigns;
72342         }
72343
72344         function svgMapillaryMapFeatures(projection, context, dispatch) {
72345           var throttledRedraw = throttle(function () {
72346             dispatch.call('change');
72347           }, 1000);
72348
72349           var minZoom = 12;
72350           var layer = select(null);
72351
72352           var _mapillary;
72353
72354           function init() {
72355             if (svgMapillaryMapFeatures.initialized) return; // run once
72356
72357             svgMapillaryMapFeatures.enabled = false;
72358             svgMapillaryMapFeatures.initialized = true;
72359           }
72360
72361           function getService() {
72362             if (services.mapillary && !_mapillary) {
72363               _mapillary = services.mapillary;
72364
72365               _mapillary.event.on('loadedMapFeatures', throttledRedraw);
72366             } else if (!services.mapillary && _mapillary) {
72367               _mapillary = null;
72368             }
72369
72370             return _mapillary;
72371           }
72372
72373           function showLayer() {
72374             var service = getService();
72375             if (!service) return;
72376             service.loadObjectResources(context);
72377             editOn();
72378           }
72379
72380           function hideLayer() {
72381             throttledRedraw.cancel();
72382             editOff();
72383           }
72384
72385           function editOn() {
72386             layer.style('display', 'block');
72387           }
72388
72389           function editOff() {
72390             layer.selectAll('.icon-map-feature').remove();
72391             layer.style('display', 'none');
72392           }
72393
72394           function click(d3_event, d) {
72395             var service = getService();
72396             if (!service) return;
72397             context.map().centerEase(d.loc);
72398             var selectedImageKey = service.getSelectedImageKey();
72399             var imageKey;
72400             var highlightedDetection; // Pick one of the images the map feature was detected in,
72401             // preference given to an image already selected.
72402
72403             d.detections.forEach(function (detection) {
72404               if (!imageKey || selectedImageKey === detection.image_key) {
72405                 imageKey = detection.image_key;
72406                 highlightedDetection = detection;
72407               }
72408             });
72409
72410             if (imageKey === selectedImageKey) {
72411               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
72412             } else {
72413               service.ensureViewerLoaded(context).then(function () {
72414                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
72415               });
72416             }
72417           }
72418
72419           function filterData(detectedFeatures) {
72420             var service = getService();
72421             var fromDate = context.photos().fromDate();
72422             var toDate = context.photos().toDate();
72423             var usernames = context.photos().usernames();
72424
72425             if (fromDate) {
72426               var fromTimestamp = new Date(fromDate).getTime();
72427               detectedFeatures = detectedFeatures.filter(function (feature) {
72428                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
72429               });
72430             }
72431
72432             if (toDate) {
72433               var toTimestamp = new Date(toDate).getTime();
72434               detectedFeatures = detectedFeatures.filter(function (feature) {
72435                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
72436               });
72437             }
72438
72439             if (usernames && service) {
72440               detectedFeatures = detectedFeatures.filter(function (feature) {
72441                 return feature.detections.some(function (detection) {
72442                   var imageKey = detection.image_key;
72443                   var image = service.cachedImage(imageKey);
72444                   return image && usernames.indexOf(image.captured_by) !== -1;
72445                 });
72446               });
72447             }
72448
72449             return detectedFeatures;
72450           }
72451
72452           function update() {
72453             var service = getService();
72454             var data = service ? service.mapFeatures(projection) : [];
72455             data = filterData(data);
72456             var selectedImageKey = service && service.getSelectedImageKey();
72457             var transform = svgPointTransform(projection);
72458             var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
72459               return d.key;
72460             }); // exit
72461
72462             mapFeatures.exit().remove(); // enter
72463
72464             var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
72465             enter.append('title').text(function (d) {
72466               var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
72467               return _t('mapillary_map_features.' + id);
72468             });
72469             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
72470               if (d.value === 'object--billboard') {
72471                 // no billboard icon right now, so use the advertisement icon
72472                 return '#object--sign--advertisement';
72473               }
72474
72475               return '#' + d.value;
72476             });
72477             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
72478
72479             mapFeatures.merge(enter).attr('transform', transform).classed('currentView', function (d) {
72480               return d.detections.some(function (detection) {
72481                 return detection.image_key === selectedImageKey;
72482               });
72483             }).sort(function (a, b) {
72484               var aSelected = a.detections.some(function (detection) {
72485                 return detection.image_key === selectedImageKey;
72486               });
72487               var bSelected = b.detections.some(function (detection) {
72488                 return detection.image_key === selectedImageKey;
72489               });
72490
72491               if (aSelected === bSelected) {
72492                 return b.loc[1] - a.loc[1]; // sort Y
72493               } else if (aSelected) {
72494                 return 1;
72495               }
72496
72497               return -1;
72498             });
72499           }
72500
72501           function drawMapFeatures(selection) {
72502             var enabled = svgMapillaryMapFeatures.enabled;
72503             var service = getService();
72504             layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
72505             layer.exit().remove();
72506             layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
72507
72508             if (enabled) {
72509               if (service && ~~context.map().zoom() >= minZoom) {
72510                 editOn();
72511                 update();
72512                 service.loadMapFeatures(projection);
72513                 service.showFeatureDetections(true);
72514               } else {
72515                 editOff();
72516               }
72517             } else if (service) {
72518               service.showFeatureDetections(false);
72519             }
72520           }
72521
72522           drawMapFeatures.enabled = function (_) {
72523             if (!arguments.length) return svgMapillaryMapFeatures.enabled;
72524             svgMapillaryMapFeatures.enabled = _;
72525
72526             if (svgMapillaryMapFeatures.enabled) {
72527               showLayer();
72528               context.photos().on('change.mapillary_map_features', update);
72529             } else {
72530               hideLayer();
72531               context.photos().on('change.mapillary_map_features', null);
72532             }
72533
72534             dispatch.call('change');
72535             return this;
72536           };
72537
72538           drawMapFeatures.supported = function () {
72539             return !!getService();
72540           };
72541
72542           init();
72543           return drawMapFeatures;
72544         }
72545
72546         function svgOpenstreetcamImages(projection, context, dispatch) {
72547           var throttledRedraw = throttle(function () {
72548             dispatch.call('change');
72549           }, 1000);
72550
72551           var minZoom = 12;
72552           var minMarkerZoom = 16;
72553           var minViewfieldZoom = 18;
72554           var layer = select(null);
72555
72556           var _openstreetcam;
72557
72558           function init() {
72559             if (svgOpenstreetcamImages.initialized) return; // run once
72560
72561             svgOpenstreetcamImages.enabled = false;
72562             svgOpenstreetcamImages.initialized = true;
72563           }
72564
72565           function getService() {
72566             if (services.openstreetcam && !_openstreetcam) {
72567               _openstreetcam = services.openstreetcam;
72568
72569               _openstreetcam.event.on('loadedImages', throttledRedraw);
72570             } else if (!services.openstreetcam && _openstreetcam) {
72571               _openstreetcam = null;
72572             }
72573
72574             return _openstreetcam;
72575           }
72576
72577           function showLayer() {
72578             var service = getService();
72579             if (!service) return;
72580             editOn();
72581             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72582               dispatch.call('change');
72583             });
72584           }
72585
72586           function hideLayer() {
72587             throttledRedraw.cancel();
72588             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72589           }
72590
72591           function editOn() {
72592             layer.style('display', 'block');
72593           }
72594
72595           function editOff() {
72596             layer.selectAll('.viewfield-group').remove();
72597             layer.style('display', 'none');
72598           }
72599
72600           function click(d3_event, d) {
72601             var service = getService();
72602             if (!service) return;
72603             service.ensureViewerLoaded(context).then(function () {
72604               service.selectImage(context, d.key).showViewer(context);
72605             });
72606             context.map().centerEase(d.loc);
72607           }
72608
72609           function mouseover(d3_event, d) {
72610             var service = getService();
72611             if (service) service.setStyles(context, d);
72612           }
72613
72614           function mouseout() {
72615             var service = getService();
72616             if (service) service.setStyles(context, null);
72617           }
72618
72619           function transform(d) {
72620             var t = svgPointTransform(projection)(d);
72621
72622             if (d.ca) {
72623               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72624             }
72625
72626             return t;
72627           }
72628
72629           function filterImages(images) {
72630             var fromDate = context.photos().fromDate();
72631             var toDate = context.photos().toDate();
72632             var usernames = context.photos().usernames();
72633
72634             if (fromDate) {
72635               var fromTimestamp = new Date(fromDate).getTime();
72636               images = images.filter(function (item) {
72637                 return new Date(item.captured_at).getTime() >= fromTimestamp;
72638               });
72639             }
72640
72641             if (toDate) {
72642               var toTimestamp = new Date(toDate).getTime();
72643               images = images.filter(function (item) {
72644                 return new Date(item.captured_at).getTime() <= toTimestamp;
72645               });
72646             }
72647
72648             if (usernames) {
72649               images = images.filter(function (item) {
72650                 return usernames.indexOf(item.captured_by) !== -1;
72651               });
72652             }
72653
72654             return images;
72655           }
72656
72657           function filterSequences(sequences) {
72658             var fromDate = context.photos().fromDate();
72659             var toDate = context.photos().toDate();
72660             var usernames = context.photos().usernames();
72661
72662             if (fromDate) {
72663               var fromTimestamp = new Date(fromDate).getTime();
72664               sequences = sequences.filter(function (image) {
72665                 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
72666               });
72667             }
72668
72669             if (toDate) {
72670               var toTimestamp = new Date(toDate).getTime();
72671               sequences = sequences.filter(function (image) {
72672                 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
72673               });
72674             }
72675
72676             if (usernames) {
72677               sequences = sequences.filter(function (image) {
72678                 return usernames.indexOf(image.properties.captured_by) !== -1;
72679               });
72680             }
72681
72682             return sequences;
72683           }
72684
72685           function update() {
72686             var viewer = context.container().select('.photoviewer');
72687             var selected = viewer.empty() ? undefined : viewer.datum();
72688             var z = ~~context.map().zoom();
72689             var showMarkers = z >= minMarkerZoom;
72690             var showViewfields = z >= minViewfieldZoom;
72691             var service = getService();
72692             var sequences = [];
72693             var images = [];
72694
72695             if (context.photos().showsFlat()) {
72696               sequences = service ? service.sequences(projection) : [];
72697               images = service && showMarkers ? service.images(projection) : [];
72698               sequences = filterSequences(sequences);
72699               images = filterImages(images);
72700             }
72701
72702             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72703               return d.properties.key;
72704             }); // exit
72705
72706             traces.exit().remove(); // enter/update
72707
72708             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72709             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
72710               return d.key;
72711             }); // exit
72712
72713             groups.exit().remove(); // enter
72714
72715             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72716             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72717
72718             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72719               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
72720             }).attr('transform', transform).select('.viewfield-scale');
72721             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72722             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72723             viewfields.exit().remove();
72724             viewfields.enter() // viewfields may or may not be drawn...
72725             .insert('path', 'circle') // but if they are, draw below the circles
72726             .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');
72727           }
72728
72729           function drawImages(selection) {
72730             var enabled = svgOpenstreetcamImages.enabled,
72731                 service = getService();
72732             layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
72733             layer.exit().remove();
72734             var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
72735             layerEnter.append('g').attr('class', 'sequences');
72736             layerEnter.append('g').attr('class', 'markers');
72737             layer = layerEnter.merge(layer);
72738
72739             if (enabled) {
72740               if (service && ~~context.map().zoom() >= minZoom) {
72741                 editOn();
72742                 update();
72743                 service.loadImages(projection);
72744               } else {
72745                 editOff();
72746               }
72747             }
72748           }
72749
72750           drawImages.enabled = function (_) {
72751             if (!arguments.length) return svgOpenstreetcamImages.enabled;
72752             svgOpenstreetcamImages.enabled = _;
72753
72754             if (svgOpenstreetcamImages.enabled) {
72755               showLayer();
72756               context.photos().on('change.openstreetcam_images', update);
72757             } else {
72758               hideLayer();
72759               context.photos().on('change.openstreetcam_images', null);
72760             }
72761
72762             dispatch.call('change');
72763             return this;
72764           };
72765
72766           drawImages.supported = function () {
72767             return !!getService();
72768           };
72769
72770           init();
72771           return drawImages;
72772         }
72773
72774         function svgOsm(projection, context, dispatch) {
72775           var enabled = true;
72776
72777           function drawOsm(selection) {
72778             selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
72779               return 'layer-osm ' + d;
72780             });
72781             selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
72782               return 'points-group ' + d;
72783             });
72784           }
72785
72786           function showLayer() {
72787             var layer = context.surface().selectAll('.data-layer.osm');
72788             layer.interrupt();
72789             layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72790               dispatch.call('change');
72791             });
72792           }
72793
72794           function hideLayer() {
72795             var layer = context.surface().selectAll('.data-layer.osm');
72796             layer.interrupt();
72797             layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72798               layer.classed('disabled', true);
72799               dispatch.call('change');
72800             });
72801           }
72802
72803           drawOsm.enabled = function (val) {
72804             if (!arguments.length) return enabled;
72805             enabled = val;
72806
72807             if (enabled) {
72808               showLayer();
72809             } else {
72810               hideLayer();
72811             }
72812
72813             dispatch.call('change');
72814             return this;
72815           };
72816
72817           return drawOsm;
72818         }
72819
72820         var _notesEnabled = false;
72821
72822         var _osmService;
72823
72824         function svgNotes(projection, context, dispatch$1) {
72825           if (!dispatch$1) {
72826             dispatch$1 = dispatch('change');
72827           }
72828
72829           var throttledRedraw = throttle(function () {
72830             dispatch$1.call('change');
72831           }, 1000);
72832
72833           var minZoom = 12;
72834           var touchLayer = select(null);
72835           var drawLayer = select(null);
72836           var _notesVisible = false;
72837
72838           function markerPath(selection, klass) {
72839             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');
72840           } // Loosely-coupled osm service for fetching notes.
72841
72842
72843           function getService() {
72844             if (services.osm && !_osmService) {
72845               _osmService = services.osm;
72846
72847               _osmService.on('loadedNotes', throttledRedraw);
72848             } else if (!services.osm && _osmService) {
72849               _osmService = null;
72850             }
72851
72852             return _osmService;
72853           } // Show the notes
72854
72855
72856           function editOn() {
72857             if (!_notesVisible) {
72858               _notesVisible = true;
72859               drawLayer.style('display', 'block');
72860             }
72861           } // Immediately remove the notes and their touch targets
72862
72863
72864           function editOff() {
72865             if (_notesVisible) {
72866               _notesVisible = false;
72867               drawLayer.style('display', 'none');
72868               drawLayer.selectAll('.note').remove();
72869               touchLayer.selectAll('.note').remove();
72870             }
72871           } // Enable the layer.  This shows the notes and transitions them to visible.
72872
72873
72874           function layerOn() {
72875             editOn();
72876             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72877               dispatch$1.call('change');
72878             });
72879           } // Disable the layer.  This transitions the layer invisible and then hides the notes.
72880
72881
72882           function layerOff() {
72883             throttledRedraw.cancel();
72884             drawLayer.interrupt();
72885             touchLayer.selectAll('.note').remove();
72886             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72887               editOff();
72888               dispatch$1.call('change');
72889             });
72890           } // Update the note markers
72891
72892
72893           function updateMarkers() {
72894             if (!_notesVisible || !_notesEnabled) return;
72895             var service = getService();
72896             var selectedID = context.selectedNoteID();
72897             var data = service ? service.notes(projection) : [];
72898             var getTransform = svgPointTransform(projection); // Draw markers..
72899
72900             var notes = drawLayer.selectAll('.note').data(data, function (d) {
72901               return d.status + d.id;
72902             }); // exit
72903
72904             notes.exit().remove(); // enter
72905
72906             var notesEnter = notes.enter().append('g').attr('class', function (d) {
72907               return 'note note-' + d.id + ' ' + d.status;
72908             }).classed('new', function (d) {
72909               return d.id < 0;
72910             });
72911             notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
72912             notesEnter.append('path').call(markerPath, 'shadow');
72913             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');
72914             notesEnter.selectAll('.icon-annotation').data(function (d) {
72915               return [d];
72916             }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
72917               return '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
72918             }); // update
72919
72920             notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
72921               var mode = context.mode();
72922               var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
72923
72924               return !isMoving && d.id === selectedID;
72925             }).attr('transform', getTransform); // Draw targets..
72926
72927             if (touchLayer.empty()) return;
72928             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
72929             var targets = touchLayer.selectAll('.note').data(data, function (d) {
72930               return d.id;
72931             }); // exit
72932
72933             targets.exit().remove(); // enter/update
72934
72935             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
72936               var newClass = d.id < 0 ? 'new' : '';
72937               return 'note target note-' + d.id + ' ' + fillClass + newClass;
72938             }).attr('transform', getTransform);
72939
72940             function sortY(a, b) {
72941               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72942             }
72943           } // Draw the notes layer and schedule loading notes and updating markers.
72944
72945
72946           function drawNotes(selection) {
72947             var service = getService();
72948             var surface = context.surface();
72949
72950             if (surface && !surface.empty()) {
72951               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72952             }
72953
72954             drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
72955             drawLayer.exit().remove();
72956             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
72957
72958             if (_notesEnabled) {
72959               if (service && ~~context.map().zoom() >= minZoom) {
72960                 editOn();
72961                 service.loadNotes(projection);
72962                 updateMarkers();
72963               } else {
72964                 editOff();
72965               }
72966             }
72967           } // Toggles the layer on and off
72968
72969
72970           drawNotes.enabled = function (val) {
72971             if (!arguments.length) return _notesEnabled;
72972             _notesEnabled = val;
72973
72974             if (_notesEnabled) {
72975               layerOn();
72976             } else {
72977               layerOff();
72978
72979               if (context.selectedNoteID()) {
72980                 context.enter(modeBrowse(context));
72981               }
72982             }
72983
72984             dispatch$1.call('change');
72985             return this;
72986           };
72987
72988           return drawNotes;
72989         }
72990
72991         function svgTouch() {
72992           function drawTouch(selection) {
72993             selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
72994               return 'layer-touch ' + d;
72995             });
72996           }
72997
72998           return drawTouch;
72999         }
73000
73001         function refresh(selection, node) {
73002           var cr = node.getBoundingClientRect();
73003           var prop = [cr.width, cr.height];
73004           selection.property('__dimensions__', prop);
73005           return prop;
73006         }
73007
73008         function utilGetDimensions(selection, force) {
73009           if (!selection || selection.empty()) {
73010             return [0, 0];
73011           }
73012
73013           var node = selection.node(),
73014               cached = selection.property('__dimensions__');
73015           return !cached || force ? refresh(selection, node) : cached;
73016         }
73017         function utilSetDimensions(selection, dimensions) {
73018           if (!selection || selection.empty()) {
73019             return selection;
73020           }
73021
73022           var node = selection.node();
73023
73024           if (dimensions === null) {
73025             refresh(selection, node);
73026             return selection;
73027           }
73028
73029           return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
73030         }
73031
73032         function svgLayers(projection, context) {
73033           var dispatch$1 = dispatch('change');
73034           var svg = select(null);
73035           var _layers = [{
73036             id: 'osm',
73037             layer: svgOsm(projection, context, dispatch$1)
73038           }, {
73039             id: 'notes',
73040             layer: svgNotes(projection, context, dispatch$1)
73041           }, {
73042             id: 'data',
73043             layer: svgData(projection, context, dispatch$1)
73044           }, {
73045             id: 'keepRight',
73046             layer: svgKeepRight(projection, context, dispatch$1)
73047           }, {
73048             id: 'improveOSM',
73049             layer: svgImproveOSM(projection, context, dispatch$1)
73050           }, {
73051             id: 'osmose',
73052             layer: svgOsmose(projection, context, dispatch$1)
73053           }, {
73054             id: 'streetside',
73055             layer: svgStreetside(projection, context, dispatch$1)
73056           }, {
73057             id: 'mapillary',
73058             layer: svgMapillaryImages(projection, context, dispatch$1)
73059           }, {
73060             id: 'mapillary-position',
73061             layer: svgMapillaryPosition(projection, context)
73062           }, {
73063             id: 'mapillary-map-features',
73064             layer: svgMapillaryMapFeatures(projection, context, dispatch$1)
73065           }, {
73066             id: 'mapillary-signs',
73067             layer: svgMapillarySigns(projection, context, dispatch$1)
73068           }, {
73069             id: 'openstreetcam',
73070             layer: svgOpenstreetcamImages(projection, context, dispatch$1)
73071           }, {
73072             id: 'debug',
73073             layer: svgDebug(projection, context)
73074           }, {
73075             id: 'geolocate',
73076             layer: svgGeolocate(projection)
73077           }, {
73078             id: 'touch',
73079             layer: svgTouch()
73080           }];
73081
73082           function drawLayers(selection) {
73083             svg = selection.selectAll('.surface').data([0]);
73084             svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
73085             var defs = svg.selectAll('.surface-defs').data([0]);
73086             defs.enter().append('defs').attr('class', 'surface-defs');
73087             var groups = svg.selectAll('.data-layer').data(_layers);
73088             groups.exit().remove();
73089             groups.enter().append('g').attr('class', function (d) {
73090               return 'data-layer ' + d.id;
73091             }).merge(groups).each(function (d) {
73092               select(this).call(d.layer);
73093             });
73094           }
73095
73096           drawLayers.all = function () {
73097             return _layers;
73098           };
73099
73100           drawLayers.layer = function (id) {
73101             var obj = _layers.find(function (o) {
73102               return o.id === id;
73103             });
73104
73105             return obj && obj.layer;
73106           };
73107
73108           drawLayers.only = function (what) {
73109             var arr = [].concat(what);
73110
73111             var all = _layers.map(function (layer) {
73112               return layer.id;
73113             });
73114
73115             return drawLayers.remove(utilArrayDifference(all, arr));
73116           };
73117
73118           drawLayers.remove = function (what) {
73119             var arr = [].concat(what);
73120             arr.forEach(function (id) {
73121               _layers = _layers.filter(function (o) {
73122                 return o.id !== id;
73123               });
73124             });
73125             dispatch$1.call('change');
73126             return this;
73127           };
73128
73129           drawLayers.add = function (what) {
73130             var arr = [].concat(what);
73131             arr.forEach(function (obj) {
73132               if ('id' in obj && 'layer' in obj) {
73133                 _layers.push(obj);
73134               }
73135             });
73136             dispatch$1.call('change');
73137             return this;
73138           };
73139
73140           drawLayers.dimensions = function (val) {
73141             if (!arguments.length) return utilGetDimensions(svg);
73142             utilSetDimensions(svg, val);
73143             return this;
73144           };
73145
73146           return utilRebind(drawLayers, dispatch$1, 'on');
73147         }
73148
73149         function svgLines(projection, context) {
73150           var detected = utilDetect();
73151           var highway_stack = {
73152             motorway: 0,
73153             motorway_link: 1,
73154             trunk: 2,
73155             trunk_link: 3,
73156             primary: 4,
73157             primary_link: 5,
73158             secondary: 6,
73159             tertiary: 7,
73160             unclassified: 8,
73161             residential: 9,
73162             service: 10,
73163             footway: 11
73164           };
73165
73166           function drawTargets(selection, graph, entities, filter) {
73167             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73168             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
73169             var getPath = svgPath(projection).geojson;
73170             var activeID = context.activeID();
73171             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
73172
73173             var data = {
73174               targets: [],
73175               nopes: []
73176             };
73177             entities.forEach(function (way) {
73178               var features = svgSegmentWay(way, graph, activeID);
73179               data.targets.push.apply(data.targets, features.passive);
73180               data.nopes.push.apply(data.nopes, features.active);
73181             }); // Targets allow hover and vertex snapping
73182
73183             var targetData = data.targets.filter(getPath);
73184             var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
73185               return filter(d.properties.entity);
73186             }).data(targetData, function key(d) {
73187               return d.id;
73188             }); // exit
73189
73190             targets.exit().remove();
73191
73192             var segmentWasEdited = function segmentWasEdited(d) {
73193               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
73194
73195               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
73196                 return false;
73197               }
73198
73199               return d.properties.nodes.some(function (n) {
73200                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
73201               });
73202             }; // enter/update
73203
73204
73205             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
73206               return 'way line target target-allowed ' + targetClass + d.id;
73207             }).classed('segment-edited', segmentWasEdited); // NOPE
73208
73209             var nopeData = data.nopes.filter(getPath);
73210             var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
73211               return filter(d.properties.entity);
73212             }).data(nopeData, function key(d) {
73213               return d.id;
73214             }); // exit
73215
73216             nopes.exit().remove(); // enter/update
73217
73218             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
73219               return 'way line target target-nope ' + nopeClass + d.id;
73220             }).classed('segment-edited', segmentWasEdited);
73221           }
73222
73223           function drawLines(selection, graph, entities, filter) {
73224             var base = context.history().base();
73225
73226             function waystack(a, b) {
73227               var selected = context.selectedIDs();
73228               var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
73229               var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
73230
73231               if (a.tags.highway) {
73232                 scoreA -= highway_stack[a.tags.highway];
73233               }
73234
73235               if (b.tags.highway) {
73236                 scoreB -= highway_stack[b.tags.highway];
73237               }
73238
73239               return scoreA - scoreB;
73240             }
73241
73242             function drawLineGroup(selection, klass, isSelected) {
73243               // Note: Don't add `.selected` class in draw modes
73244               var mode = context.mode();
73245               var isDrawing = mode && /^draw/.test(mode.id);
73246               var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
73247               var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
73248               lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
73249               // works because osmEntity.key is defined to include the entity v attribute.
73250
73251               lines.enter().append('path').attr('class', function (d) {
73252                 var prefix = 'way line'; // if this line isn't styled by its own tags
73253
73254                 if (!d.hasInterestingTags()) {
73255                   var parentRelations = graph.parentRelations(d);
73256                   var parentMultipolygons = parentRelations.filter(function (relation) {
73257                     return relation.isMultipolygon();
73258                   }); // and if it's a member of at least one multipolygon relation
73259
73260                   if (parentMultipolygons.length > 0 && // and only multipolygon relations
73261                   parentRelations.length === parentMultipolygons.length) {
73262                     // then fudge the classes to style this as an area edge
73263                     prefix = 'relation area';
73264                   }
73265                 }
73266
73267                 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
73268                 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
73269               }).classed('added', function (d) {
73270                 return !base.entities[d.id];
73271               }).classed('geometry-edited', function (d) {
73272                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
73273               }).classed('retagged', function (d) {
73274                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
73275               }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
73276               return selection;
73277             }
73278
73279             function getPathData(isSelected) {
73280               return function () {
73281                 var layer = this.parentNode.__data__;
73282                 var data = pathdata[layer] || [];
73283                 return data.filter(function (d) {
73284                   if (isSelected) return context.selectedIDs().indexOf(d.id) !== -1;else return context.selectedIDs().indexOf(d.id) === -1;
73285                 });
73286               };
73287             }
73288
73289             function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
73290               var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
73291               markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
73292               var markers = markergroup.selectAll('path').filter(filter).data(function data() {
73293                 return groupdata[this.parentNode.__data__] || [];
73294               }, function key(d) {
73295                 return [d.id, d.index];
73296               });
73297               markers.exit().remove();
73298               markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
73299                 return d.d;
73300               });
73301
73302               if (detected.ie) {
73303                 markers.each(function () {
73304                   this.parentNode.insertBefore(this, this);
73305                 });
73306               }
73307             }
73308
73309             var getPath = svgPath(projection, graph);
73310             var ways = [];
73311             var onewaydata = {};
73312             var sideddata = {};
73313             var oldMultiPolygonOuters = {};
73314
73315             for (var i = 0; i < entities.length; i++) {
73316               var entity = entities[i];
73317               var outer = osmOldMultipolygonOuterMember(entity, graph);
73318
73319               if (outer) {
73320                 ways.push(entity.mergeTags(outer.tags));
73321                 oldMultiPolygonOuters[outer.id] = true;
73322               } else if (entity.geometry(graph) === 'line') {
73323                 ways.push(entity);
73324               }
73325             }
73326
73327             ways = ways.filter(getPath);
73328             var pathdata = utilArrayGroupBy(ways, function (way) {
73329               return way.layer();
73330             });
73331             Object.keys(pathdata).forEach(function (k) {
73332               var v = pathdata[k];
73333               var onewayArr = v.filter(function (d) {
73334                 return d.isOneWay();
73335               });
73336               var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
73337                 return entity.tags.oneway === '-1';
73338               }, function bothDirections(entity) {
73339                 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
73340               });
73341               onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
73342               var sidedArr = v.filter(function (d) {
73343                 return d.isSided();
73344               });
73345               var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
73346                 return false;
73347               }, function bothDirections() {
73348                 return false;
73349               });
73350               sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
73351             });
73352             var covered = selection.selectAll('.layer-osm.covered'); // under areas
73353
73354             var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
73355
73356             var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
73357
73358             [covered, uncovered].forEach(function (selection) {
73359               var range$1 = selection === covered ? range(-10, 0) : range(0, 11);
73360               var layergroup = selection.selectAll('g.layergroup').data(range$1);
73361               layergroup = layergroup.enter().append('g').attr('class', function (d) {
73362                 return 'layergroup layer' + String(d);
73363               }).merge(layergroup);
73364               layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
73365                 return 'linegroup line-' + d;
73366               });
73367               layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
73368               layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
73369               layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
73370               layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
73371               layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
73372               layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
73373               addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
73374               addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
73375                 var category = graph.entity(d.id).sidednessIdentifier();
73376                 return 'url(#ideditor-sided-marker-' + category + ')';
73377               });
73378             }); // Draw touch targets..
73379
73380             touchLayer.call(drawTargets, graph, ways, filter);
73381           }
73382
73383           return drawLines;
73384         }
73385
73386         function svgMidpoints(projection, context) {
73387           var targetRadius = 8;
73388
73389           function drawTargets(selection, graph, entities, filter) {
73390             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73391             var getTransform = svgPointTransform(projection).geojson;
73392             var data = entities.map(function (midpoint) {
73393               return {
73394                 type: 'Feature',
73395                 id: midpoint.id,
73396                 properties: {
73397                   target: true,
73398                   entity: midpoint
73399                 },
73400                 geometry: {
73401                   type: 'Point',
73402                   coordinates: midpoint.loc
73403                 }
73404               };
73405             });
73406             var targets = selection.selectAll('.midpoint.target').filter(function (d) {
73407               return filter(d.properties.entity);
73408             }).data(data, function key(d) {
73409               return d.id;
73410             }); // exit
73411
73412             targets.exit().remove(); // enter/update
73413
73414             targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
73415               return 'node midpoint target ' + fillClass + d.id;
73416             }).attr('transform', getTransform);
73417           }
73418
73419           function drawMidpoints(selection, graph, entities, filter, extent) {
73420             var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
73421             var touchLayer = selection.selectAll('.layer-touch.points');
73422             var mode = context.mode();
73423
73424             if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
73425               drawLayer.selectAll('.midpoint').remove();
73426               touchLayer.selectAll('.midpoint.target').remove();
73427               return;
73428             }
73429
73430             var poly = extent.polygon();
73431             var midpoints = {};
73432
73433             for (var i = 0; i < entities.length; i++) {
73434               var entity = entities[i];
73435               if (entity.type !== 'way') continue;
73436               if (!filter(entity)) continue;
73437               if (context.selectedIDs().indexOf(entity.id) < 0) continue;
73438               var nodes = graph.childNodes(entity);
73439
73440               for (var j = 0; j < nodes.length - 1; j++) {
73441                 var a = nodes[j];
73442                 var b = nodes[j + 1];
73443                 var id = [a.id, b.id].sort().join('-');
73444
73445                 if (midpoints[id]) {
73446                   midpoints[id].parents.push(entity);
73447                 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
73448                   var point = geoVecInterp(a.loc, b.loc, 0.5);
73449                   var loc = null;
73450
73451                   if (extent.intersects(point)) {
73452                     loc = point;
73453                   } else {
73454                     for (var k = 0; k < 4; k++) {
73455                       point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
73456
73457                       if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
73458                         loc = point;
73459                         break;
73460                       }
73461                     }
73462                   }
73463
73464                   if (loc) {
73465                     midpoints[id] = {
73466                       type: 'midpoint',
73467                       id: id,
73468                       loc: loc,
73469                       edge: [a.id, b.id],
73470                       parents: [entity]
73471                     };
73472                   }
73473                 }
73474               }
73475             }
73476
73477             function midpointFilter(d) {
73478               if (midpoints[d.id]) return true;
73479
73480               for (var i = 0; i < d.parents.length; i++) {
73481                 if (filter(d.parents[i])) {
73482                   return true;
73483                 }
73484               }
73485
73486               return false;
73487             }
73488
73489             var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
73490               return d.id;
73491             });
73492             groups.exit().remove();
73493             var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
73494             enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
73495             enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
73496             groups = groups.merge(enter).attr('transform', function (d) {
73497               var translate = svgPointTransform(projection);
73498               var a = graph.entity(d.edge[0]);
73499               var b = graph.entity(d.edge[1]);
73500               var angle = geoAngle(a, b, projection) * (180 / Math.PI);
73501               return translate(d) + ' rotate(' + angle + ')';
73502             }).call(svgTagClasses().tags(function (d) {
73503               return d.parents[0].tags;
73504             })); // Propagate data bindings.
73505
73506             groups.select('polygon.shadow');
73507             groups.select('polygon.fill'); // Draw touch targets..
73508
73509             touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
73510           }
73511
73512           return drawMidpoints;
73513         }
73514
73515         function svgPoints(projection, context) {
73516           function markerPath(selection, klass) {
73517             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');
73518           }
73519
73520           function sortY(a, b) {
73521             return b.loc[1] - a.loc[1];
73522           } // Avoid exit/enter if we're just moving stuff around.
73523           // The node will get a new version but we only need to run the update selection.
73524
73525
73526           function fastEntityKey(d) {
73527             var mode = context.mode();
73528             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
73529             return isMoving ? d.id : osmEntity.key(d);
73530           }
73531
73532           function drawTargets(selection, graph, entities, filter) {
73533             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73534             var getTransform = svgPointTransform(projection).geojson;
73535             var activeID = context.activeID();
73536             var data = [];
73537             entities.forEach(function (node) {
73538               if (activeID === node.id) return; // draw no target on the activeID
73539
73540               data.push({
73541                 type: 'Feature',
73542                 id: node.id,
73543                 properties: {
73544                   target: true,
73545                   entity: node
73546                 },
73547                 geometry: node.asGeoJSON()
73548               });
73549             });
73550             var targets = selection.selectAll('.point.target').filter(function (d) {
73551               return filter(d.properties.entity);
73552             }).data(data, function key(d) {
73553               return d.id;
73554             }); // exit
73555
73556             targets.exit().remove(); // enter/update
73557
73558             targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
73559               return 'node point target ' + fillClass + d.id;
73560             }).attr('transform', getTransform);
73561           }
73562
73563           function drawPoints(selection, graph, entities, filter) {
73564             var wireframe = context.surface().classed('fill-wireframe');
73565             var zoom = geoScaleToZoom(projection.scale());
73566             var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
73567
73568             function renderAsPoint(entity) {
73569               return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
73570             } // All points will render as vertices in wireframe mode too..
73571
73572
73573             var points = wireframe ? [] : entities.filter(renderAsPoint);
73574             points.sort(sortY);
73575             var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
73576             var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
73577
73578             var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
73579             groups.exit().remove();
73580             var enter = groups.enter().append('g').attr('class', function (d) {
73581               return 'node point ' + d.id;
73582             }).order();
73583             enter.append('path').call(markerPath, 'shadow');
73584             enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
73585             enter.append('path').call(markerPath, 'stroke');
73586             enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
73587             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
73588               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
73589             }).classed('moved', function (d) {
73590               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
73591             }).classed('retagged', function (d) {
73592               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
73593             }).call(svgTagClasses());
73594             groups.select('.shadow'); // propagate bound data
73595
73596             groups.select('.stroke'); // propagate bound data
73597
73598             groups.select('.icon') // propagate bound data
73599             .attr('xlink:href', function (entity) {
73600               var preset = _mainPresetIndex.match(entity, graph);
73601               var picon = preset && preset.icon;
73602
73603               if (!picon) {
73604                 return '';
73605               } else {
73606                 var isMaki = /^maki-/.test(picon);
73607                 return '#' + picon + (isMaki ? '-11' : '');
73608               }
73609             }); // Draw touch targets..
73610
73611             touchLayer.call(drawTargets, graph, points, filter);
73612           }
73613
73614           return drawPoints;
73615         }
73616
73617         function svgTurns(projection, context) {
73618           function icon(turn) {
73619             var u = turn.u ? '-u' : '';
73620             if (turn.no) return '#iD-turn-no' + u;
73621             if (turn.only) return '#iD-turn-only' + u;
73622             return '#iD-turn-yes' + u;
73623           }
73624
73625           function drawTurns(selection, graph, turns) {
73626             function turnTransform(d) {
73627               var pxRadius = 50;
73628               var toWay = graph.entity(d.to.way);
73629               var toPoints = graph.childNodes(toWay).map(function (n) {
73630                 return n.loc;
73631               }).map(projection);
73632               var toLength = geoPathLength(toPoints);
73633               var mid = toLength / 2; // midpoint of destination way
73634
73635               var toNode = graph.entity(d.to.node);
73636               var toVertex = graph.entity(d.to.vertex);
73637               var a = geoAngle(toVertex, toNode, projection);
73638               var o = projection(toVertex.loc);
73639               var r = d.u ? 0 // u-turn: no radius
73640               : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
73641               : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
73642
73643               return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
73644             }
73645
73646             var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
73647             var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
73648
73649             var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
73650               return d.key;
73651             }); // exit
73652
73653             groups.exit().remove(); // enter
73654
73655             var groupsEnter = groups.enter().append('g').attr('class', function (d) {
73656               return 'turn ' + d.key;
73657             });
73658             var turnsEnter = groupsEnter.filter(function (d) {
73659               return !d.u;
73660             });
73661             turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
73662             turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
73663             var uEnter = groupsEnter.filter(function (d) {
73664               return d.u;
73665             });
73666             uEnter.append('circle').attr('r', '16');
73667             uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
73668
73669             groups = groups.merge(groupsEnter).attr('opacity', function (d) {
73670               return d.direct === false ? '0.7' : null;
73671             }).attr('transform', turnTransform);
73672             groups.select('use').attr('xlink:href', icon);
73673             groups.select('rect'); // propagate bound data
73674
73675             groups.select('circle'); // propagate bound data
73676             // Draw touch targets..
73677
73678             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73679             groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
73680               return d.key;
73681             }); // exit
73682
73683             groups.exit().remove(); // enter
73684
73685             groupsEnter = groups.enter().append('g').attr('class', function (d) {
73686               return 'turn ' + d.key;
73687             });
73688             turnsEnter = groupsEnter.filter(function (d) {
73689               return !d.u;
73690             });
73691             turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
73692             uEnter = groupsEnter.filter(function (d) {
73693               return d.u;
73694             });
73695             uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
73696
73697             groups = groups.merge(groupsEnter).attr('transform', turnTransform);
73698             groups.select('rect'); // propagate bound data
73699
73700             groups.select('circle'); // propagate bound data
73701
73702             return this;
73703           }
73704
73705           return drawTurns;
73706         }
73707
73708         function svgVertices(projection, context) {
73709           var radiuses = {
73710             //       z16-, z17,   z18+,  w/icon
73711             shadow: [6, 7.5, 7.5, 12],
73712             stroke: [2.5, 3.5, 3.5, 8],
73713             fill: [1, 1.5, 1.5, 1.5]
73714           };
73715
73716           var _currHoverTarget;
73717
73718           var _currPersistent = {};
73719           var _currHover = {};
73720           var _prevHover = {};
73721           var _currSelected = {};
73722           var _prevSelected = {};
73723           var _radii = {};
73724
73725           function sortY(a, b) {
73726             return b.loc[1] - a.loc[1];
73727           } // Avoid exit/enter if we're just moving stuff around.
73728           // The node will get a new version but we only need to run the update selection.
73729
73730
73731           function fastEntityKey(d) {
73732             var mode = context.mode();
73733             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
73734             return isMoving ? d.id : osmEntity.key(d);
73735           }
73736
73737           function draw(selection, graph, vertices, sets, filter) {
73738             sets = sets || {
73739               selected: {},
73740               important: {},
73741               hovered: {}
73742             };
73743             var icons = {};
73744             var directions = {};
73745             var wireframe = context.surface().classed('fill-wireframe');
73746             var zoom = geoScaleToZoom(projection.scale());
73747             var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
73748             var activeID = context.activeID();
73749             var base = context.history().base();
73750
73751             function getIcon(d) {
73752               // always check latest entity, as fastEntityKey avoids enter/exit now
73753               var entity = graph.entity(d.id);
73754               if (entity.id in icons) return icons[entity.id];
73755               icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
73756               return icons[entity.id];
73757             } // memoize directions results, return false for empty arrays (for use in filter)
73758
73759
73760             function getDirections(entity) {
73761               if (entity.id in directions) return directions[entity.id];
73762               var angles = entity.directions(graph, projection);
73763               directions[entity.id] = angles.length ? angles : false;
73764               return angles;
73765             }
73766
73767             function updateAttributes(selection) {
73768               ['shadow', 'stroke', 'fill'].forEach(function (klass) {
73769                 var rads = radiuses[klass];
73770                 selection.selectAll('.' + klass).each(function (entity) {
73771                   var i = z && getIcon(entity);
73772                   var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
73773
73774                   if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
73775                     r += 1.5;
73776                   }
73777
73778                   if (klass === 'shadow') {
73779                     // remember this value, so we don't need to
73780                     _radii[entity.id] = r; // recompute it when we draw the touch targets
73781                   }
73782
73783                   select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
73784                 });
73785               });
73786             }
73787
73788             vertices.sort(sortY);
73789             var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
73790
73791             groups.exit().remove(); // enter
73792
73793             var enter = groups.enter().append('g').attr('class', function (d) {
73794               return 'node vertex ' + d.id;
73795             }).order();
73796             enter.append('circle').attr('class', 'shadow');
73797             enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
73798
73799             enter.filter(function (d) {
73800               return d.hasInterestingTags();
73801             }).append('circle').attr('class', 'fill'); // update
73802
73803             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
73804               return d.id in sets.selected;
73805             }).classed('shared', function (d) {
73806               return graph.isShared(d);
73807             }).classed('endpoint', function (d) {
73808               return d.isEndpoint(graph);
73809             }).classed('added', function (d) {
73810               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
73811             }).classed('moved', function (d) {
73812               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
73813             }).classed('retagged', function (d) {
73814               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
73815             }).call(updateAttributes); // Vertices with icons get a `use`.
73816
73817             var iconUse = groups.selectAll('.icon').data(function data(d) {
73818               return zoom >= 17 && getIcon(d) ? [d] : [];
73819             }, fastEntityKey); // exit
73820
73821             iconUse.exit().remove(); // enter
73822
73823             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) {
73824               var picon = getIcon(d);
73825               var isMaki = /^maki-/.test(picon);
73826               return '#' + picon + (isMaki ? '-11' : '');
73827             }); // Vertices with directions get viewfields
73828
73829             var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
73830               return zoom >= 18 && getDirections(d) ? [d] : [];
73831             }, fastEntityKey); // exit
73832
73833             dgroups.exit().remove(); // enter/update
73834
73835             dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
73836             var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
73837               return osmEntity.key(d);
73838             }); // exit
73839
73840             viewfields.exit().remove(); // enter/update
73841
73842             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) {
73843               return 'rotate(' + d + ')';
73844             });
73845           }
73846
73847           function drawTargets(selection, graph, entities, filter) {
73848             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73849             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
73850             var getTransform = svgPointTransform(projection).geojson;
73851             var activeID = context.activeID();
73852             var data = {
73853               targets: [],
73854               nopes: []
73855             };
73856             entities.forEach(function (node) {
73857               if (activeID === node.id) return; // draw no target on the activeID
73858
73859               var vertexType = svgPassiveVertex(node, graph, activeID);
73860
73861               if (vertexType !== 0) {
73862                 // passive or adjacent - allow to connect
73863                 data.targets.push({
73864                   type: 'Feature',
73865                   id: node.id,
73866                   properties: {
73867                     target: true,
73868                     entity: node
73869                   },
73870                   geometry: node.asGeoJSON()
73871                 });
73872               } else {
73873                 data.nopes.push({
73874                   type: 'Feature',
73875                   id: node.id + '-nope',
73876                   properties: {
73877                     nope: true,
73878                     target: true,
73879                     entity: node
73880                   },
73881                   geometry: node.asGeoJSON()
73882                 });
73883               }
73884             }); // Targets allow hover and vertex snapping
73885
73886             var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
73887               return filter(d.properties.entity);
73888             }).data(data.targets, function key(d) {
73889               return d.id;
73890             }); // exit
73891
73892             targets.exit().remove(); // enter/update
73893
73894             targets.enter().append('circle').attr('r', function (d) {
73895               return _radii[d.id] || radiuses.shadow[3];
73896             }).merge(targets).attr('class', function (d) {
73897               return 'node vertex target target-allowed ' + targetClass + d.id;
73898             }).attr('transform', getTransform); // NOPE
73899
73900             var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
73901               return filter(d.properties.entity);
73902             }).data(data.nopes, function key(d) {
73903               return d.id;
73904             }); // exit
73905
73906             nopes.exit().remove(); // enter/update
73907
73908             nopes.enter().append('circle').attr('r', function (d) {
73909               return _radii[d.properties.entity.id] || radiuses.shadow[3];
73910             }).merge(nopes).attr('class', function (d) {
73911               return 'node vertex target target-nope ' + nopeClass + d.id;
73912             }).attr('transform', getTransform);
73913           } // Points can also render as vertices:
73914           // 1. in wireframe mode or
73915           // 2. at higher zooms if they have a direction
73916
73917
73918           function renderAsVertex(entity, graph, wireframe, zoom) {
73919             var geometry = entity.geometry(graph);
73920             return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
73921           }
73922
73923           function isEditedNode(node, base, head) {
73924             var baseNode = base.entities[node.id];
73925             var headNode = head.entities[node.id];
73926             return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
73927           }
73928
73929           function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
73930             var results = {};
73931             var seenIds = {};
73932
73933             function addChildVertices(entity) {
73934               // avoid redundant work and infinite recursion of circular relations
73935               if (seenIds[entity.id]) return;
73936               seenIds[entity.id] = true;
73937               var geometry = entity.geometry(graph);
73938
73939               if (!context.features().isHiddenFeature(entity, graph, geometry)) {
73940                 var i;
73941
73942                 if (entity.type === 'way') {
73943                   for (i = 0; i < entity.nodes.length; i++) {
73944                     var child = graph.hasEntity(entity.nodes[i]);
73945
73946                     if (child) {
73947                       addChildVertices(child);
73948                     }
73949                   }
73950                 } else if (entity.type === 'relation') {
73951                   for (i = 0; i < entity.members.length; i++) {
73952                     var member = graph.hasEntity(entity.members[i].id);
73953
73954                     if (member) {
73955                       addChildVertices(member);
73956                     }
73957                   }
73958                 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
73959                   results[entity.id] = entity;
73960                 }
73961               }
73962             }
73963
73964             ids.forEach(function (id) {
73965               var entity = graph.hasEntity(id);
73966               if (!entity) return;
73967
73968               if (entity.type === 'node') {
73969                 if (renderAsVertex(entity, graph, wireframe, zoom)) {
73970                   results[entity.id] = entity;
73971                   graph.parentWays(entity).forEach(function (entity) {
73972                     addChildVertices(entity);
73973                   });
73974                 }
73975               } else {
73976                 // way, relation
73977                 addChildVertices(entity);
73978               }
73979             });
73980             return results;
73981           }
73982
73983           function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
73984             var wireframe = context.surface().classed('fill-wireframe');
73985             var visualDiff = context.surface().classed('highlight-edited');
73986             var zoom = geoScaleToZoom(projection.scale());
73987             var mode = context.mode();
73988             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
73989             var base = context.history().base();
73990             var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
73991             var touchLayer = selection.selectAll('.layer-touch.points');
73992
73993             if (fullRedraw) {
73994               _currPersistent = {};
73995               _radii = {};
73996             } // Collect important vertices from the `entities` list..
73997             // (during a partial redraw, it will not contain everything)
73998
73999
74000             for (var i = 0; i < entities.length; i++) {
74001               var entity = entities[i];
74002               var geometry = entity.geometry(graph);
74003               var keep = false; // a point that looks like a vertex..
74004
74005               if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
74006                 _currPersistent[entity.id] = entity;
74007                 keep = true; // a vertex of some importance..
74008               } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
74009                 _currPersistent[entity.id] = entity;
74010                 keep = true;
74011               } // whatever this is, it's not a persistent vertex..
74012
74013
74014               if (!keep && !fullRedraw) {
74015                 delete _currPersistent[entity.id];
74016               }
74017             } // 3 sets of vertices to consider:
74018
74019
74020             var sets = {
74021               persistent: _currPersistent,
74022               // persistent = important vertices (render always)
74023               selected: _currSelected,
74024               // selected + siblings of selected (render always)
74025               hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
74026
74027             };
74028             var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
74029             // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
74030             // Adjust the filter function to expand the scope beyond whatever entities were passed in.
74031
74032             var filterRendered = function filterRendered(d) {
74033               return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
74034             };
74035
74036             drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
74037             // When drawing, render all targets (not just those affected by a partial redraw)
74038
74039             var filterTouch = function filterTouch(d) {
74040               return isMoving ? true : filterRendered(d);
74041             };
74042
74043             touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
74044
74045             function currentVisible(which) {
74046               return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
74047               .filter(function (entity) {
74048                 return entity && entity.intersects(extent, graph);
74049               });
74050             }
74051           } // partial redraw - only update the selected items..
74052
74053
74054           drawVertices.drawSelected = function (selection, graph, extent) {
74055             var wireframe = context.surface().classed('fill-wireframe');
74056             var zoom = geoScaleToZoom(projection.scale());
74057             _prevSelected = _currSelected || {};
74058
74059             if (context.map().isInWideSelection()) {
74060               _currSelected = {};
74061               context.selectedIDs().forEach(function (id) {
74062                 var entity = graph.hasEntity(id);
74063                 if (!entity) return;
74064
74065                 if (entity.type === 'node') {
74066                   if (renderAsVertex(entity, graph, wireframe, zoom)) {
74067                     _currSelected[entity.id] = entity;
74068                   }
74069                 }
74070               });
74071             } else {
74072               _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
74073             } // note that drawVertices will add `_currSelected` automatically if needed..
74074
74075
74076             var filter = function filter(d) {
74077               return d.id in _prevSelected;
74078             };
74079
74080             drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
74081           }; // partial redraw - only update the hovered items..
74082
74083
74084           drawVertices.drawHover = function (selection, graph, target, extent) {
74085             if (target === _currHoverTarget) return; // continue only if something changed
74086
74087             var wireframe = context.surface().classed('fill-wireframe');
74088             var zoom = geoScaleToZoom(projection.scale());
74089             _prevHover = _currHover || {};
74090             _currHoverTarget = target;
74091             var entity = target && target.properties && target.properties.entity;
74092
74093             if (entity) {
74094               _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
74095             } else {
74096               _currHover = {};
74097             } // note that drawVertices will add `_currHover` automatically if needed..
74098
74099
74100             var filter = function filter(d) {
74101               return d.id in _prevHover;
74102             };
74103
74104             drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
74105           };
74106
74107           return drawVertices;
74108         }
74109
74110         function utilBindOnce(target, type, listener, capture) {
74111           var typeOnce = type + '.once';
74112
74113           function one() {
74114             target.on(typeOnce, null);
74115             listener.apply(this, arguments);
74116           }
74117
74118           target.on(typeOnce, one, capture);
74119           return this;
74120         }
74121
74122         function defaultFilter$2(d3_event) {
74123           return !d3_event.ctrlKey && !d3_event.button;
74124         }
74125
74126         function defaultExtent$1() {
74127           var e = this;
74128
74129           if (e instanceof SVGElement) {
74130             e = e.ownerSVGElement || e;
74131
74132             if (e.hasAttribute('viewBox')) {
74133               e = e.viewBox.baseVal;
74134               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
74135             }
74136
74137             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
74138           }
74139
74140           return [[0, 0], [e.clientWidth, e.clientHeight]];
74141         }
74142
74143         function defaultWheelDelta$1(d3_event) {
74144           return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
74145         }
74146
74147         function defaultConstrain$1(transform, extent, translateExtent) {
74148           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
74149               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
74150               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
74151               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
74152           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));
74153         }
74154
74155         function utilZoomPan() {
74156           var filter = defaultFilter$2,
74157               extent = defaultExtent$1,
74158               constrain = defaultConstrain$1,
74159               wheelDelta = defaultWheelDelta$1,
74160               scaleExtent = [0, Infinity],
74161               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
74162               interpolate = interpolateZoom,
74163               dispatch$1 = dispatch('start', 'zoom', 'end'),
74164               _wheelDelay = 150,
74165               _transform = identity$2,
74166               _activeGesture;
74167
74168           function zoom(selection) {
74169             selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
74170             select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
74171           }
74172
74173           zoom.transform = function (collection, transform, point) {
74174             var selection = collection.selection ? collection.selection() : collection;
74175
74176             if (collection !== selection) {
74177               schedule(collection, transform, point);
74178             } else {
74179               selection.interrupt().each(function () {
74180                 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
74181               });
74182             }
74183           };
74184
74185           zoom.scaleBy = function (selection, k, p) {
74186             zoom.scaleTo(selection, function () {
74187               var k0 = _transform.k,
74188                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
74189               return k0 * k1;
74190             }, p);
74191           };
74192
74193           zoom.scaleTo = function (selection, k, p) {
74194             zoom.transform(selection, function () {
74195               var e = extent.apply(this, arguments),
74196                   t0 = _transform,
74197                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
74198                   p1 = t0.invert(p0),
74199                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
74200               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
74201             }, p);
74202           };
74203
74204           zoom.translateBy = function (selection, x, y) {
74205             zoom.transform(selection, function () {
74206               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);
74207             });
74208           };
74209
74210           zoom.translateTo = function (selection, x, y, p) {
74211             zoom.transform(selection, function () {
74212               var e = extent.apply(this, arguments),
74213                   t = _transform,
74214                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
74215               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);
74216             }, p);
74217           };
74218
74219           function scale(transform, k) {
74220             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
74221             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
74222           }
74223
74224           function translate(transform, p0, p1) {
74225             var x = p0[0] - p1[0] * transform.k,
74226                 y = p0[1] - p1[1] * transform.k;
74227             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
74228           }
74229
74230           function centroid(extent) {
74231             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
74232           }
74233
74234           function schedule(transition, transform, point) {
74235             transition.on('start.zoom', function () {
74236               gesture(this, arguments).start(null);
74237             }).on('interrupt.zoom end.zoom', function () {
74238               gesture(this, arguments).end(null);
74239             }).tween('zoom', function () {
74240               var that = this,
74241                   args = arguments,
74242                   g = gesture(that, args),
74243                   e = extent.apply(that, args),
74244                   p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
74245                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
74246                   a = _transform,
74247                   b = typeof transform === 'function' ? transform.apply(that, args) : transform,
74248                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
74249               return function (t) {
74250                 if (t === 1) t = b; // Avoid rounding error on end.
74251                 else {
74252                     var l = i(t),
74253                         k = w / l[2];
74254                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
74255                   }
74256                 g.zoom(null, null, t);
74257               };
74258             });
74259           }
74260
74261           function gesture(that, args, clean) {
74262             return !clean && _activeGesture || new Gesture(that, args);
74263           }
74264
74265           function Gesture(that, args) {
74266             this.that = that;
74267             this.args = args;
74268             this.active = 0;
74269             this.extent = extent.apply(that, args);
74270           }
74271
74272           Gesture.prototype = {
74273             start: function start(d3_event) {
74274               if (++this.active === 1) {
74275                 _activeGesture = this;
74276                 dispatch$1.call('start', this, d3_event);
74277               }
74278
74279               return this;
74280             },
74281             zoom: function zoom(d3_event, key, transform) {
74282               if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
74283               if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
74284               if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
74285               _transform = transform;
74286               dispatch$1.call('zoom', this, d3_event, key, transform);
74287               return this;
74288             },
74289             end: function end(d3_event) {
74290               if (--this.active === 0) {
74291                 _activeGesture = null;
74292                 dispatch$1.call('end', this, d3_event);
74293               }
74294
74295               return this;
74296             }
74297           };
74298
74299           function wheeled(d3_event) {
74300             if (!filter.apply(this, arguments)) return;
74301             var g = gesture(this, arguments),
74302                 t = _transform,
74303                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
74304                 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
74305             // If there were recent wheel events, reset the wheel idle timeout.
74306
74307             if (g.wheel) {
74308               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
74309                 g.mouse[1] = t.invert(g.mouse[0] = p);
74310               }
74311
74312               clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
74313             } else {
74314               g.mouse = [p, t.invert(p)];
74315               interrupt(this);
74316               g.start(d3_event);
74317             }
74318
74319             d3_event.preventDefault();
74320             d3_event.stopImmediatePropagation();
74321             g.wheel = setTimeout(wheelidled, _wheelDelay);
74322             g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
74323
74324             function wheelidled() {
74325               g.wheel = null;
74326               g.end(d3_event);
74327             }
74328           }
74329
74330           var _downPointerIDs = new Set();
74331
74332           var _pointerLocGetter;
74333
74334           function pointerdown(d3_event) {
74335             _downPointerIDs.add(d3_event.pointerId);
74336
74337             if (!filter.apply(this, arguments)) return;
74338             var g = gesture(this, arguments, _downPointerIDs.size === 1);
74339             var started;
74340             d3_event.stopImmediatePropagation();
74341             _pointerLocGetter = utilFastMouse(this);
74342
74343             var loc = _pointerLocGetter(d3_event);
74344
74345             var p = [loc, _transform.invert(loc), d3_event.pointerId];
74346
74347             if (!g.pointer0) {
74348               g.pointer0 = p;
74349               started = true;
74350             } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
74351               g.pointer1 = p;
74352             }
74353
74354             if (started) {
74355               interrupt(this);
74356               g.start(d3_event);
74357             }
74358           }
74359
74360           function pointermove(d3_event) {
74361             if (!_downPointerIDs.has(d3_event.pointerId)) return;
74362             if (!_activeGesture || !_pointerLocGetter) return;
74363             var g = gesture(this, arguments);
74364             var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
74365             var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
74366
74367             if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
74368               // The pointer went up without ending the gesture somehow, e.g.
74369               // a down mouse was moved off the map and released. End it here.
74370               if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
74371               if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
74372               g.end(d3_event);
74373               return;
74374             }
74375
74376             d3_event.preventDefault();
74377             d3_event.stopImmediatePropagation();
74378
74379             var loc = _pointerLocGetter(d3_event);
74380
74381             var t, p, l;
74382             if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
74383             t = _transform;
74384
74385             if (g.pointer1) {
74386               var p0 = g.pointer0[0],
74387                   l0 = g.pointer0[1],
74388                   p1 = g.pointer1[0],
74389                   l1 = g.pointer1[1],
74390                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
74391                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
74392               t = scale(t, Math.sqrt(dp / dl));
74393               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
74394               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
74395             } else if (g.pointer0) {
74396               p = g.pointer0[0];
74397               l = g.pointer0[1];
74398             } else return;
74399
74400             g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
74401           }
74402
74403           function pointerup(d3_event) {
74404             if (!_downPointerIDs.has(d3_event.pointerId)) return;
74405
74406             _downPointerIDs["delete"](d3_event.pointerId);
74407
74408             if (!_activeGesture) return;
74409             var g = gesture(this, arguments);
74410             d3_event.stopImmediatePropagation();
74411             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;
74412
74413             if (g.pointer1 && !g.pointer0) {
74414               g.pointer0 = g.pointer1;
74415               delete g.pointer1;
74416             }
74417
74418             if (g.pointer0) g.pointer0[1] = _transform.invert(g.pointer0[0]);else {
74419               g.end(d3_event);
74420             }
74421           }
74422
74423           zoom.wheelDelta = function (_) {
74424             return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
74425           };
74426
74427           zoom.filter = function (_) {
74428             return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
74429           };
74430
74431           zoom.extent = function (_) {
74432             return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
74433           };
74434
74435           zoom.scaleExtent = function (_) {
74436             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
74437           };
74438
74439           zoom.translateExtent = function (_) {
74440             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]]];
74441           };
74442
74443           zoom.constrain = function (_) {
74444             return arguments.length ? (constrain = _, zoom) : constrain;
74445           };
74446
74447           zoom.interpolate = function (_) {
74448             return arguments.length ? (interpolate = _, zoom) : interpolate;
74449           };
74450
74451           zoom._transform = function (_) {
74452             return arguments.length ? (_transform = _, zoom) : _transform;
74453           };
74454
74455           return utilRebind(zoom, dispatch$1, 'on');
74456         }
74457
74458         // if pointer events are supported. Falls back to default `dblclick` event.
74459
74460         function utilDoubleUp() {
74461           var dispatch$1 = dispatch('doubleUp');
74462           var _maxTimespan = 500; // milliseconds
74463
74464           var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
74465
74466           var _pointer; // object representing the pointer that could trigger double up
74467
74468
74469           function pointerIsValidFor(loc) {
74470             // second pointerup must occur within a small timeframe after the first pointerdown
74471             return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
74472             geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
74473           }
74474
74475           function pointerdown(d3_event) {
74476             // ignore right-click
74477             if (d3_event.ctrlKey || d3_event.button === 2) return;
74478             var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
74479             // events on touch devices
74480
74481             if (_pointer && !pointerIsValidFor(loc)) {
74482               // if this pointer is no longer valid, clear it so another can be started
74483               _pointer = undefined;
74484             }
74485
74486             if (!_pointer) {
74487               _pointer = {
74488                 startLoc: loc,
74489                 startTime: new Date().getTime(),
74490                 upCount: 0,
74491                 pointerId: d3_event.pointerId
74492               };
74493             } else {
74494               // double down
74495               _pointer.pointerId = d3_event.pointerId;
74496             }
74497           }
74498
74499           function pointerup(d3_event) {
74500             // ignore right-click
74501             if (d3_event.ctrlKey || d3_event.button === 2) return;
74502             if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
74503             _pointer.upCount += 1;
74504
74505             if (_pointer.upCount === 2) {
74506               // double up!
74507               var loc = [d3_event.clientX, d3_event.clientY];
74508
74509               if (pointerIsValidFor(loc)) {
74510                 var locInThis = utilFastMouse(this)(d3_event);
74511                 dispatch$1.call('doubleUp', this, d3_event, locInThis);
74512               } // clear the pointer info in any case
74513
74514
74515               _pointer = undefined;
74516             }
74517           }
74518
74519           function doubleUp(selection) {
74520             if ('PointerEvent' in window) {
74521               // dblclick isn't well supported on touch devices so manually use
74522               // pointer events if they're available
74523               selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
74524             } else {
74525               // fallback to dblclick
74526               selection.on('dblclick.doubleUp', function (d3_event) {
74527                 dispatch$1.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
74528               });
74529             }
74530           }
74531
74532           doubleUp.off = function (selection) {
74533             selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
74534           };
74535
74536           return utilRebind(doubleUp, dispatch$1, 'on');
74537         }
74538
74539         var TILESIZE = 256;
74540         var minZoom = 2;
74541         var maxZoom = 24;
74542         var kMin = geoZoomToScale(minZoom, TILESIZE);
74543         var kMax = geoZoomToScale(maxZoom, TILESIZE);
74544
74545         function clamp(num, min, max) {
74546           return Math.max(min, Math.min(num, max));
74547         }
74548
74549         function rendererMap(context) {
74550           var dispatch$1 = dispatch('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
74551           var projection = context.projection;
74552           var curtainProjection = context.curtainProjection;
74553           var drawLayers;
74554           var drawPoints;
74555           var drawVertices;
74556           var drawLines;
74557           var drawAreas;
74558           var drawMidpoints;
74559           var drawLabels;
74560
74561           var _selection = select(null);
74562
74563           var supersurface = select(null);
74564           var wrapper = select(null);
74565           var surface = select(null);
74566           var _dimensions = [1, 1];
74567           var _dblClickZoomEnabled = true;
74568           var _redrawEnabled = true;
74569
74570           var _gestureTransformStart;
74571
74572           var _transformStart = projection.transform();
74573
74574           var _transformLast;
74575
74576           var _isTransformed = false;
74577           var _minzoom = 0;
74578
74579           var _getMouseCoords;
74580
74581           var _lastPointerEvent;
74582
74583           var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
74584
74585
74586           var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
74587
74588           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
74589
74590
74591           var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
74592
74593           var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
74594             _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
74595           }).on('end.map', function () {
74596             _pointerDown = false;
74597           });
74598
74599           var _doubleUpHandler = utilDoubleUp();
74600
74601           var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
74602           // var pendingRedrawCall;
74603           // function scheduleRedraw() {
74604           //     // Only schedule the redraw if one has not already been set.
74605           //     if (isRedrawScheduled) return;
74606           //     isRedrawScheduled = true;
74607           //     var that = this;
74608           //     var args = arguments;
74609           //     pendingRedrawCall = window.requestIdleCallback(function () {
74610           //         // Reset the boolean so future redraws can be set.
74611           //         isRedrawScheduled = false;
74612           //         redraw.apply(that, args);
74613           //     }, { timeout: 1400 });
74614           // }
74615
74616
74617           function cancelPendingRedraw() {
74618             scheduleRedraw.cancel(); // isRedrawScheduled = false;
74619             // window.cancelIdleCallback(pendingRedrawCall);
74620           }
74621
74622           function map(selection) {
74623             _selection = selection;
74624             context.on('change.map', immediateRedraw);
74625             var osm = context.connection();
74626
74627             if (osm) {
74628               osm.on('change.map', immediateRedraw);
74629             }
74630
74631             function didUndoOrRedo(targetTransform) {
74632               var mode = context.mode().id;
74633               if (mode !== 'browse' && mode !== 'select') return;
74634
74635               if (targetTransform) {
74636                 map.transformEase(targetTransform);
74637               }
74638             }
74639
74640             context.history().on('merge.map', function () {
74641               scheduleRedraw();
74642             }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
74643               didUndoOrRedo(fromStack.transform);
74644             }).on('redone.map', function (stack) {
74645               didUndoOrRedo(stack.transform);
74646             });
74647             context.background().on('change.map', immediateRedraw);
74648             context.features().on('redraw.map', immediateRedraw);
74649             drawLayers.on('change.map', function () {
74650               context.background().updateImagery();
74651               immediateRedraw();
74652             });
74653             selection.on('wheel.map mousewheel.map', function (d3_event) {
74654               // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
74655               d3_event.preventDefault();
74656             }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
74657
74658             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
74659             // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
74660
74661             wrapper = supersurface.append('div').attr('class', 'layer layer-data');
74662             map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
74663             surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
74664               _lastPointerEvent = d3_event;
74665
74666               if (d3_event.button === 2) {
74667                 d3_event.stopPropagation();
74668               }
74669             }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
74670               _lastPointerEvent = d3_event;
74671
74672               if (resetTransform()) {
74673                 immediateRedraw();
74674               }
74675             }).on(_pointerPrefix + 'move.map', function (d3_event) {
74676               _lastPointerEvent = d3_event;
74677             }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
74678               if (map.editableDataEnabled() && !_isTransformed) {
74679                 var hover = d3_event.target.__data__;
74680                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
74681                 dispatch$1.call('drawn', this, {
74682                   full: false
74683                 });
74684               }
74685             }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
74686               if (map.editableDataEnabled() && !_isTransformed) {
74687                 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
74688                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
74689                 dispatch$1.call('drawn', this, {
74690                   full: false
74691                 });
74692               }
74693             });
74694             var detected = utilDetect(); // only WebKit supports gesture events
74695
74696             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
74697             // but we only need to do this on desktop Safari anyway. – #7694
74698             !detected.isMobileWebKit) {
74699               // Desktop Safari sends gesture events for multitouch trackpad pinches.
74700               // We can listen for these and translate them into map zooms.
74701               surface.on('gesturestart.surface', function (d3_event) {
74702                 d3_event.preventDefault();
74703                 _gestureTransformStart = projection.transform();
74704               }).on('gesturechange.surface', gestureChange);
74705             } // must call after surface init
74706
74707
74708             updateAreaFill();
74709
74710             _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
74711               if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
74712
74713               if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
74714               !select(d3_event.target).classed('fill')) return;
74715               var zoomOut = d3_event.shiftKey;
74716               var t = projection.transform();
74717               var p1 = t.invert(p0);
74718               t = t.scale(zoomOut ? 0.5 : 2);
74719               t.x = p0[0] - p1[0] * t.k;
74720               t.y = p0[1] - p1[1] * t.k;
74721               map.transformEase(t);
74722             });
74723
74724             context.on('enter.map', function () {
74725               if (!map.editableDataEnabled(true
74726               /* skip zoom check */
74727               )) return; // redraw immediately any objects affected by a change in selectedIDs.
74728
74729               var graph = context.graph();
74730               var selectedAndParents = {};
74731               context.selectedIDs().forEach(function (id) {
74732                 var entity = graph.hasEntity(id);
74733
74734                 if (entity) {
74735                   selectedAndParents[entity.id] = entity;
74736
74737                   if (entity.type === 'node') {
74738                     graph.parentWays(entity).forEach(function (parent) {
74739                       selectedAndParents[parent.id] = parent;
74740                     });
74741                   }
74742                 }
74743               });
74744               var data = Object.values(selectedAndParents);
74745
74746               var filter = function filter(d) {
74747                 return d.id in selectedAndParents;
74748               };
74749
74750               data = context.features().filter(data, graph);
74751               surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
74752               dispatch$1.call('drawn', this, {
74753                 full: false
74754               }); // redraw everything else later
74755
74756               scheduleRedraw();
74757             });
74758             map.dimensions(utilGetDimensions(selection));
74759           }
74760
74761           function zoomEventFilter(d3_event) {
74762             // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
74763             // Intercept `mousedown` and check if there is an orphaned zoom gesture.
74764             // This can happen if a previous `mousedown` occurred without a `mouseup`.
74765             // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
74766             // so that d3-zoom won't stop propagation of new `mousedown` events.
74767             if (d3_event.type === 'mousedown') {
74768               var hasOrphan = false;
74769               var listeners = window.__on;
74770
74771               for (var i = 0; i < listeners.length; i++) {
74772                 var listener = listeners[i];
74773
74774                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
74775                   hasOrphan = true;
74776                   break;
74777                 }
74778               }
74779
74780               if (hasOrphan) {
74781                 var event = window.CustomEvent;
74782
74783                 if (event) {
74784                   event = new event('mouseup');
74785                 } else {
74786                   event = window.document.createEvent('Event');
74787                   event.initEvent('mouseup', false, false);
74788                 } // Event needs to be dispatched with an event.view property.
74789
74790
74791                 event.view = window;
74792                 window.dispatchEvent(event);
74793               }
74794             }
74795
74796             return d3_event.button !== 2; // ignore right clicks
74797           }
74798
74799           function pxCenter() {
74800             return [_dimensions[0] / 2, _dimensions[1] / 2];
74801           }
74802
74803           function drawEditable(difference, extent) {
74804             var mode = context.mode();
74805             var graph = context.graph();
74806             var features = context.features();
74807             var all = context.history().intersects(map.extent());
74808             var fullRedraw = false;
74809             var data;
74810             var set;
74811             var filter;
74812             var applyFeatureLayerFilters = true;
74813
74814             if (map.isInWideSelection()) {
74815               data = [];
74816               utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
74817                 var entity = context.hasEntity(id);
74818                 if (entity) data.push(entity);
74819               });
74820               fullRedraw = true;
74821               filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
74822
74823               applyFeatureLayerFilters = false;
74824             } else if (difference) {
74825               var complete = difference.complete(map.extent());
74826               data = Object.values(complete).filter(Boolean);
74827               set = new Set(Object.keys(complete));
74828
74829               filter = function filter(d) {
74830                 return set.has(d.id);
74831               };
74832
74833               features.clear(data);
74834             } else {
74835               // force a full redraw if gatherStats detects that a feature
74836               // should be auto-hidden (e.g. points or buildings)..
74837               if (features.gatherStats(all, graph, _dimensions)) {
74838                 extent = undefined;
74839               }
74840
74841               if (extent) {
74842                 data = context.history().intersects(map.extent().intersection(extent));
74843                 set = new Set(data.map(function (entity) {
74844                   return entity.id;
74845                 }));
74846
74847                 filter = function filter(d) {
74848                   return set.has(d.id);
74849                 };
74850               } else {
74851                 data = all;
74852                 fullRedraw = true;
74853                 filter = utilFunctor(true);
74854               }
74855             }
74856
74857             if (applyFeatureLayerFilters) {
74858               data = features.filter(data, graph);
74859             } else {
74860               context.features().resetStats();
74861             }
74862
74863             if (mode && mode.id === 'select') {
74864               // update selected vertices - the user might have just double-clicked a way,
74865               // creating a new vertex, triggering a partial redraw without a mode change
74866               surface.call(drawVertices.drawSelected, graph, map.extent());
74867             }
74868
74869             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);
74870             dispatch$1.call('drawn', this, {
74871               full: true
74872             });
74873           }
74874
74875           map.init = function () {
74876             drawLayers = svgLayers(projection, context);
74877             drawPoints = svgPoints(projection, context);
74878             drawVertices = svgVertices(projection, context);
74879             drawLines = svgLines(projection, context);
74880             drawAreas = svgAreas(projection, context);
74881             drawMidpoints = svgMidpoints(projection, context);
74882             drawLabels = svgLabels(projection, context);
74883           };
74884
74885           function editOff() {
74886             context.features().resetStats();
74887             surface.selectAll('.layer-osm *').remove();
74888             surface.selectAll('.layer-touch:not(.markers) *').remove();
74889             var allowed = {
74890               'browse': true,
74891               'save': true,
74892               'select-note': true,
74893               'select-data': true,
74894               'select-error': true
74895             };
74896             var mode = context.mode();
74897
74898             if (mode && !allowed[mode.id]) {
74899               context.enter(modeBrowse(context));
74900             }
74901
74902             dispatch$1.call('drawn', this, {
74903               full: true
74904             });
74905           }
74906
74907           function gestureChange(d3_event) {
74908             // Remap Safari gesture events to wheel events - #5492
74909             // We want these disabled most places, but enabled for zoom/unzoom on map surface
74910             // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
74911             var e = d3_event;
74912             e.preventDefault();
74913             var props = {
74914               deltaMode: 0,
74915               // dummy values to ignore in zoomPan
74916               deltaY: 1,
74917               // dummy values to ignore in zoomPan
74918               clientX: e.clientX,
74919               clientY: e.clientY,
74920               screenX: e.screenX,
74921               screenY: e.screenY,
74922               x: e.x,
74923               y: e.y
74924             };
74925             var e2 = new WheelEvent('wheel', props);
74926             e2._scale = e.scale; // preserve the original scale
74927
74928             e2._rotation = e.rotation; // preserve the original rotation
74929
74930             _selection.node().dispatchEvent(e2);
74931           }
74932
74933           function zoomPan(event, key, transform) {
74934             var source = event && event.sourceEvent || event;
74935             var eventTransform = transform || event && event.transform;
74936             var x = eventTransform.x;
74937             var y = eventTransform.y;
74938             var k = eventTransform.k; // Special handling of 'wheel' events:
74939             // They might be triggered by the user scrolling the mouse wheel,
74940             // or 2-finger pinch/zoom gestures, the transform may need adjustment.
74941
74942             if (source && source.type === 'wheel') {
74943               // assume that the gesture is already handled by pointer events
74944               if (_pointerDown) return;
74945               var detected = utilDetect();
74946               var dX = source.deltaX;
74947               var dY = source.deltaY;
74948               var x2 = x;
74949               var y2 = y;
74950               var k2 = k;
74951               var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
74952               // If wheel delta is provided in LINE units, recalculate it in PIXEL units
74953               // We are essentially redoing the calculations that occur here:
74954               //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
74955               // See this for more info:
74956               //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
74957
74958               if (source.deltaMode === 1
74959               /* LINE */
74960               ) {
74961                   // Convert from lines to pixels, more if the user is scrolling fast.
74962                   // (I made up the exp function to roughly match Firefox to what Chrome does)
74963                   // These numbers should be floats, because integers are treated as pan gesture below.
74964                   var lines = Math.abs(source.deltaY);
74965                   var sign = source.deltaY > 0 ? 1 : -1;
74966                   dY = sign * clamp(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
74967                   350.000244140625 // max
74968                   ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
74969                   // There doesn't seem to be any scroll acceleration.
74970                   // This multiplier increases the speed a little bit - #5512
74971
74972                   if (detected.os !== 'mac') {
74973                     dY *= 5;
74974                   } // recalculate x2,y2,k2
74975
74976
74977                   t0 = _isTransformed ? _transformLast : _transformStart;
74978                   p0 = _getMouseCoords(source);
74979                   p1 = t0.invert(p0);
74980                   k2 = t0.k * Math.pow(2, -dY / 500);
74981                   k2 = clamp(k2, kMin, kMax);
74982                   x2 = p0[0] - p1[0] * k2;
74983                   y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
74984                   // These are fake `wheel` events we made from Safari `gesturechange` events..
74985                 } else if (source._scale) {
74986                 // recalculate x2,y2,k2
74987                 t0 = _gestureTransformStart;
74988                 p0 = _getMouseCoords(source);
74989                 p1 = t0.invert(p0);
74990                 k2 = t0.k * source._scale;
74991                 k2 = clamp(k2, kMin, kMax);
74992                 x2 = p0[0] - p1[0] * k2;
74993                 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
74994                 // Pinch zooming via the `wheel` event will always have:
74995                 // - `ctrlKey = true`
74996                 // - `deltaY` is not round integer pixels (ignore `deltaX`)
74997               } else if (source.ctrlKey && !isInteger(dY)) {
74998                 dY *= 6; // slightly scale up whatever the browser gave us
74999                 // recalculate x2,y2,k2
75000
75001                 t0 = _isTransformed ? _transformLast : _transformStart;
75002                 p0 = _getMouseCoords(source);
75003                 p1 = t0.invert(p0);
75004                 k2 = t0.k * Math.pow(2, -dY / 500);
75005                 k2 = clamp(k2, kMin, kMax);
75006                 x2 = p0[0] - p1[0] * k2;
75007                 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
75008               } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
75009                 // recalculate x2,y2,k2
75010                 t0 = _isTransformed ? _transformLast : _transformStart;
75011                 p0 = _getMouseCoords(source);
75012                 p1 = t0.invert(p0);
75013                 k2 = t0.k * Math.pow(2, -dY / 500);
75014                 k2 = clamp(k2, kMin, kMax);
75015                 x2 = p0[0] - p1[0] * k2;
75016                 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers) - #5492, #5512
75017                 // Panning via the `wheel` event will always have:
75018                 // - `ctrlKey = false`
75019                 // - `deltaX`,`deltaY` are round integer pixels
75020               } else if (detected.os === 'mac' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
75021                 p1 = projection.translate();
75022                 x2 = p1[0] - dX;
75023                 y2 = p1[1] - dY;
75024                 k2 = projection.scale();
75025                 k2 = clamp(k2, kMin, kMax);
75026               } // something changed - replace the event transform
75027
75028
75029               if (x2 !== x || y2 !== y || k2 !== k) {
75030                 x = x2;
75031                 y = y2;
75032                 k = k2;
75033                 eventTransform = identity$2.translate(x2, y2).scale(k2);
75034
75035                 if (_zoomerPanner._transform) {
75036                   // utilZoomPan interface
75037                   _zoomerPanner._transform(eventTransform);
75038                 } else {
75039                   // d3_zoom interface
75040                   _selection.node().__zoom = eventTransform;
75041                 }
75042               }
75043             }
75044
75045             if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
75046               return; // no change
75047             }
75048
75049             var withinEditableZoom = map.withinEditableZoom();
75050
75051             if (_lastWithinEditableZoom !== withinEditableZoom) {
75052               if (_lastWithinEditableZoom !== undefined) {
75053                 // notify that the map zoomed in or out over the editable zoom threshold
75054                 dispatch$1.call('crossEditableZoom', this, withinEditableZoom);
75055               }
75056
75057               _lastWithinEditableZoom = withinEditableZoom;
75058             }
75059
75060             if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
75061               surface.interrupt();
75062               dispatch$1.call('hitMinZoom', this, map);
75063               setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
75064               scheduleRedraw();
75065               dispatch$1.call('move', this, map);
75066               return;
75067             }
75068
75069             projection.transform(eventTransform);
75070             var scale = k / _transformStart.k;
75071             var tX = (x / scale - _transformStart.x) * scale;
75072             var tY = (y / scale - _transformStart.y) * scale;
75073
75074             if (context.inIntro()) {
75075               curtainProjection.transform({
75076                 x: x - tX,
75077                 y: y - tY,
75078                 k: k
75079               });
75080             }
75081
75082             if (source) {
75083               _lastPointerEvent = event;
75084             }
75085
75086             _isTransformed = true;
75087             _transformLast = eventTransform;
75088             utilSetTransform(supersurface, tX, tY, scale);
75089             scheduleRedraw();
75090             dispatch$1.call('move', this, map);
75091
75092             function isInteger(val) {
75093               return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
75094             }
75095           }
75096
75097           function resetTransform() {
75098             if (!_isTransformed) return false;
75099             utilSetTransform(supersurface, 0, 0);
75100             _isTransformed = false;
75101
75102             if (context.inIntro()) {
75103               curtainProjection.transform(projection.transform());
75104             }
75105
75106             return true;
75107           }
75108
75109           function redraw(difference, extent) {
75110             if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
75111             // It would result in artifacts where differenced entities are redrawn with
75112             // one transform and unchanged entities with another.
75113
75114             if (resetTransform()) {
75115               difference = extent = undefined;
75116             }
75117
75118             var zoom = map.zoom();
75119             var z = String(~~zoom);
75120
75121             if (surface.attr('data-zoom') !== z) {
75122               surface.attr('data-zoom', z);
75123             } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
75124
75125
75126             var lat = map.center()[1];
75127             var lowzoom = linear$2().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
75128             surface.classed('low-zoom', zoom <= lowzoom(lat));
75129
75130             if (!difference) {
75131               supersurface.call(context.background());
75132               wrapper.call(drawLayers);
75133             } // OSM
75134
75135
75136             if (map.editableDataEnabled() || map.isInWideSelection()) {
75137               context.loadTiles(projection);
75138               drawEditable(difference, extent);
75139             } else {
75140               editOff();
75141             }
75142
75143             _transformStart = projection.transform();
75144             return map;
75145           }
75146
75147           var immediateRedraw = function immediateRedraw(difference, extent) {
75148             if (!difference && !extent) cancelPendingRedraw();
75149             redraw(difference, extent);
75150           };
75151
75152           map.lastPointerEvent = function () {
75153             return _lastPointerEvent;
75154           };
75155
75156           map.mouse = function (d3_event) {
75157             var event = _lastPointerEvent || d3_event;
75158
75159             if (event) {
75160               var s;
75161
75162               while (s = event.sourceEvent) {
75163                 event = s;
75164               }
75165
75166               return _getMouseCoords(event);
75167             }
75168
75169             return null;
75170           }; // returns Lng/Lat
75171
75172
75173           map.mouseCoordinates = function () {
75174             var coord = map.mouse() || pxCenter();
75175             return projection.invert(coord);
75176           };
75177
75178           map.dblclickZoomEnable = function (val) {
75179             if (!arguments.length) return _dblClickZoomEnabled;
75180             _dblClickZoomEnabled = val;
75181             return map;
75182           };
75183
75184           map.redrawEnable = function (val) {
75185             if (!arguments.length) return _redrawEnabled;
75186             _redrawEnabled = val;
75187             return map;
75188           };
75189
75190           map.isTransformed = function () {
75191             return _isTransformed;
75192           };
75193
75194           function setTransform(t2, duration, force) {
75195             var t = projection.transform();
75196             if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
75197
75198             if (duration) {
75199               _selection.transition().duration(duration).on('start', function () {
75200                 map.startEase();
75201               }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
75202             } else {
75203               projection.transform(t2);
75204               _transformStart = t2;
75205
75206               _selection.call(_zoomerPanner.transform, _transformStart);
75207             }
75208
75209             return true;
75210           }
75211
75212           function setCenterZoom(loc2, z2, duration, force) {
75213             var c = map.center();
75214             var z = map.zoom();
75215             if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
75216             var proj = geoRawMercator().transform(projection.transform()); // copy projection
75217
75218             var k2 = clamp(geoZoomToScale(z2, TILESIZE), kMin, kMax);
75219             proj.scale(k2);
75220             var t = proj.translate();
75221             var point = proj(loc2);
75222             var center = pxCenter();
75223             t[0] += center[0] - point[0];
75224             t[1] += center[1] - point[1];
75225             return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
75226           }
75227
75228           map.pan = function (delta, duration) {
75229             var t = projection.translate();
75230             var k = projection.scale();
75231             t[0] += delta[0];
75232             t[1] += delta[1];
75233
75234             if (duration) {
75235               _selection.transition().duration(duration).on('start', function () {
75236                 map.startEase();
75237               }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
75238             } else {
75239               projection.translate(t);
75240               _transformStart = projection.transform();
75241
75242               _selection.call(_zoomerPanner.transform, _transformStart);
75243
75244               dispatch$1.call('move', this, map);
75245               immediateRedraw();
75246             }
75247
75248             return map;
75249           };
75250
75251           map.dimensions = function (val) {
75252             if (!arguments.length) return _dimensions;
75253             _dimensions = val;
75254             drawLayers.dimensions(_dimensions);
75255             context.background().dimensions(_dimensions);
75256             projection.clipExtent([[0, 0], _dimensions]);
75257             _getMouseCoords = utilFastMouse(supersurface.node());
75258             scheduleRedraw();
75259             return map;
75260           };
75261
75262           function zoomIn(delta) {
75263             setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
75264           }
75265
75266           function zoomOut(delta) {
75267             setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
75268           }
75269
75270           map.zoomIn = function () {
75271             zoomIn(1);
75272           };
75273
75274           map.zoomInFurther = function () {
75275             zoomIn(4);
75276           };
75277
75278           map.canZoomIn = function () {
75279             return map.zoom() < maxZoom;
75280           };
75281
75282           map.zoomOut = function () {
75283             zoomOut(1);
75284           };
75285
75286           map.zoomOutFurther = function () {
75287             zoomOut(4);
75288           };
75289
75290           map.canZoomOut = function () {
75291             return map.zoom() > minZoom;
75292           };
75293
75294           map.center = function (loc2) {
75295             if (!arguments.length) {
75296               return projection.invert(pxCenter());
75297             }
75298
75299             if (setCenterZoom(loc2, map.zoom())) {
75300               dispatch$1.call('move', this, map);
75301             }
75302
75303             scheduleRedraw();
75304             return map;
75305           };
75306
75307           map.unobscuredCenterZoomEase = function (loc, zoom) {
75308             var offset = map.unobscuredOffsetPx();
75309             var proj = geoRawMercator().transform(projection.transform()); // copy projection
75310             // use the target zoom to calculate the offset center
75311
75312             proj.scale(geoZoomToScale(zoom, TILESIZE));
75313             var locPx = proj(loc);
75314             var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
75315             var offsetLoc = proj.invert(offsetLocPx);
75316             map.centerZoomEase(offsetLoc, zoom);
75317           };
75318
75319           map.unobscuredOffsetPx = function () {
75320             var openPane = context.container().select('.map-panes .map-pane.shown');
75321
75322             if (!openPane.empty()) {
75323               return [openPane.node().offsetWidth / 2, 0];
75324             }
75325
75326             return [0, 0];
75327           };
75328
75329           map.zoom = function (z2) {
75330             if (!arguments.length) {
75331               return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
75332             }
75333
75334             if (z2 < _minzoom) {
75335               surface.interrupt();
75336               dispatch$1.call('hitMinZoom', this, map);
75337               z2 = context.minEditableZoom();
75338             }
75339
75340             if (setCenterZoom(map.center(), z2)) {
75341               dispatch$1.call('move', this, map);
75342             }
75343
75344             scheduleRedraw();
75345             return map;
75346           };
75347
75348           map.centerZoom = function (loc2, z2) {
75349             if (setCenterZoom(loc2, z2)) {
75350               dispatch$1.call('move', this, map);
75351             }
75352
75353             scheduleRedraw();
75354             return map;
75355           };
75356
75357           map.zoomTo = function (entity) {
75358             var extent = entity.extent(context.graph());
75359             if (!isFinite(extent.area())) return map;
75360             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
75361             return map.centerZoom(extent.center(), z2);
75362           };
75363
75364           map.centerEase = function (loc2, duration) {
75365             duration = duration || 250;
75366             setCenterZoom(loc2, map.zoom(), duration);
75367             return map;
75368           };
75369
75370           map.zoomEase = function (z2, duration) {
75371             duration = duration || 250;
75372             setCenterZoom(map.center(), z2, duration, false);
75373             return map;
75374           };
75375
75376           map.centerZoomEase = function (loc2, z2, duration) {
75377             duration = duration || 250;
75378             setCenterZoom(loc2, z2, duration, false);
75379             return map;
75380           };
75381
75382           map.transformEase = function (t2, duration) {
75383             duration = duration || 250;
75384             setTransform(t2, duration, false
75385             /* don't force */
75386             );
75387             return map;
75388           };
75389
75390           map.zoomToEase = function (obj, duration) {
75391             var extent;
75392
75393             if (Array.isArray(obj)) {
75394               obj.forEach(function (entity) {
75395                 var entityExtent = entity.extent(context.graph());
75396
75397                 if (!extent) {
75398                   extent = entityExtent;
75399                 } else {
75400                   extent = extent.extend(entityExtent);
75401                 }
75402               });
75403             } else {
75404               extent = obj.extent(context.graph());
75405             }
75406
75407             if (!isFinite(extent.area())) return map;
75408             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
75409             return map.centerZoomEase(extent.center(), z2, duration);
75410           };
75411
75412           map.startEase = function () {
75413             utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
75414               map.cancelEase();
75415             });
75416             return map;
75417           };
75418
75419           map.cancelEase = function () {
75420             _selection.interrupt();
75421
75422             return map;
75423           };
75424
75425           map.extent = function (val) {
75426             if (!arguments.length) {
75427               return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
75428             } else {
75429               var extent = geoExtent(val);
75430               map.centerZoom(extent.center(), map.extentZoom(extent));
75431             }
75432           };
75433
75434           map.trimmedExtent = function (val) {
75435             if (!arguments.length) {
75436               var headerY = 71;
75437               var footerY = 30;
75438               var pad = 10;
75439               return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
75440             } else {
75441               var extent = geoExtent(val);
75442               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
75443             }
75444           };
75445
75446           function calcExtentZoom(extent, dim) {
75447             var tl = projection([extent[0][0], extent[1][1]]);
75448             var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
75449
75450             var hFactor = (br[0] - tl[0]) / dim[0];
75451             var vFactor = (br[1] - tl[1]) / dim[1];
75452             var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
75453             var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
75454             var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
75455             return newZoom;
75456           }
75457
75458           map.extentZoom = function (val) {
75459             return calcExtentZoom(geoExtent(val), _dimensions);
75460           };
75461
75462           map.trimmedExtentZoom = function (val) {
75463             var trimY = 120;
75464             var trimX = 40;
75465             var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
75466             return calcExtentZoom(geoExtent(val), trimmed);
75467           };
75468
75469           map.withinEditableZoom = function () {
75470             return map.zoom() >= context.minEditableZoom();
75471           };
75472
75473           map.isInWideSelection = function () {
75474             return !map.withinEditableZoom() && context.selectedIDs().length;
75475           };
75476
75477           map.editableDataEnabled = function (skipZoomCheck) {
75478             var layer = context.layers().layer('osm');
75479             if (!layer || !layer.enabled()) return false;
75480             return skipZoomCheck || map.withinEditableZoom();
75481           };
75482
75483           map.notesEditable = function () {
75484             var layer = context.layers().layer('notes');
75485             if (!layer || !layer.enabled()) return false;
75486             return map.withinEditableZoom();
75487           };
75488
75489           map.minzoom = function (val) {
75490             if (!arguments.length) return _minzoom;
75491             _minzoom = val;
75492             return map;
75493           };
75494
75495           map.toggleHighlightEdited = function () {
75496             surface.classed('highlight-edited', !surface.classed('highlight-edited'));
75497             map.pan([0, 0]); // trigger a redraw
75498
75499             dispatch$1.call('changeHighlighting', this);
75500           };
75501
75502           map.areaFillOptions = ['wireframe', 'partial', 'full'];
75503
75504           map.activeAreaFill = function (val) {
75505             if (!arguments.length) return corePreferences('area-fill') || 'partial';
75506             corePreferences('area-fill', val);
75507
75508             if (val !== 'wireframe') {
75509               corePreferences('area-fill-toggle', val);
75510             }
75511
75512             updateAreaFill();
75513             map.pan([0, 0]); // trigger a redraw
75514
75515             dispatch$1.call('changeAreaFill', this);
75516             return map;
75517           };
75518
75519           map.toggleWireframe = function () {
75520             var activeFill = map.activeAreaFill();
75521
75522             if (activeFill === 'wireframe') {
75523               activeFill = corePreferences('area-fill-toggle') || 'partial';
75524             } else {
75525               activeFill = 'wireframe';
75526             }
75527
75528             map.activeAreaFill(activeFill);
75529           };
75530
75531           function updateAreaFill() {
75532             var activeFill = map.activeAreaFill();
75533             map.areaFillOptions.forEach(function (opt) {
75534               surface.classed('fill-' + opt, Boolean(opt === activeFill));
75535             });
75536           }
75537
75538           map.layers = function () {
75539             return drawLayers;
75540           };
75541
75542           map.doubleUpHandler = function () {
75543             return _doubleUpHandler;
75544           };
75545
75546           return utilRebind(map, dispatch$1, 'on');
75547         }
75548
75549         function rendererPhotos(context) {
75550           var dispatch$1 = dispatch('change');
75551           var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
75552           var _allPhotoTypes = ['flat', 'panoramic'];
75553
75554           var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
75555
75556
75557           var _dateFilters = ['fromDate', 'toDate'];
75558
75559           var _fromDate;
75560
75561           var _toDate;
75562
75563           var _usernames;
75564
75565           function photos() {}
75566
75567           function updateStorage() {
75568             if (window.mocha) return;
75569             var hash = utilStringQs(window.location.hash);
75570             var enabled = context.layers().all().filter(function (d) {
75571               return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
75572             }).map(function (d) {
75573               return d.id;
75574             });
75575
75576             if (enabled.length) {
75577               hash.photo_overlay = enabled.join(',');
75578             } else {
75579               delete hash.photo_overlay;
75580             }
75581
75582             window.location.replace('#' + utilQsString(hash, true));
75583           }
75584
75585           photos.overlayLayerIDs = function () {
75586             return _layerIDs;
75587           };
75588
75589           photos.allPhotoTypes = function () {
75590             return _allPhotoTypes;
75591           };
75592
75593           photos.dateFilters = function () {
75594             return _dateFilters;
75595           };
75596
75597           photos.dateFilterValue = function (val) {
75598             return val === _dateFilters[0] ? _fromDate : _toDate;
75599           };
75600
75601           photos.setDateFilter = function (type, val, updateUrl) {
75602             // validate the date
75603             var date = val && new Date(val);
75604
75605             if (date && !isNaN(date)) {
75606               val = date.toISOString().substr(0, 10);
75607             } else {
75608               val = null;
75609             }
75610
75611             if (type === _dateFilters[0]) {
75612               _fromDate = val;
75613
75614               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
75615                 _toDate = _fromDate;
75616               }
75617             }
75618
75619             if (type === _dateFilters[1]) {
75620               _toDate = val;
75621
75622               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
75623                 _fromDate = _toDate;
75624               }
75625             }
75626
75627             dispatch$1.call('change', this);
75628
75629             if (updateUrl) {
75630               var rangeString;
75631
75632               if (_fromDate || _toDate) {
75633                 rangeString = (_fromDate || '') + '_' + (_toDate || '');
75634               }
75635
75636               setUrlFilterValue('photo_dates', rangeString);
75637             }
75638           };
75639
75640           photos.setUsernameFilter = function (val, updateUrl) {
75641             if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
75642
75643             if (val) {
75644               val = val.map(function (d) {
75645                 return d.trim();
75646               }).filter(Boolean);
75647
75648               if (!val.length) {
75649                 val = null;
75650               }
75651             }
75652
75653             _usernames = val;
75654             dispatch$1.call('change', this);
75655
75656             if (updateUrl) {
75657               var hashString;
75658
75659               if (_usernames) {
75660                 hashString = _usernames.join(',');
75661               }
75662
75663               setUrlFilterValue('photo_username', hashString);
75664             }
75665           };
75666
75667           function setUrlFilterValue(property, val) {
75668             if (!window.mocha) {
75669               var hash = utilStringQs(window.location.hash);
75670
75671               if (val) {
75672                 if (hash[property] === val) return;
75673                 hash[property] = val;
75674               } else {
75675                 if (!(property in hash)) return;
75676                 delete hash[property];
75677               }
75678
75679               window.location.replace('#' + utilQsString(hash, true));
75680             }
75681           }
75682
75683           function showsLayer(id) {
75684             var layer = context.layers().layer(id);
75685             return layer && layer.supported() && layer.enabled();
75686           }
75687
75688           photos.shouldFilterByDate = function () {
75689             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
75690           };
75691
75692           photos.shouldFilterByPhotoType = function () {
75693             return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
75694           };
75695
75696           photos.shouldFilterByUsername = function () {
75697             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
75698           };
75699
75700           photos.showsPhotoType = function (val) {
75701             if (!photos.shouldFilterByPhotoType()) return true;
75702             return _shownPhotoTypes.indexOf(val) !== -1;
75703           };
75704
75705           photos.showsFlat = function () {
75706             return photos.showsPhotoType('flat');
75707           };
75708
75709           photos.showsPanoramic = function () {
75710             return photos.showsPhotoType('panoramic');
75711           };
75712
75713           photos.fromDate = function () {
75714             return _fromDate;
75715           };
75716
75717           photos.toDate = function () {
75718             return _toDate;
75719           };
75720
75721           photos.togglePhotoType = function (val) {
75722             var index = _shownPhotoTypes.indexOf(val);
75723
75724             if (index !== -1) {
75725               _shownPhotoTypes.splice(index, 1);
75726             } else {
75727               _shownPhotoTypes.push(val);
75728             }
75729
75730             dispatch$1.call('change', this);
75731             return photos;
75732           };
75733
75734           photos.usernames = function () {
75735             return _usernames;
75736           };
75737
75738           photos.init = function () {
75739             var hash = utilStringQs(window.location.hash);
75740
75741             if (hash.photo_dates) {
75742               // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
75743               var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
75744               this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
75745               this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
75746             }
75747
75748             if (hash.photo_username) {
75749               this.setUsernameFilter(hash.photo_username, false);
75750             }
75751
75752             if (hash.photo_overlay) {
75753               // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
75754               var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
75755               hashOverlayIDs.forEach(function (id) {
75756                 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
75757                 if (layer && !layer.enabled()) layer.enabled(true);
75758               });
75759             }
75760
75761             if (hash.photo) {
75762               // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
75763               var photoIds = hash.photo.replace(/;/g, ',').split(',');
75764               var photoId = photoIds.length && photoIds[0].trim();
75765               var results = /(.*)\/(.*)/g.exec(photoId);
75766
75767               if (results && results.length >= 3) {
75768                 var serviceId = results[1];
75769                 var photoKey = results[2];
75770                 var service = services[serviceId];
75771
75772                 if (service && service.ensureViewerLoaded) {
75773                   // if we're showing a photo then make sure its layer is enabled too
75774                   var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
75775                   if (layer && !layer.enabled()) layer.enabled(true);
75776                   var baselineTime = Date.now();
75777                   service.on('loadedImages.rendererPhotos', function () {
75778                     // don't open the viewer if too much time has elapsed
75779                     if (Date.now() - baselineTime > 45000) {
75780                       service.on('loadedImages.rendererPhotos', null);
75781                       return;
75782                     }
75783
75784                     if (!service.cachedImage(photoKey)) return;
75785                     service.on('loadedImages.rendererPhotos', null);
75786                     service.ensureViewerLoaded(context).then(function () {
75787                       service.selectImage(context, photoKey).showViewer(context);
75788                     });
75789                   });
75790                 }
75791               }
75792             }
75793
75794             context.layers().on('change.rendererPhotos', updateStorage);
75795           };
75796
75797           return utilRebind(photos, dispatch$1, 'on');
75798         }
75799
75800         function uiAccount(context) {
75801           var osm = context.connection();
75802
75803           function update(selection) {
75804             if (!osm) return;
75805
75806             if (!osm.authenticated()) {
75807               selection.selectAll('.userLink, .logoutLink').classed('hide', true);
75808               return;
75809             }
75810
75811             osm.userDetails(function (err, details) {
75812               var userLink = selection.select('.userLink'),
75813                   logoutLink = selection.select('.logoutLink');
75814               userLink.html('');
75815               logoutLink.html('');
75816               if (err || !details) return;
75817               selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
75818
75819               var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
75820
75821               if (details.image_url) {
75822                 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
75823               } else {
75824                 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
75825               } // Add user name
75826
75827
75828               userLinkA.append('span').attr('class', 'label').html(details.display_name);
75829               logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
75830                 d3_event.preventDefault();
75831                 osm.logout();
75832               });
75833             });
75834           }
75835
75836           return function (selection) {
75837             selection.append('li').attr('class', 'userLink').classed('hide', true);
75838             selection.append('li').attr('class', 'logoutLink').classed('hide', true);
75839
75840             if (osm) {
75841               osm.on('change.account', function () {
75842                 update(selection);
75843               });
75844               update(selection);
75845             }
75846           };
75847         }
75848
75849         function uiAttribution(context) {
75850           var _selection = select(null);
75851
75852           function render(selection, data, klass) {
75853             var div = selection.selectAll(".".concat(klass)).data([0]);
75854             div = div.enter().append('div').attr('class', klass).merge(div);
75855             var attributions = div.selectAll('.attribution').data(data, function (d) {
75856               return d.id;
75857             });
75858             attributions.exit().remove();
75859             attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
75860               var attribution = select(nodes[i]);
75861
75862               if (d.terms_html) {
75863                 attribution.html(d.terms_html);
75864                 return;
75865               }
75866
75867               if (d.terms_url) {
75868                 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
75869               }
75870
75871               var sourceID = d.id.replace(/\./g, '<TX_DOT>');
75872               var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
75873                 "default": d.terms_text || d.id || d.name()
75874               });
75875
75876               if (d.icon && !d.overlay) {
75877                 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
75878               }
75879
75880               attribution.append('span').attr('class', 'attribution-text').html(terms_text);
75881             }).merge(attributions);
75882             var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
75883               var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
75884               return notice ? [notice] : [];
75885             });
75886             copyright.exit().remove();
75887             copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
75888             copyright.html(String);
75889           }
75890
75891           function update() {
75892             var baselayer = context.background().baseLayerSource();
75893
75894             _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
75895
75896             var z = context.map().zoom();
75897             var overlays = context.background().overlayLayerSources() || [];
75898
75899             _selection.call(render, overlays.filter(function (s) {
75900               return s.validZoom(z);
75901             }), 'overlay-layer-attribution');
75902           }
75903
75904           return function (selection) {
75905             _selection = selection;
75906             context.background().on('change.attribution', update);
75907             context.map().on('move.attribution', throttle(update, 400, {
75908               leading: false
75909             }));
75910             update();
75911           };
75912         }
75913
75914         function uiContributors(context) {
75915           var osm = context.connection(),
75916               debouncedUpdate = debounce(function () {
75917             update();
75918           }, 1000),
75919               limit = 4,
75920               hidden = false,
75921               wrap = select(null);
75922
75923           function update() {
75924             if (!osm) return;
75925             var users = {},
75926                 entities = context.history().intersects(context.map().extent());
75927             entities.forEach(function (entity) {
75928               if (entity && entity.user) users[entity.user] = true;
75929             });
75930             var u = Object.keys(users),
75931                 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
75932             wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
75933             var userList = select(document.createElement('span'));
75934             userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
75935               return osm.userURL(d);
75936             }).attr('target', '_blank').html(String);
75937
75938             if (u.length > limit) {
75939               var count = select(document.createElement('span'));
75940               var othersNum = u.length - limit + 1;
75941               count.append('a').attr('target', '_blank').attr('href', function () {
75942                 return osm.changesetsURL(context.map().center(), context.map().zoom());
75943               }).html(othersNum);
75944               wrap.append('span').html(_t.html('contributors.truncated_list', {
75945                 n: othersNum,
75946                 users: userList.html(),
75947                 count: count.html()
75948               }));
75949             } else {
75950               wrap.append('span').html(_t.html('contributors.list', {
75951                 users: userList.html()
75952               }));
75953             }
75954
75955             if (!u.length) {
75956               hidden = true;
75957               wrap.transition().style('opacity', 0);
75958             } else if (hidden) {
75959               wrap.transition().style('opacity', 1);
75960             }
75961           }
75962
75963           return function (selection) {
75964             if (!osm) return;
75965             wrap = selection;
75966             update();
75967             osm.on('loaded.contributors', debouncedUpdate);
75968             context.map().on('move.contributors', debouncedUpdate);
75969           };
75970         }
75971
75972         var _popoverID = 0;
75973         function uiPopover(klass) {
75974           var _id = _popoverID++;
75975
75976           var _anchorSelection = select(null);
75977
75978           var popover = function popover(selection) {
75979             _anchorSelection = selection;
75980             selection.each(setup);
75981           };
75982
75983           var _animation = utilFunctor(false);
75984
75985           var _placement = utilFunctor('top'); // top, bottom, left, right
75986
75987
75988           var _alignment = utilFunctor('center'); // leading, center, trailing
75989
75990
75991           var _scrollContainer = utilFunctor(select(null));
75992
75993           var _content;
75994
75995           var _displayType = utilFunctor('');
75996
75997           var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
75998
75999
76000           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
76001
76002           popover.displayType = function (val) {
76003             if (arguments.length) {
76004               _displayType = utilFunctor(val);
76005               return popover;
76006             } else {
76007               return _displayType;
76008             }
76009           };
76010
76011           popover.hasArrow = function (val) {
76012             if (arguments.length) {
76013               _hasArrow = utilFunctor(val);
76014               return popover;
76015             } else {
76016               return _hasArrow;
76017             }
76018           };
76019
76020           popover.placement = function (val) {
76021             if (arguments.length) {
76022               _placement = utilFunctor(val);
76023               return popover;
76024             } else {
76025               return _placement;
76026             }
76027           };
76028
76029           popover.alignment = function (val) {
76030             if (arguments.length) {
76031               _alignment = utilFunctor(val);
76032               return popover;
76033             } else {
76034               return _alignment;
76035             }
76036           };
76037
76038           popover.scrollContainer = function (val) {
76039             if (arguments.length) {
76040               _scrollContainer = utilFunctor(val);
76041               return popover;
76042             } else {
76043               return _scrollContainer;
76044             }
76045           };
76046
76047           popover.content = function (val) {
76048             if (arguments.length) {
76049               _content = val;
76050               return popover;
76051             } else {
76052               return _content;
76053             }
76054           };
76055
76056           popover.isShown = function () {
76057             var popoverSelection = _anchorSelection.select('.popover-' + _id);
76058
76059             return !popoverSelection.empty() && popoverSelection.classed('in');
76060           };
76061
76062           popover.show = function () {
76063             _anchorSelection.each(show);
76064           };
76065
76066           popover.updateContent = function () {
76067             _anchorSelection.each(updateContent);
76068           };
76069
76070           popover.hide = function () {
76071             _anchorSelection.each(hide);
76072           };
76073
76074           popover.toggle = function () {
76075             _anchorSelection.each(toggle);
76076           };
76077
76078           popover.destroy = function (selection, selector) {
76079             // by default, just destroy the current popover
76080             selector = selector || '.popover-' + _id;
76081             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 () {
76082               return this.getAttribute('data-original-title') || this.getAttribute('title');
76083             }).attr('data-original-title', null).selectAll(selector).remove();
76084           };
76085
76086           popover.destroyAny = function (selection) {
76087             selection.call(popover.destroy, '.popover');
76088           };
76089
76090           function setup() {
76091             var anchor = select(this);
76092
76093             var animate = _animation.apply(this, arguments);
76094
76095             var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
76096             var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
76097             enter.append('div').attr('class', 'popover-arrow');
76098             enter.append('div').attr('class', 'popover-inner');
76099             popoverSelection = enter.merge(popoverSelection);
76100
76101             if (animate) {
76102               popoverSelection.classed('fade', true);
76103             }
76104
76105             var display = _displayType.apply(this, arguments);
76106
76107             if (display === 'hover') {
76108               var _lastNonMouseEnterTime;
76109
76110               anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
76111                 if (d3_event.pointerType) {
76112                   if (d3_event.pointerType !== 'mouse') {
76113                     _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
76114
76115                     return;
76116                   } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
76117                     // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
76118                     // event for non-mouse interactions right after sending
76119                     // the correct type pointerenter event. Workaround by discarding
76120                     // any mouse event that occurs immediately after a non-mouse event.
76121                     return;
76122                   }
76123                 } // don't show if buttons are pressed, e.g. during click and drag of map
76124
76125
76126                 if (d3_event.buttons !== 0) return;
76127                 show.apply(this, arguments);
76128               }).on(_pointerPrefix + 'leave.popover', function () {
76129                 hide.apply(this, arguments);
76130               }) // show on focus too for better keyboard navigation support
76131               .on('focus.popover', function () {
76132                 show.apply(this, arguments);
76133               }).on('blur.popover', function () {
76134                 hide.apply(this, arguments);
76135               });
76136             } else if (display === 'clickFocus') {
76137               anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
76138                 d3_event.preventDefault();
76139                 d3_event.stopPropagation();
76140               }).on(_pointerPrefix + 'up.popover', function (d3_event) {
76141                 d3_event.preventDefault();
76142                 d3_event.stopPropagation();
76143               }).on('click.popover', toggle);
76144               popoverSelection // This attribute lets the popover take focus
76145               .attr('tabindex', 0).on('blur.popover', function () {
76146                 anchor.each(function () {
76147                   hide.apply(this, arguments);
76148                 });
76149               });
76150             }
76151           }
76152
76153           function show() {
76154             var anchor = select(this);
76155             var popoverSelection = anchor.selectAll('.popover-' + _id);
76156
76157             if (popoverSelection.empty()) {
76158               // popover was removed somehow, put it back
76159               anchor.call(popover.destroy);
76160               anchor.each(setup);
76161               popoverSelection = anchor.selectAll('.popover-' + _id);
76162             }
76163
76164             popoverSelection.classed('in', true);
76165
76166             var displayType = _displayType.apply(this, arguments);
76167
76168             if (displayType === 'clickFocus') {
76169               anchor.classed('active', true);
76170               popoverSelection.node().focus();
76171             }
76172
76173             anchor.each(updateContent);
76174           }
76175
76176           function updateContent() {
76177             var anchor = select(this);
76178
76179             if (_content) {
76180               anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
76181             }
76182
76183             updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
76184             // set before the dynamic popover size is calculated by the browser
76185
76186             updatePosition.apply(this, arguments);
76187             updatePosition.apply(this, arguments);
76188           }
76189
76190           function updatePosition() {
76191             var anchor = select(this);
76192             var popoverSelection = anchor.selectAll('.popover-' + _id);
76193
76194             var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
76195
76196             var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
76197             var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
76198             var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
76199
76200             var placement = _placement.apply(this, arguments);
76201
76202             popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
76203
76204             var alignment = _alignment.apply(this, arguments);
76205
76206             var alignFactor = 0.5;
76207
76208             if (alignment === 'leading') {
76209               alignFactor = 0;
76210             } else if (alignment === 'trailing') {
76211               alignFactor = 1;
76212             }
76213
76214             var anchorFrame = getFrame(anchor.node());
76215             var popoverFrame = getFrame(popoverSelection.node());
76216             var position;
76217
76218             switch (placement) {
76219               case 'top':
76220                 position = {
76221                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
76222                   y: anchorFrame.y - popoverFrame.h
76223                 };
76224                 break;
76225
76226               case 'bottom':
76227                 position = {
76228                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
76229                   y: anchorFrame.y + anchorFrame.h
76230                 };
76231                 break;
76232
76233               case 'left':
76234                 position = {
76235                   x: anchorFrame.x - popoverFrame.w,
76236                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
76237                 };
76238                 break;
76239
76240               case 'right':
76241                 position = {
76242                   x: anchorFrame.x + anchorFrame.w,
76243                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
76244                 };
76245                 break;
76246             }
76247
76248             if (position) {
76249               if (scrollNode && (placement === 'top' || placement === 'bottom')) {
76250                 var initialPosX = position.x;
76251
76252                 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
76253                   position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
76254                 } else if (position.x < 10) {
76255                   position.x = 10;
76256                 }
76257
76258                 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
76259
76260                 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
76261                 arrow.style('left', ~~arrowPosX + 'px');
76262               }
76263
76264               popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
76265             } else {
76266               popoverSelection.style('left', null).style('top', null);
76267             }
76268
76269             function getFrame(node) {
76270               var positionStyle = select(node).style('position');
76271
76272               if (positionStyle === 'absolute' || positionStyle === 'static') {
76273                 return {
76274                   x: node.offsetLeft - scrollLeft,
76275                   y: node.offsetTop - scrollTop,
76276                   w: node.offsetWidth,
76277                   h: node.offsetHeight
76278                 };
76279               } else {
76280                 return {
76281                   x: 0,
76282                   y: 0,
76283                   w: node.offsetWidth,
76284                   h: node.offsetHeight
76285                 };
76286               }
76287             }
76288           }
76289
76290           function hide() {
76291             var anchor = select(this);
76292
76293             if (_displayType.apply(this, arguments) === 'clickFocus') {
76294               anchor.classed('active', false);
76295             }
76296
76297             anchor.selectAll('.popover-' + _id).classed('in', false);
76298           }
76299
76300           function toggle() {
76301             if (select(this).select('.popover-' + _id).classed('in')) {
76302               hide.apply(this, arguments);
76303             } else {
76304               show.apply(this, arguments);
76305             }
76306           }
76307
76308           return popover;
76309         }
76310
76311         function uiTooltip(klass) {
76312           var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
76313
76314           var _title = function _title() {
76315             var title = this.getAttribute('data-original-title');
76316
76317             if (title) {
76318               return title;
76319             } else {
76320               title = this.getAttribute('title');
76321               this.removeAttribute('title');
76322               this.setAttribute('data-original-title', title);
76323             }
76324
76325             return title;
76326           };
76327
76328           var _heading = utilFunctor(null);
76329
76330           var _keys = utilFunctor(null);
76331
76332           tooltip.title = function (val) {
76333             if (!arguments.length) return _title;
76334             _title = utilFunctor(val);
76335             return tooltip;
76336           };
76337
76338           tooltip.heading = function (val) {
76339             if (!arguments.length) return _heading;
76340             _heading = utilFunctor(val);
76341             return tooltip;
76342           };
76343
76344           tooltip.keys = function (val) {
76345             if (!arguments.length) return _keys;
76346             _keys = utilFunctor(val);
76347             return tooltip;
76348           };
76349
76350           tooltip.content(function () {
76351             var heading = _heading.apply(this, arguments);
76352
76353             var text = _title.apply(this, arguments);
76354
76355             var keys = _keys.apply(this, arguments);
76356
76357             return function (selection) {
76358               var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
76359               headingSelect.exit().remove();
76360               headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
76361               var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
76362               textSelect.exit().remove();
76363               textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
76364               var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
76365               keyhintWrap.exit().remove();
76366               var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
76367               keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
76368               keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
76369               keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
76370                 return d;
76371               });
76372             };
76373           });
76374           return tooltip;
76375         }
76376
76377         function uiEditMenu(context) {
76378           var dispatch$1 = dispatch('toggled');
76379
76380           var _menu = select(null);
76381
76382           var _operations = []; // the position the menu should be displayed relative to
76383
76384           var _anchorLoc = [0, 0];
76385           var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
76386
76387           var _triggerType = '';
76388           var _vpTopMargin = 85; // viewport top margin
76389
76390           var _vpBottomMargin = 45; // viewport bottom margin
76391
76392           var _vpSideMargin = 35; // viewport side margin
76393
76394           var _menuTop = false;
76395
76396           var _menuHeight;
76397
76398           var _menuWidth; // hardcode these values to make menu positioning easier
76399
76400
76401           var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
76402
76403           var _tooltipWidth = 210; // offset the menu slightly from the target location
76404
76405           var _menuSideMargin = 10;
76406           var _tooltips = [];
76407
76408           var editMenu = function editMenu(selection) {
76409             var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
76410
76411             var ops = _operations.filter(function (op) {
76412               return !isTouchMenu || !op.mouseOnly;
76413             });
76414
76415             if (!ops.length) return;
76416             _tooltips = []; // Position the menu above the anchor for stylus and finger input
76417             // since the mapper's hand likely obscures the screen below the anchor
76418
76419             _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
76420
76421             var showLabels = isTouchMenu;
76422             var buttonHeight = showLabels ? 32 : 34;
76423
76424             if (showLabels) {
76425               // Get a general idea of the width based on the length of the label
76426               _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
76427                 return op.title.length;
76428               })));
76429             } else {
76430               _menuWidth = 44;
76431             }
76432
76433             _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
76434             _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
76435
76436             var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
76437
76438
76439             var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
76440               return 'edit-menu-item edit-menu-item-' + d.id;
76441             }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
76442             .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
76443               // don't let button presses also act as map input - #1869
76444               d3_event.stopPropagation();
76445             }).on('mouseenter.highlight', function (d3_event, d) {
76446               if (!d.relatedEntityIds || select(this).classed('disabled')) return;
76447               utilHighlightEntities(d.relatedEntityIds(), true, context);
76448             }).on('mouseleave.highlight', function (d3_event, d) {
76449               if (!d.relatedEntityIds) return;
76450               utilHighlightEntities(d.relatedEntityIds(), false, context);
76451             });
76452             buttonsEnter.each(function (d) {
76453               var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
76454
76455               _tooltips.push(tooltip);
76456
76457               select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
76458             });
76459
76460             if (showLabels) {
76461               buttonsEnter.append('span').attr('class', 'label').html(function (d) {
76462                 return d.title;
76463               });
76464             } // update
76465
76466
76467             buttonsEnter.merge(buttons).classed('disabled', function (d) {
76468               return d.disabled();
76469             });
76470             updatePosition();
76471             var initialScale = context.projection.scale();
76472             context.map().on('move.edit-menu', function () {
76473               if (initialScale !== context.projection.scale()) {
76474                 editMenu.close();
76475               }
76476             }).on('drawn.edit-menu', function (info) {
76477               if (info.full) updatePosition();
76478             });
76479             var lastPointerUpType; // `pointerup` is always called before `click`
76480
76481             function pointerup(d3_event) {
76482               lastPointerUpType = d3_event.pointerType;
76483             }
76484
76485             function click(d3_event, operation) {
76486               d3_event.stopPropagation();
76487
76488               if (operation.relatedEntityIds) {
76489                 utilHighlightEntities(operation.relatedEntityIds(), false, context);
76490               }
76491
76492               if (operation.disabled()) {
76493                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
76494                   // there are no tooltips for touch interactions so flash feedback instead
76495                   context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
76496                 }
76497               } else {
76498                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
76499                   context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
76500                 }
76501
76502                 operation();
76503                 editMenu.close();
76504               }
76505
76506               lastPointerUpType = null;
76507             }
76508
76509             dispatch$1.call('toggled', this, true);
76510           };
76511
76512           function updatePosition() {
76513             if (!_menu || _menu.empty()) return;
76514             var anchorLoc = context.projection(_anchorLocLonLat);
76515             var viewport = context.surfaceRect();
76516
76517             if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
76518               // close the menu if it's gone offscreen
76519               editMenu.close();
76520               return;
76521             }
76522
76523             var menuLeft = displayOnLeft(viewport);
76524             var offset = [0, 0];
76525             offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
76526
76527             if (_menuTop) {
76528               if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
76529                 // menu is near top viewport edge, shift downward
76530                 offset[1] = -anchorLoc[1] + _vpTopMargin;
76531               } else {
76532                 offset[1] = -_menuHeight;
76533               }
76534             } else {
76535               if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
76536                 // menu is near bottom viewport edge, shift upwards
76537                 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
76538               } else {
76539                 offset[1] = 0;
76540               }
76541             }
76542
76543             var origin = geoVecAdd(anchorLoc, offset);
76544
76545             _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
76546
76547             var tooltipSide = tooltipPosition(viewport, menuLeft);
76548
76549             _tooltips.forEach(function (tooltip) {
76550               tooltip.placement(tooltipSide);
76551             });
76552
76553             function displayOnLeft(viewport) {
76554               if (_mainLocalizer.textDirection() === 'ltr') {
76555                 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
76556                   // right menu would be too close to the right viewport edge, go left
76557                   return true;
76558                 } // prefer right menu
76559
76560
76561                 return false;
76562               } else {
76563                 // rtl
76564                 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
76565                   // left menu would be too close to the left viewport edge, go right
76566                   return false;
76567                 } // prefer left menu
76568
76569
76570                 return true;
76571               }
76572             }
76573
76574             function tooltipPosition(viewport, menuLeft) {
76575               if (_mainLocalizer.textDirection() === 'ltr') {
76576                 if (menuLeft) {
76577                   // if there's not room for a right-side menu then there definitely
76578                   // isn't room for right-side tooltips
76579                   return 'left';
76580                 }
76581
76582                 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
76583                   // right tooltips would be too close to the right viewport edge, go left
76584                   return 'left';
76585                 } // prefer right tooltips
76586
76587
76588                 return 'right';
76589               } else {
76590                 // rtl
76591                 if (!menuLeft) {
76592                   return 'right';
76593                 }
76594
76595                 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
76596                   // left tooltips would be too close to the left viewport edge, go right
76597                   return 'right';
76598                 } // prefer left tooltips
76599
76600
76601                 return 'left';
76602               }
76603             }
76604           }
76605
76606           editMenu.close = function () {
76607             context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
76608
76609             _menu.remove();
76610
76611             _tooltips = [];
76612             dispatch$1.call('toggled', this, false);
76613           };
76614
76615           editMenu.anchorLoc = function (val) {
76616             if (!arguments.length) return _anchorLoc;
76617             _anchorLoc = val;
76618             _anchorLocLonLat = context.projection.invert(_anchorLoc);
76619             return editMenu;
76620           };
76621
76622           editMenu.triggerType = function (val) {
76623             if (!arguments.length) return _triggerType;
76624             _triggerType = val;
76625             return editMenu;
76626           };
76627
76628           editMenu.operations = function (val) {
76629             if (!arguments.length) return _operations;
76630             _operations = val;
76631             return editMenu;
76632           };
76633
76634           return utilRebind(editMenu, dispatch$1, 'on');
76635         }
76636
76637         function uiFeatureInfo(context) {
76638           function update(selection) {
76639             var features = context.features();
76640             var stats = features.stats();
76641             var count = 0;
76642             var hiddenList = features.hidden().map(function (k) {
76643               if (stats[k]) {
76644                 count += stats[k];
76645                 return _t('inspector.title_count', {
76646                   title: _t.html('feature.' + k + '.description'),
76647                   count: stats[k]
76648                 });
76649               }
76650
76651               return null;
76652             }).filter(Boolean);
76653             selection.html('');
76654
76655             if (hiddenList.length) {
76656               var tooltipBehavior = uiTooltip().placement('top').title(function () {
76657                 return hiddenList.join('<br/>');
76658               });
76659               selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
76660                 count: count
76661               })).call(tooltipBehavior).on('click', function (d3_event) {
76662                 tooltipBehavior.hide();
76663                 d3_event.preventDefault(); // open the Map Data pane
76664
76665                 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
76666               });
76667             }
76668
76669             selection.classed('hide', !hiddenList.length);
76670           }
76671
76672           return function (selection) {
76673             update(selection);
76674             context.features().on('change.feature_info', function () {
76675               update(selection);
76676             });
76677           };
76678         }
76679
76680         function uiFlash(context) {
76681           var _flashTimer;
76682
76683           var _duration = 2000;
76684           var _iconName = '#iD-icon-no';
76685           var _iconClass = 'disabled';
76686           var _label = '';
76687
76688           function flash() {
76689             if (_flashTimer) {
76690               _flashTimer.stop();
76691             }
76692
76693             context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
76694             context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
76695             var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
76696
76697             var contentEnter = content.enter().append('div').attr('class', 'flash-content');
76698             var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
76699             iconEnter.append('circle').attr('r', 9);
76700             iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
76701             contentEnter.append('div').attr('class', 'flash-text'); // Update
76702
76703             content = content.merge(contentEnter);
76704             content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
76705             content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
76706             content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
76707             _flashTimer = d3_timeout(function () {
76708               _flashTimer = null;
76709               context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
76710               context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
76711             }, _duration);
76712             return content;
76713           }
76714
76715           flash.duration = function (_) {
76716             if (!arguments.length) return _duration;
76717             _duration = _;
76718             return flash;
76719           };
76720
76721           flash.label = function (_) {
76722             if (!arguments.length) return _label;
76723             _label = _;
76724             return flash;
76725           };
76726
76727           flash.iconName = function (_) {
76728             if (!arguments.length) return _iconName;
76729             _iconName = _;
76730             return flash;
76731           };
76732
76733           flash.iconClass = function (_) {
76734             if (!arguments.length) return _iconClass;
76735             _iconClass = _;
76736             return flash;
76737           };
76738
76739           return flash;
76740         }
76741
76742         function uiFullScreen(context) {
76743           var element = context.container().node(); // var button = d3_select(null);
76744
76745           function getFullScreenFn() {
76746             if (element.requestFullscreen) {
76747               return element.requestFullscreen;
76748             } else if (element.msRequestFullscreen) {
76749               return element.msRequestFullscreen;
76750             } else if (element.mozRequestFullScreen) {
76751               return element.mozRequestFullScreen;
76752             } else if (element.webkitRequestFullscreen) {
76753               return element.webkitRequestFullscreen;
76754             }
76755           }
76756
76757           function getExitFullScreenFn() {
76758             if (document.exitFullscreen) {
76759               return document.exitFullscreen;
76760             } else if (document.msExitFullscreen) {
76761               return document.msExitFullscreen;
76762             } else if (document.mozCancelFullScreen) {
76763               return document.mozCancelFullScreen;
76764             } else if (document.webkitExitFullscreen) {
76765               return document.webkitExitFullscreen;
76766             }
76767           }
76768
76769           function isFullScreen() {
76770             return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
76771           }
76772
76773           function isSupported() {
76774             return !!getFullScreenFn();
76775           }
76776
76777           function fullScreen(d3_event) {
76778             d3_event.preventDefault();
76779
76780             if (!isFullScreen()) {
76781               // button.classed('active', true);
76782               getFullScreenFn().apply(element);
76783             } else {
76784               // button.classed('active', false);
76785               getExitFullScreenFn().apply(document);
76786             }
76787           }
76788
76789           return function () {
76790             // selection) {
76791             if (!isSupported()) return; // button = selection.append('button')
76792             //     .attr('title', t('full_screen'))
76793             //     .on('click', fullScreen)
76794             //     .call(tooltip);
76795             // button.append('span')
76796             //     .attr('class', 'icon full-screen');
76797
76798             var detected = utilDetect();
76799             var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
76800             context.keybinding().on(keys, fullScreen);
76801           };
76802         }
76803
76804         function uiGeolocate(context) {
76805           var _geolocationOptions = {
76806             // prioritize speed and power usage over precision
76807             enableHighAccuracy: false,
76808             // don't hang indefinitely getting the location
76809             timeout: 6000 // 6sec
76810
76811           };
76812
76813           var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
76814
76815           var _layer = context.layers().layer('geolocate');
76816
76817           var _position;
76818
76819           var _extent;
76820
76821           var _timeoutID;
76822
76823           var _button = select(null);
76824
76825           function click() {
76826             if (context.inIntro()) return;
76827
76828             if (!_layer.enabled() && !_locating.isShown()) {
76829               // This timeout ensures that we still call finish() even if
76830               // the user declines to share their location in Firefox
76831               _timeoutID = setTimeout(error, 10000
76832               /* 10sec */
76833               );
76834               context.container().call(_locating); // get the latest position even if we already have one
76835
76836               navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
76837             } else {
76838               _locating.close();
76839
76840               _layer.enabled(null, false);
76841
76842               updateButtonState();
76843             }
76844           }
76845
76846           function zoomTo() {
76847             context.enter(modeBrowse(context));
76848             var map = context.map();
76849
76850             _layer.enabled(_position, true);
76851
76852             updateButtonState();
76853             map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
76854           }
76855
76856           function success(geolocation) {
76857             _position = geolocation;
76858             var coords = _position.coords;
76859             _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
76860             zoomTo();
76861             finish();
76862           }
76863
76864           function error() {
76865             if (_position) {
76866               // use the position from a previous call if we have one
76867               zoomTo();
76868             } else {
76869               context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
76870             }
76871
76872             finish();
76873           }
76874
76875           function finish() {
76876             _locating.close(); // unblock ui
76877
76878
76879             if (_timeoutID) {
76880               clearTimeout(_timeoutID);
76881             }
76882
76883             _timeoutID = undefined;
76884           }
76885
76886           function updateButtonState() {
76887             _button.classed('active', _layer.enabled());
76888           }
76889
76890           return function (selection) {
76891             if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
76892             _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')]));
76893             context.keybinding().on(_t('geolocate.key'), click);
76894           };
76895         }
76896
76897         function uiPanelBackground(context) {
76898           var background = context.background();
76899           var _currSourceName = null;
76900           var _metadata = {};
76901           var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
76902
76903           var debouncedRedraw = debounce(redraw, 250);
76904
76905           function redraw(selection) {
76906             var source = background.baseLayerSource();
76907             if (!source) return;
76908             var isDG = source.id.match(/^DigitalGlobe/i) !== null;
76909             var sourceLabel = source.label();
76910
76911             if (_currSourceName !== sourceLabel) {
76912               _currSourceName = sourceLabel;
76913               _metadata = {};
76914             }
76915
76916             selection.html('');
76917             var list = selection.append('ul').attr('class', 'background-info');
76918             list.append('li').html(_currSourceName);
76919
76920             _metadataKeys.forEach(function (k) {
76921               // DigitalGlobe vintage is available in raster layers for now.
76922               if (isDG && k === 'vintage') return;
76923               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]);
76924             });
76925
76926             debouncedGetMetadata(selection);
76927             var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
76928             selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
76929               d3_event.preventDefault();
76930               context.setDebug('tile', !context.getDebug('tile'));
76931               selection.call(redraw);
76932             });
76933
76934             if (isDG) {
76935               var key = source.id + '-vintage';
76936               var sourceVintage = context.background().findSource(key);
76937               var showsVintage = context.background().showsLayer(sourceVintage);
76938               var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
76939               selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
76940                 d3_event.preventDefault();
76941                 context.background().toggleOverlayLayer(sourceVintage);
76942                 selection.call(redraw);
76943               });
76944             } // disable if necessary
76945
76946
76947             ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
76948               if (source.id !== layerId) {
76949                 var key = layerId + '-vintage';
76950                 var sourceVintage = context.background().findSource(key);
76951
76952                 if (context.background().showsLayer(sourceVintage)) {
76953                   context.background().toggleOverlayLayer(sourceVintage);
76954                 }
76955               }
76956             });
76957           }
76958
76959           var debouncedGetMetadata = debounce(getMetadata, 250);
76960
76961           function getMetadata(selection) {
76962             var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
76963
76964             if (tile.empty()) return;
76965             var sourceName = _currSourceName;
76966             var d = tile.datum();
76967             var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
76968             var center = context.map().center(); // update zoom
76969
76970             _metadata.zoom = String(zoom);
76971             selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
76972             if (!d || !d.length >= 3) return;
76973             background.baseLayerSource().getMetadata(center, d, function (err, result) {
76974               if (err || _currSourceName !== sourceName) return; // update vintage
76975
76976               var vintage = result.vintage;
76977               _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
76978               selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
76979
76980               _metadataKeys.forEach(function (k) {
76981                 if (k === 'zoom' || k === 'vintage') return; // done already
76982
76983                 var val = result[k];
76984                 _metadata[k] = val;
76985                 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
76986               });
76987             });
76988           }
76989
76990           var panel = function panel(selection) {
76991             selection.call(redraw);
76992             context.map().on('drawn.info-background', function () {
76993               selection.call(debouncedRedraw);
76994             }).on('move.info-background', function () {
76995               selection.call(debouncedGetMetadata);
76996             });
76997           };
76998
76999           panel.off = function () {
77000             context.map().on('drawn.info-background', null).on('move.info-background', null);
77001           };
77002
77003           panel.id = 'background';
77004           panel.label = _t.html('info_panels.background.title');
77005           panel.key = _t('info_panels.background.key');
77006           return panel;
77007         }
77008
77009         function uiPanelHistory(context) {
77010           var osm;
77011
77012           function displayTimestamp(timestamp) {
77013             if (!timestamp) return _t('info_panels.history.unknown');
77014             var options = {
77015               day: 'numeric',
77016               month: 'short',
77017               year: 'numeric',
77018               hour: 'numeric',
77019               minute: 'numeric',
77020               second: 'numeric'
77021             };
77022             var d = new Date(timestamp);
77023             if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
77024             return d.toLocaleString(_mainLocalizer.localeCode(), options);
77025           }
77026
77027           function displayUser(selection, userName) {
77028             if (!userName) {
77029               selection.append('span').html(_t.html('info_panels.history.unknown'));
77030               return;
77031             }
77032
77033             selection.append('span').attr('class', 'user-name').html(userName);
77034             var links = selection.append('div').attr('class', 'links');
77035
77036             if (osm) {
77037               links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
77038             }
77039
77040             links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
77041           }
77042
77043           function displayChangeset(selection, changeset) {
77044             if (!changeset) {
77045               selection.append('span').html(_t.html('info_panels.history.unknown'));
77046               return;
77047             }
77048
77049             selection.append('span').attr('class', 'changeset-id').html(changeset);
77050             var links = selection.append('div').attr('class', 'links');
77051
77052             if (osm) {
77053               links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
77054             }
77055
77056             links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
77057             links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
77058           }
77059
77060           function redraw(selection) {
77061             var selectedNoteID = context.selectedNoteID();
77062             osm = context.connection();
77063             var selected, note, entity;
77064
77065             if (selectedNoteID && osm) {
77066               // selected 1 note
77067               selected = [_t('note.note') + ' ' + selectedNoteID];
77068               note = osm.getNote(selectedNoteID);
77069             } else {
77070               // selected 1..n entities
77071               selected = context.selectedIDs().filter(function (e) {
77072                 return context.hasEntity(e);
77073               });
77074
77075               if (selected.length) {
77076                 entity = context.entity(selected[0]);
77077               }
77078             }
77079
77080             var singular = selected.length === 1 ? selected[0] : null;
77081             selection.html('');
77082             selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
77083               n: selected.length
77084             }));
77085             if (!singular) return;
77086
77087             if (entity) {
77088               selection.call(redrawEntity, entity);
77089             } else if (note) {
77090               selection.call(redrawNote, note);
77091             }
77092           }
77093
77094           function redrawNote(selection, note) {
77095             if (!note || note.isNew()) {
77096               selection.append('div').html(_t.html('info_panels.history.note_no_history'));
77097               return;
77098             }
77099
77100             var list = selection.append('ul');
77101             list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
77102
77103             if (note.comments.length) {
77104               list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
77105               list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
77106             }
77107
77108             if (osm) {
77109               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'));
77110             }
77111           }
77112
77113           function redrawEntity(selection, entity) {
77114             if (!entity || entity.isNew()) {
77115               selection.append('div').html(_t.html('info_panels.history.no_history'));
77116               return;
77117             }
77118
77119             var links = selection.append('div').attr('class', 'links');
77120
77121             if (osm) {
77122               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');
77123             }
77124
77125             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');
77126             var list = selection.append('ul');
77127             list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
77128             list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
77129             list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
77130             list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
77131           }
77132
77133           var panel = function panel(selection) {
77134             selection.call(redraw);
77135             context.map().on('drawn.info-history', function () {
77136               selection.call(redraw);
77137             });
77138             context.on('enter.info-history', function () {
77139               selection.call(redraw);
77140             });
77141           };
77142
77143           panel.off = function () {
77144             context.map().on('drawn.info-history', null);
77145             context.on('enter.info-history', null);
77146           };
77147
77148           panel.id = 'history';
77149           panel.label = _t.html('info_panels.history.title');
77150           panel.key = _t('info_panels.history.key');
77151           return panel;
77152         }
77153
77154         var OSM_PRECISION = 7;
77155         /**
77156          * Returns a localized representation of the given length measurement.
77157          *
77158          * @param {Number} m area in meters
77159          * @param {Boolean} isImperial true for U.S. customary units; false for metric
77160          */
77161
77162         function displayLength(m, isImperial) {
77163           var d = m * (isImperial ? 3.28084 : 1);
77164           var unit;
77165
77166           if (isImperial) {
77167             if (d >= 5280) {
77168               d /= 5280;
77169               unit = 'miles';
77170             } else {
77171               unit = 'feet';
77172             }
77173           } else {
77174             if (d >= 1000) {
77175               d /= 1000;
77176               unit = 'kilometers';
77177             } else {
77178               unit = 'meters';
77179             }
77180           }
77181
77182           return _t('units.' + unit, {
77183             quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
77184               maximumSignificantDigits: 4
77185             })
77186           });
77187         }
77188         /**
77189          * Returns a localized representation of the given area measurement.
77190          *
77191          * @param {Number} m2 area in square meters
77192          * @param {Boolean} isImperial true for U.S. customary units; false for metric
77193          */
77194
77195         function displayArea(m2, isImperial) {
77196           var locale = _mainLocalizer.localeCode();
77197           var d = m2 * (isImperial ? 10.7639111056 : 1);
77198           var d1, d2, area;
77199           var unit1 = '';
77200           var unit2 = '';
77201
77202           if (isImperial) {
77203             if (d >= 6969600) {
77204               // > 0.25mi² show mi²
77205               d1 = d / 27878400;
77206               unit1 = 'square_miles';
77207             } else {
77208               d1 = d;
77209               unit1 = 'square_feet';
77210             }
77211
77212             if (d > 4356 && d < 43560000) {
77213               // 0.1 - 1000 acres
77214               d2 = d / 43560;
77215               unit2 = 'acres';
77216             }
77217           } else {
77218             if (d >= 250000) {
77219               // > 0.25km² show km²
77220               d1 = d / 1000000;
77221               unit1 = 'square_kilometers';
77222             } else {
77223               d1 = d;
77224               unit1 = 'square_meters';
77225             }
77226
77227             if (d > 1000 && d < 10000000) {
77228               // 0.1 - 1000 hectares
77229               d2 = d / 10000;
77230               unit2 = 'hectares';
77231             }
77232           }
77233
77234           area = _t('units.' + unit1, {
77235             quantity: d1.toLocaleString(locale, {
77236               maximumSignificantDigits: 4
77237             })
77238           });
77239
77240           if (d2) {
77241             return _t('units.area_pair', {
77242               area1: area,
77243               area2: _t('units.' + unit2, {
77244                 quantity: d2.toLocaleString(locale, {
77245                   maximumSignificantDigits: 2
77246                 })
77247               })
77248             });
77249           } else {
77250             return area;
77251           }
77252         }
77253
77254         function wrap$2(x, min, max) {
77255           var d = max - min;
77256           return ((x - min) % d + d) % d + min;
77257         }
77258
77259         function clamp$1(x, min, max) {
77260           return Math.max(min, Math.min(x, max));
77261         }
77262
77263         function displayCoordinate(deg, pos, neg) {
77264           var locale = _mainLocalizer.localeCode();
77265           var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
77266           var sec = (min - Math.floor(min)) * 60;
77267           var displayDegrees = _t('units.arcdegrees', {
77268             quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
77269           });
77270           var displayCoordinate;
77271
77272           if (Math.floor(sec) > 0) {
77273             displayCoordinate = displayDegrees + _t('units.arcminutes', {
77274               quantity: Math.floor(min).toLocaleString(locale)
77275             }) + _t('units.arcseconds', {
77276               quantity: Math.round(sec).toLocaleString(locale)
77277             });
77278           } else if (Math.floor(min) > 0) {
77279             displayCoordinate = displayDegrees + _t('units.arcminutes', {
77280               quantity: Math.round(min).toLocaleString(locale)
77281             });
77282           } else {
77283             displayCoordinate = _t('units.arcdegrees', {
77284               quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
77285             });
77286           }
77287
77288           if (deg === 0) {
77289             return displayCoordinate;
77290           } else {
77291             return _t('units.coordinate', {
77292               coordinate: displayCoordinate,
77293               direction: _t('units.' + (deg > 0 ? pos : neg))
77294             });
77295           }
77296         }
77297         /**
77298          * Returns given coordinate pair in degree-minute-second format.
77299          *
77300          * @param {Array<Number>} coord longitude and latitude
77301          */
77302
77303
77304         function dmsCoordinatePair(coord) {
77305           return _t('units.coordinate_pair', {
77306             latitude: displayCoordinate(clamp$1(coord[1], -90, 90), 'north', 'south'),
77307             longitude: displayCoordinate(wrap$2(coord[0], -180, 180), 'east', 'west')
77308           });
77309         }
77310         /**
77311          * Returns the given coordinate pair in decimal format.
77312          * note: unlocalized to avoid comma ambiguity - see #4765
77313          *
77314          * @param {Array<Number>} coord longitude and latitude
77315          */
77316
77317         function decimalCoordinatePair(coord) {
77318           return _t('units.coordinate_pair', {
77319             latitude: clamp$1(coord[1], -90, 90).toFixed(OSM_PRECISION),
77320             longitude: wrap$2(coord[0], -180, 180).toFixed(OSM_PRECISION)
77321           });
77322         }
77323
77324         function uiPanelLocation(context) {
77325           var currLocation = '';
77326
77327           function redraw(selection) {
77328             selection.html('');
77329             var list = selection.append('ul'); // Mouse coordinates
77330
77331             var coord = context.map().mouseCoordinates();
77332
77333             if (coord.some(isNaN)) {
77334               coord = context.map().center();
77335             }
77336
77337             list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
77338
77339             selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
77340             debouncedGetLocation(selection, coord);
77341           }
77342
77343           var debouncedGetLocation = debounce(getLocation, 250);
77344
77345           function getLocation(selection, coord) {
77346             if (!services.geocoder) {
77347               currLocation = _t('info_panels.location.unknown_location');
77348               selection.selectAll('.location-info').html(currLocation);
77349             } else {
77350               services.geocoder.reverse(coord, function (err, result) {
77351                 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
77352                 selection.selectAll('.location-info').html(currLocation);
77353               });
77354             }
77355           }
77356
77357           var panel = function panel(selection) {
77358             selection.call(redraw);
77359             context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
77360               selection.call(redraw);
77361             });
77362           };
77363
77364           panel.off = function () {
77365             context.surface().on('.info-location', null);
77366           };
77367
77368           panel.id = 'location';
77369           panel.label = _t.html('info_panels.location.title');
77370           panel.key = _t('info_panels.location.key');
77371           return panel;
77372         }
77373
77374         function uiPanelMeasurement(context) {
77375           function radiansToMeters(r) {
77376             // using WGS84 authalic radius (6371007.1809 m)
77377             return r * 6371007.1809;
77378           }
77379
77380           function steradiansToSqmeters(r) {
77381             // http://gis.stackexchange.com/a/124857/40446
77382             return r / (4 * Math.PI) * 510065621724000;
77383           }
77384
77385           function toLineString(feature) {
77386             if (feature.type === 'LineString') return feature;
77387             var result = {
77388               type: 'LineString',
77389               coordinates: []
77390             };
77391
77392             if (feature.type === 'Polygon') {
77393               result.coordinates = feature.coordinates[0];
77394             } else if (feature.type === 'MultiPolygon') {
77395               result.coordinates = feature.coordinates[0][0];
77396             }
77397
77398             return result;
77399           }
77400
77401           var _isImperial = !_mainLocalizer.usesMetric();
77402
77403           function redraw(selection) {
77404             var graph = context.graph();
77405             var selectedNoteID = context.selectedNoteID();
77406             var osm = services.osm;
77407             var localeCode = _mainLocalizer.localeCode();
77408             var heading;
77409             var center, location, centroid;
77410             var closed, geometry;
77411             var totalNodeCount,
77412                 length = 0,
77413                 area = 0,
77414                 distance;
77415
77416             if (selectedNoteID && osm) {
77417               // selected 1 note
77418               var note = osm.getNote(selectedNoteID);
77419               heading = _t('note.note') + ' ' + selectedNoteID;
77420               location = note.loc;
77421               geometry = 'note';
77422             } else {
77423               // selected 1..n entities
77424               var selectedIDs = context.selectedIDs().filter(function (id) {
77425                 return context.hasEntity(id);
77426               });
77427               var selected = selectedIDs.map(function (id) {
77428                 return context.entity(id);
77429               });
77430               heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
77431                 n: selected.length
77432               });
77433
77434               if (selected.length) {
77435                 var extent = geoExtent();
77436
77437                 for (var i in selected) {
77438                   var entity = selected[i];
77439
77440                   extent._extend(entity.extent(graph));
77441
77442                   geometry = entity.geometry(graph);
77443
77444                   if (geometry === 'line' || geometry === 'area') {
77445                     closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
77446                     var feature = entity.asGeoJSON(graph);
77447                     length += radiansToMeters(d3_geoLength(toLineString(feature))); // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
77448
77449                     centroid = d3_geoCentroid(geojsonRewind(Object.assign({}, feature), true));
77450
77451                     if (closed) {
77452                       area += steradiansToSqmeters(entity.area(graph));
77453                     }
77454                   }
77455                 }
77456
77457                 if (selected.length > 1) {
77458                   geometry = null;
77459                   closed = null;
77460                   centroid = null;
77461                 }
77462
77463                 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
77464                   distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
77465                 }
77466
77467                 if (selected.length === 1 && selected[0].type === 'node') {
77468                   location = selected[0].loc;
77469                 } else {
77470                   totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
77471                 }
77472
77473                 if (!location && !centroid) {
77474                   center = extent.center();
77475                 }
77476               }
77477             }
77478
77479             selection.html('');
77480
77481             if (heading) {
77482               selection.append('h4').attr('class', 'measurement-heading').html(heading);
77483             }
77484
77485             var list = selection.append('ul');
77486             var coordItem;
77487
77488             if (geometry) {
77489               list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
77490             }
77491
77492             if (totalNodeCount) {
77493               list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
77494             }
77495
77496             if (area) {
77497               list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
77498             }
77499
77500             if (length) {
77501               list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
77502             }
77503
77504             if (typeof distance === 'number') {
77505               list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
77506             }
77507
77508             if (location) {
77509               coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
77510               coordItem.append('span').html(dmsCoordinatePair(location));
77511               coordItem.append('span').html(decimalCoordinatePair(location));
77512             }
77513
77514             if (centroid) {
77515               coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
77516               coordItem.append('span').html(dmsCoordinatePair(centroid));
77517               coordItem.append('span').html(decimalCoordinatePair(centroid));
77518             }
77519
77520             if (center) {
77521               coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
77522               coordItem.append('span').html(dmsCoordinatePair(center));
77523               coordItem.append('span').html(decimalCoordinatePair(center));
77524             }
77525
77526             if (length || area || typeof distance === 'number') {
77527               var toggle = _isImperial ? 'imperial' : 'metric';
77528               selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
77529                 d3_event.preventDefault();
77530                 _isImperial = !_isImperial;
77531                 selection.call(redraw);
77532               });
77533             }
77534           }
77535
77536           var panel = function panel(selection) {
77537             selection.call(redraw);
77538             context.map().on('drawn.info-measurement', function () {
77539               selection.call(redraw);
77540             });
77541             context.on('enter.info-measurement', function () {
77542               selection.call(redraw);
77543             });
77544           };
77545
77546           panel.off = function () {
77547             context.map().on('drawn.info-measurement', null);
77548             context.on('enter.info-measurement', null);
77549           };
77550
77551           panel.id = 'measurement';
77552           panel.label = _t.html('info_panels.measurement.title');
77553           panel.key = _t('info_panels.measurement.key');
77554           return panel;
77555         }
77556
77557         var uiInfoPanels = {
77558           background: uiPanelBackground,
77559           history: uiPanelHistory,
77560           location: uiPanelLocation,
77561           measurement: uiPanelMeasurement
77562         };
77563
77564         function uiInfo(context) {
77565           var ids = Object.keys(uiInfoPanels);
77566           var wasActive = ['measurement'];
77567           var panels = {};
77568           var active = {}; // create panels
77569
77570           ids.forEach(function (k) {
77571             if (!panels[k]) {
77572               panels[k] = uiInfoPanels[k](context);
77573               active[k] = false;
77574             }
77575           });
77576
77577           function info(selection) {
77578             function redraw() {
77579               var activeids = ids.filter(function (k) {
77580                 return active[k];
77581               }).sort();
77582               var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
77583                 return k;
77584               });
77585               containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
77586                 select(this).call(panels[d].off).remove();
77587               });
77588               var enter = containers.enter().append('div').attr('class', function (d) {
77589                 return 'fillD2 panel-container panel-container-' + d;
77590               });
77591               enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
77592               var title = enter.append('div').attr('class', 'panel-title fillD2');
77593               title.append('h3').html(function (d) {
77594                 return panels[d].label;
77595               });
77596               title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
77597                 d3_event.stopImmediatePropagation();
77598                 d3_event.preventDefault();
77599                 info.toggle(d);
77600               }).call(svgIcon('#iD-icon-close'));
77601               enter.append('div').attr('class', function (d) {
77602                 return 'panel-content panel-content-' + d;
77603               }); // redraw the panels
77604
77605               infoPanels.selectAll('.panel-content').each(function (d) {
77606                 select(this).call(panels[d]);
77607               });
77608             }
77609
77610             info.toggle = function (which) {
77611               var activeids = ids.filter(function (k) {
77612                 return active[k];
77613               });
77614
77615               if (which) {
77616                 // toggle one
77617                 active[which] = !active[which];
77618
77619                 if (activeids.length === 1 && activeids[0] === which) {
77620                   // none active anymore
77621                   wasActive = [which];
77622                 }
77623
77624                 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
77625               } else {
77626                 // toggle all
77627                 if (activeids.length) {
77628                   wasActive = activeids;
77629                   activeids.forEach(function (k) {
77630                     active[k] = false;
77631                   });
77632                 } else {
77633                   wasActive.forEach(function (k) {
77634                     active[k] = true;
77635                   });
77636                 }
77637               }
77638
77639               redraw();
77640             };
77641
77642             var infoPanels = selection.selectAll('.info-panels').data([0]);
77643             infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
77644             redraw();
77645             context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
77646               d3_event.stopImmediatePropagation();
77647               d3_event.preventDefault();
77648               info.toggle();
77649             });
77650             ids.forEach(function (k) {
77651               var key = _t('info_panels.' + k + '.key', {
77652                 "default": null
77653               });
77654               if (!key) return;
77655               context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
77656                 d3_event.stopImmediatePropagation();
77657                 d3_event.preventDefault();
77658                 info.toggle(k);
77659               });
77660             });
77661           }
77662
77663           return info;
77664         }
77665
77666         function pointBox(loc, context) {
77667           var rect = context.surfaceRect();
77668           var point = context.curtainProjection(loc);
77669           return {
77670             left: point[0] + rect.left - 40,
77671             top: point[1] + rect.top - 60,
77672             width: 80,
77673             height: 90
77674           };
77675         }
77676         function pad(locOrBox, padding, context) {
77677           var box;
77678
77679           if (locOrBox instanceof Array) {
77680             var rect = context.surfaceRect();
77681             var point = context.curtainProjection(locOrBox);
77682             box = {
77683               left: point[0] + rect.left,
77684               top: point[1] + rect.top
77685             };
77686           } else {
77687             box = locOrBox;
77688           }
77689
77690           return {
77691             left: box.left - padding,
77692             top: box.top - padding,
77693             width: (box.width || 0) + 2 * padding,
77694             height: (box.width || 0) + 2 * padding
77695           };
77696         }
77697         function icon(name, svgklass, useklass) {
77698           return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
77699         }
77700         var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
77701         // label replacements suitable for tutorials and documentation. Optionally supplemented
77702         // with custom `replacements`
77703
77704         function helpHtml(id, replacements) {
77705           // only load these the first time
77706           if (!helpStringReplacements) helpStringReplacements = {
77707             // insert icons corresponding to various UI elements
77708             point_icon: icon('#iD-icon-point', 'inline'),
77709             line_icon: icon('#iD-icon-line', 'inline'),
77710             area_icon: icon('#iD-icon-area', 'inline'),
77711             note_icon: icon('#iD-icon-note', 'inline add-note'),
77712             plus: icon('#iD-icon-plus', 'inline'),
77713             minus: icon('#iD-icon-minus', 'inline'),
77714             layers_icon: icon('#iD-icon-layers', 'inline'),
77715             data_icon: icon('#iD-icon-data', 'inline'),
77716             inspect: icon('#iD-icon-inspect', 'inline'),
77717             help_icon: icon('#iD-icon-help', 'inline'),
77718             undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
77719             redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
77720             save_icon: icon('#iD-icon-save', 'inline'),
77721             // operation icons
77722             circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
77723             continue_icon: icon('#iD-operation-continue', 'inline operation'),
77724             copy_icon: icon('#iD-operation-copy', 'inline operation'),
77725             delete_icon: icon('#iD-operation-delete', 'inline operation'),
77726             disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
77727             downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
77728             extract_icon: icon('#iD-operation-extract', 'inline operation'),
77729             merge_icon: icon('#iD-operation-merge', 'inline operation'),
77730             move_icon: icon('#iD-operation-move', 'inline operation'),
77731             orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
77732             paste_icon: icon('#iD-operation-paste', 'inline operation'),
77733             reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
77734             reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
77735             reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
77736             rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
77737             split_icon: icon('#iD-operation-split', 'inline operation'),
77738             straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
77739             // interaction icons
77740             leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
77741             rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
77742             mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
77743             tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
77744             doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
77745             longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
77746             touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
77747             pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
77748             // insert keys; may be localized and platform-dependent
77749             shift: uiCmd.display('⇧'),
77750             alt: uiCmd.display('⌥'),
77751             "return": uiCmd.display('↵'),
77752             esc: _t.html('shortcuts.key.esc'),
77753             space: _t.html('shortcuts.key.space'),
77754             add_note_key: _t.html('modes.add_note.key'),
77755             help_key: _t.html('help.key'),
77756             shortcuts_key: _t.html('shortcuts.toggle.key'),
77757             // reference localized UI labels directly so that they'll always match
77758             save: _t.html('save.title'),
77759             undo: _t.html('undo.title'),
77760             redo: _t.html('redo.title'),
77761             upload: _t.html('commit.save'),
77762             point: _t.html('modes.add_point.title'),
77763             line: _t.html('modes.add_line.title'),
77764             area: _t.html('modes.add_area.title'),
77765             note: _t.html('modes.add_note.label'),
77766             circularize: _t.html('operations.circularize.title'),
77767             "continue": _t.html('operations.continue.title'),
77768             copy: _t.html('operations.copy.title'),
77769             "delete": _t.html('operations.delete.title'),
77770             disconnect: _t.html('operations.disconnect.title'),
77771             downgrade: _t.html('operations.downgrade.title'),
77772             extract: _t.html('operations.extract.title'),
77773             merge: _t.html('operations.merge.title'),
77774             move: _t.html('operations.move.title'),
77775             orthogonalize: _t.html('operations.orthogonalize.title'),
77776             paste: _t.html('operations.paste.title'),
77777             reflect_long: _t.html('operations.reflect.title.long'),
77778             reflect_short: _t.html('operations.reflect.title.short'),
77779             reverse: _t.html('operations.reverse.title'),
77780             rotate: _t.html('operations.rotate.title'),
77781             split: _t.html('operations.split.title'),
77782             straighten: _t.html('operations.straighten.title'),
77783             map_data: _t.html('map_data.title'),
77784             osm_notes: _t.html('map_data.layers.notes.title'),
77785             fields: _t.html('inspector.fields'),
77786             tags: _t.html('inspector.tags'),
77787             relations: _t.html('inspector.relations'),
77788             new_relation: _t.html('inspector.new_relation'),
77789             turn_restrictions: _t.html('presets.fields.restrictions.label'),
77790             background_settings: _t.html('background.description'),
77791             imagery_offset: _t.html('background.fix_misalignment'),
77792             start_the_walkthrough: _t.html('splash.walkthrough'),
77793             help: _t.html('help.title'),
77794             ok: _t.html('intro.ok')
77795           };
77796           var reps;
77797
77798           if (replacements) {
77799             reps = Object.assign(replacements, helpStringReplacements);
77800           } else {
77801             reps = helpStringReplacements;
77802           }
77803
77804           return _t.html(id, reps) // use keyboard key styling for shortcuts
77805           .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
77806         }
77807
77808         function slugify(text) {
77809           return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
77810           .replace(/[^\w\-]+/g, '') // Remove all non-word chars
77811           .replace(/\-\-+/g, '-') // Replace multiple - with single -
77812           .replace(/^-+/, '') // Trim - from start of text
77813           .replace(/-+$/, ''); // Trim - from end of text
77814         } // console warning for missing walkthrough names
77815
77816
77817         var missingStrings = {};
77818
77819         function checkKey(key, text) {
77820           if (_t(key, {
77821             "default": undefined
77822           }) === undefined) {
77823             if (missingStrings.hasOwnProperty(key)) return; // warn once
77824
77825             missingStrings[key] = text;
77826             var missing = key + ': ' + text;
77827             if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
77828           }
77829         }
77830
77831         function localize(obj) {
77832           var key; // Assign name if entity has one..
77833
77834           var name = obj.tags && obj.tags.name;
77835
77836           if (name) {
77837             key = 'intro.graph.name.' + slugify(name);
77838             obj.tags.name = _t(key, {
77839               "default": name
77840             });
77841             checkKey(key, name);
77842           } // Assign street name if entity has one..
77843
77844
77845           var street = obj.tags && obj.tags['addr:street'];
77846
77847           if (street) {
77848             key = 'intro.graph.name.' + slugify(street);
77849             obj.tags['addr:street'] = _t(key, {
77850               "default": street
77851             });
77852             checkKey(key, street); // Add address details common across walkthrough..
77853
77854             var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
77855             addrTags.forEach(function (k) {
77856               var key = 'intro.graph.' + k;
77857               var tag = 'addr:' + k;
77858               var val = obj.tags && obj.tags[tag];
77859               var str = _t(key, {
77860                 "default": val
77861               });
77862
77863               if (str) {
77864                 if (str.match(/^<.*>$/) !== null) {
77865                   delete obj.tags[tag];
77866                 } else {
77867                   obj.tags[tag] = str;
77868                 }
77869               }
77870             });
77871           }
77872
77873           return obj;
77874         } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
77875
77876         function isMostlySquare(points) {
77877           // note: uses 15 here instead of the 12 from actionOrthogonalize because
77878           // actionOrthogonalize can actually straighten some larger angles as it iterates
77879           var threshold = 15; // degrees within right or straight
77880
77881           var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
77882
77883           var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
77884
77885           for (var i = 0; i < points.length; i++) {
77886             var a = points[(i - 1 + points.length) % points.length];
77887             var origin = points[i];
77888             var b = points[(i + 1) % points.length];
77889             var dotp = geoVecNormalizedDot(a, b, origin);
77890             var mag = Math.abs(dotp);
77891
77892             if (mag > lowerBound && mag < upperBound) {
77893               return false;
77894             }
77895           }
77896
77897           return true;
77898         }
77899         function selectMenuItem(context, operation) {
77900           return context.container().select('.edit-menu .edit-menu-item-' + operation);
77901         }
77902         function transitionTime(point1, point2) {
77903           var distance = geoSphericalDistance(point1, point2);
77904           if (distance === 0) return 0;else if (distance < 80) return 500;else return 1000;
77905         }
77906
77907         function uiCurtain(containerNode) {
77908           var surface = select(null),
77909               tooltip = select(null),
77910               darkness = select(null);
77911
77912           function curtain(selection) {
77913             surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
77914             darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
77915             select(window).on('resize.curtain', resize);
77916             tooltip = selection.append('div').attr('class', 'tooltip');
77917             tooltip.append('div').attr('class', 'popover-arrow');
77918             tooltip.append('div').attr('class', 'popover-inner');
77919             resize();
77920
77921             function resize() {
77922               surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
77923               curtain.cut(darkness.datum());
77924             }
77925           }
77926           /**
77927            * Reveal cuts the curtain to highlight the given box,
77928            * and shows a tooltip with instructions next to the box.
77929            *
77930            * @param  {String|ClientRect} [box]   box used to cut the curtain
77931            * @param  {String}    [text]          text for a tooltip
77932            * @param  {Object}    [options]
77933            * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
77934            * @param  {integer}   [options.duration]        transition time in milliseconds
77935            * @param  {string}    [options.buttonText]      if set, create a button with this text label
77936            * @param  {function}  [options.buttonCallback]  if set, the callback for the button
77937            * @param  {function}  [options.padding]         extra margin in px to put around bbox
77938            * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
77939            */
77940
77941
77942           curtain.reveal = function (box, html, options) {
77943             options = options || {};
77944
77945             if (typeof box === 'string') {
77946               box = select(box).node();
77947             }
77948
77949             if (box && box.getBoundingClientRect) {
77950               box = copyBox(box.getBoundingClientRect());
77951               var containerRect = containerNode.getBoundingClientRect();
77952               box.top -= containerRect.top;
77953               box.left -= containerRect.left;
77954             }
77955
77956             if (box && options.padding) {
77957               box.top -= options.padding;
77958               box.left -= options.padding;
77959               box.bottom += options.padding;
77960               box.right += options.padding;
77961               box.height += options.padding * 2;
77962               box.width += options.padding * 2;
77963             }
77964
77965             var tooltipBox;
77966
77967             if (options.tooltipBox) {
77968               tooltipBox = options.tooltipBox;
77969
77970               if (typeof tooltipBox === 'string') {
77971                 tooltipBox = select(tooltipBox).node();
77972               }
77973
77974               if (tooltipBox && tooltipBox.getBoundingClientRect) {
77975                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
77976               }
77977             } else {
77978               tooltipBox = box;
77979             }
77980
77981             if (tooltipBox && html) {
77982               if (html.indexOf('**') !== -1) {
77983                 if (html.indexOf('<span') === 0) {
77984                   html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
77985                 } else {
77986                   html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
77987                 } // pseudo markdown bold text for the instruction section..
77988
77989
77990                 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
77991               }
77992
77993               html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
77994
77995               html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
77996
77997               if (options.buttonText && options.buttonCallback) {
77998                 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
77999               }
78000
78001               var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
78002               tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
78003
78004               if (options.buttonText && options.buttonCallback) {
78005                 var button = tooltip.selectAll('.button-section .button.action');
78006                 button.on('click', function (d3_event) {
78007                   d3_event.preventDefault();
78008                   options.buttonCallback();
78009                 });
78010               }
78011
78012               var tip = copyBox(tooltip.node().getBoundingClientRect()),
78013                   w = containerNode.clientWidth,
78014                   h = containerNode.clientHeight,
78015                   tooltipWidth = 200,
78016                   tooltipArrow = 5,
78017                   side,
78018                   pos; // hack: this will have bottom placement,
78019               // so need to reserve extra space for the tooltip illustration.
78020
78021               if (options.tooltipClass === 'intro-mouse') {
78022                 tip.height += 80;
78023               } // trim box dimensions to just the portion that fits in the container..
78024
78025
78026               if (tooltipBox.top + tooltipBox.height > h) {
78027                 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
78028               }
78029
78030               if (tooltipBox.left + tooltipBox.width > w) {
78031                 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
78032               } // determine tooltip placement..
78033
78034
78035               if (tooltipBox.top + tooltipBox.height < 100) {
78036                 // tooltip below box..
78037                 side = 'bottom';
78038                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
78039               } else if (tooltipBox.top > h - 140) {
78040                 // tooltip above box..
78041                 side = 'top';
78042                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
78043               } else {
78044                 // tooltip to the side of the tooltipBox..
78045                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
78046
78047                 if (_mainLocalizer.textDirection() === 'rtl') {
78048                   if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
78049                     side = 'right';
78050                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
78051                   } else {
78052                     side = 'left';
78053                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
78054                   }
78055                 } else {
78056                   if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
78057                     side = 'left';
78058                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
78059                   } else {
78060                     side = 'right';
78061                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
78062                   }
78063                 }
78064               }
78065
78066               if (options.duration !== 0 || !tooltip.classed(side)) {
78067                 tooltip.call(uiToggle(true));
78068               }
78069
78070               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
78071               // (doesn't affect the placement of the popover-arrow)
78072
78073               var shiftY = 0;
78074
78075               if (side === 'left' || side === 'right') {
78076                 if (pos[1] < 60) {
78077                   shiftY = 60 - pos[1];
78078                 } else if (pos[1] + tip.height > h - 100) {
78079                   shiftY = h - pos[1] - tip.height - 100;
78080                 }
78081               }
78082
78083               tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
78084             } else {
78085               tooltip.classed('in', false).call(uiToggle(false));
78086             }
78087
78088             curtain.cut(box, options.duration);
78089             return tooltip;
78090           };
78091
78092           curtain.cut = function (datum, duration) {
78093             darkness.datum(datum).interrupt();
78094             var selection;
78095
78096             if (duration === 0) {
78097               selection = darkness;
78098             } else {
78099               selection = darkness.transition().duration(duration || 600).ease(linear$1);
78100             }
78101
78102             selection.attr('d', function (d) {
78103               var containerWidth = containerNode.clientWidth;
78104               var containerHeight = containerNode.clientHeight;
78105               var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
78106               if (!d) return string;
78107               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';
78108             });
78109           };
78110
78111           curtain.remove = function () {
78112             surface.remove();
78113             tooltip.remove();
78114             select(window).on('resize.curtain', null);
78115           }; // ClientRects are immutable, so copy them to an object,
78116           // in case we need to trim the height/width.
78117
78118
78119           function copyBox(src) {
78120             return {
78121               top: src.top,
78122               right: src.right,
78123               bottom: src.bottom,
78124               left: src.left,
78125               width: src.width,
78126               height: src.height
78127             };
78128           }
78129
78130           return curtain;
78131         }
78132
78133         function uiIntroWelcome(context, reveal) {
78134           var dispatch$1 = dispatch('done');
78135           var chapter = {
78136             title: 'intro.welcome.title'
78137           };
78138
78139           function welcome() {
78140             context.map().centerZoom([-85.63591, 41.94285], 19);
78141             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
78142               buttonText: _t.html('intro.ok'),
78143               buttonCallback: practice
78144             });
78145           }
78146
78147           function practice() {
78148             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
78149               buttonText: _t.html('intro.ok'),
78150               buttonCallback: words
78151             });
78152           }
78153
78154           function words() {
78155             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
78156               buttonText: _t.html('intro.ok'),
78157               buttonCallback: chapters
78158             });
78159           }
78160
78161           function chapters() {
78162             dispatch$1.call('done');
78163             reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
78164               next: _t('intro.navigation.title')
78165             }));
78166           }
78167
78168           chapter.enter = function () {
78169             welcome();
78170           };
78171
78172           chapter.exit = function () {
78173             context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
78174           };
78175
78176           chapter.restart = function () {
78177             chapter.exit();
78178             chapter.enter();
78179           };
78180
78181           return utilRebind(chapter, dispatch$1, 'on');
78182         }
78183
78184         function uiIntroNavigation(context, reveal) {
78185           var dispatch$1 = dispatch('done');
78186           var timeouts = [];
78187           var hallId = 'n2061';
78188           var townHall = [-85.63591, 41.94285];
78189           var springStreetId = 'w397';
78190           var springStreetEndId = 'n1834';
78191           var springStreet = [-85.63582, 41.94255];
78192           var onewayField = _mainPresetIndex.field('oneway');
78193           var maxspeedField = _mainPresetIndex.field('maxspeed');
78194           var chapter = {
78195             title: 'intro.navigation.title'
78196           };
78197
78198           function timeout(f, t) {
78199             timeouts.push(window.setTimeout(f, t));
78200           }
78201
78202           function eventCancel(d3_event) {
78203             d3_event.stopPropagation();
78204             d3_event.preventDefault();
78205           }
78206
78207           function isTownHallSelected() {
78208             var ids = context.selectedIDs();
78209             return ids.length === 1 && ids[0] === hallId;
78210           }
78211
78212           function dragMap() {
78213             context.enter(modeBrowse(context));
78214             context.history().reset('initial');
78215             var msec = transitionTime(townHall, context.map().center());
78216
78217             if (msec) {
78218               reveal(null, null, {
78219                 duration: 0
78220               });
78221             }
78222
78223             context.map().centerZoomEase(townHall, 19, msec);
78224             timeout(function () {
78225               var centerStart = context.map().center();
78226               var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
78227               var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
78228               reveal('.surface', dragString);
78229               context.map().on('drawn.intro', function () {
78230                 reveal('.surface', dragString, {
78231                   duration: 0
78232                 });
78233               });
78234               context.map().on('move.intro', function () {
78235                 var centerNow = context.map().center();
78236
78237                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
78238                   context.map().on('move.intro', null);
78239                   timeout(function () {
78240                     continueTo(zoomMap);
78241                   }, 3000);
78242                 }
78243               });
78244             }, msec + 100);
78245
78246             function continueTo(nextStep) {
78247               context.map().on('move.intro drawn.intro', null);
78248               nextStep();
78249             }
78250           }
78251
78252           function zoomMap() {
78253             var zoomStart = context.map().zoom();
78254             var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
78255             var zoomString = helpHtml('intro.navigation.' + textId);
78256             reveal('.surface', zoomString);
78257             context.map().on('drawn.intro', function () {
78258               reveal('.surface', zoomString, {
78259                 duration: 0
78260               });
78261             });
78262             context.map().on('move.intro', function () {
78263               if (context.map().zoom() !== zoomStart) {
78264                 context.map().on('move.intro', null);
78265                 timeout(function () {
78266                   continueTo(features);
78267                 }, 3000);
78268               }
78269             });
78270
78271             function continueTo(nextStep) {
78272               context.map().on('move.intro drawn.intro', null);
78273               nextStep();
78274             }
78275           }
78276
78277           function features() {
78278             var onClick = function onClick() {
78279               continueTo(pointsLinesAreas);
78280             };
78281
78282             reveal('.surface', helpHtml('intro.navigation.features'), {
78283               buttonText: _t.html('intro.ok'),
78284               buttonCallback: onClick
78285             });
78286             context.map().on('drawn.intro', function () {
78287               reveal('.surface', helpHtml('intro.navigation.features'), {
78288                 duration: 0,
78289                 buttonText: _t.html('intro.ok'),
78290                 buttonCallback: onClick
78291               });
78292             });
78293
78294             function continueTo(nextStep) {
78295               context.map().on('drawn.intro', null);
78296               nextStep();
78297             }
78298           }
78299
78300           function pointsLinesAreas() {
78301             var onClick = function onClick() {
78302               continueTo(nodesWays);
78303             };
78304
78305             reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
78306               buttonText: _t.html('intro.ok'),
78307               buttonCallback: onClick
78308             });
78309             context.map().on('drawn.intro', function () {
78310               reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
78311                 duration: 0,
78312                 buttonText: _t.html('intro.ok'),
78313                 buttonCallback: onClick
78314               });
78315             });
78316
78317             function continueTo(nextStep) {
78318               context.map().on('drawn.intro', null);
78319               nextStep();
78320             }
78321           }
78322
78323           function nodesWays() {
78324             var onClick = function onClick() {
78325               continueTo(clickTownHall);
78326             };
78327
78328             reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
78329               buttonText: _t.html('intro.ok'),
78330               buttonCallback: onClick
78331             });
78332             context.map().on('drawn.intro', function () {
78333               reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
78334                 duration: 0,
78335                 buttonText: _t.html('intro.ok'),
78336                 buttonCallback: onClick
78337               });
78338             });
78339
78340             function continueTo(nextStep) {
78341               context.map().on('drawn.intro', null);
78342               nextStep();
78343             }
78344           }
78345
78346           function clickTownHall() {
78347             context.enter(modeBrowse(context));
78348             context.history().reset('initial');
78349             var entity = context.hasEntity(hallId);
78350             if (!entity) return;
78351             reveal(null, null, {
78352               duration: 0
78353             });
78354             context.map().centerZoomEase(entity.loc, 19, 500);
78355             timeout(function () {
78356               var entity = context.hasEntity(hallId);
78357               if (!entity) return;
78358               var box = pointBox(entity.loc, context);
78359               var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
78360               reveal(box, helpHtml('intro.navigation.' + textId));
78361               context.map().on('move.intro drawn.intro', function () {
78362                 var entity = context.hasEntity(hallId);
78363                 if (!entity) return;
78364                 var box = pointBox(entity.loc, context);
78365                 reveal(box, helpHtml('intro.navigation.' + textId), {
78366                   duration: 0
78367                 });
78368               });
78369               context.on('enter.intro', function () {
78370                 if (isTownHallSelected()) continueTo(selectedTownHall);
78371               });
78372             }, 550); // after centerZoomEase
78373
78374             context.history().on('change.intro', function () {
78375               if (!context.hasEntity(hallId)) {
78376                 continueTo(clickTownHall);
78377               }
78378             });
78379
78380             function continueTo(nextStep) {
78381               context.on('enter.intro', null);
78382               context.map().on('move.intro drawn.intro', null);
78383               context.history().on('change.intro', null);
78384               nextStep();
78385             }
78386           }
78387
78388           function selectedTownHall() {
78389             if (!isTownHallSelected()) return clickTownHall();
78390             var entity = context.hasEntity(hallId);
78391             if (!entity) return clickTownHall();
78392             var box = pointBox(entity.loc, context);
78393
78394             var onClick = function onClick() {
78395               continueTo(editorTownHall);
78396             };
78397
78398             reveal(box, helpHtml('intro.navigation.selected_townhall'), {
78399               buttonText: _t.html('intro.ok'),
78400               buttonCallback: onClick
78401             });
78402             context.map().on('move.intro drawn.intro', function () {
78403               var entity = context.hasEntity(hallId);
78404               if (!entity) return;
78405               var box = pointBox(entity.loc, context);
78406               reveal(box, helpHtml('intro.navigation.selected_townhall'), {
78407                 duration: 0,
78408                 buttonText: _t.html('intro.ok'),
78409                 buttonCallback: onClick
78410               });
78411             });
78412             context.history().on('change.intro', function () {
78413               if (!context.hasEntity(hallId)) {
78414                 continueTo(clickTownHall);
78415               }
78416             });
78417
78418             function continueTo(nextStep) {
78419               context.map().on('move.intro drawn.intro', null);
78420               context.history().on('change.intro', null);
78421               nextStep();
78422             }
78423           }
78424
78425           function editorTownHall() {
78426             if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
78427
78428             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
78429
78430             var onClick = function onClick() {
78431               continueTo(presetTownHall);
78432             };
78433
78434             reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
78435               buttonText: _t.html('intro.ok'),
78436               buttonCallback: onClick
78437             });
78438             context.on('exit.intro', function () {
78439               continueTo(clickTownHall);
78440             });
78441             context.history().on('change.intro', function () {
78442               if (!context.hasEntity(hallId)) {
78443                 continueTo(clickTownHall);
78444               }
78445             });
78446
78447             function continueTo(nextStep) {
78448               context.on('exit.intro', null);
78449               context.history().on('change.intro', null);
78450               context.container().select('.inspector-wrap').on('wheel.intro', null);
78451               nextStep();
78452             }
78453           }
78454
78455           function presetTownHall() {
78456             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
78457
78458             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
78459
78460             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
78461
78462             var entity = context.entity(context.selectedIDs()[0]);
78463             var preset = _mainPresetIndex.match(entity, context.graph());
78464
78465             var onClick = function onClick() {
78466               continueTo(fieldsTownHall);
78467             };
78468
78469             reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
78470               preset: preset.name()
78471             }), {
78472               buttonText: _t.html('intro.ok'),
78473               buttonCallback: onClick
78474             });
78475             context.on('exit.intro', function () {
78476               continueTo(clickTownHall);
78477             });
78478             context.history().on('change.intro', function () {
78479               if (!context.hasEntity(hallId)) {
78480                 continueTo(clickTownHall);
78481               }
78482             });
78483
78484             function continueTo(nextStep) {
78485               context.on('exit.intro', null);
78486               context.history().on('change.intro', null);
78487               context.container().select('.inspector-wrap').on('wheel.intro', null);
78488               nextStep();
78489             }
78490           }
78491
78492           function fieldsTownHall() {
78493             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
78494
78495             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
78496
78497             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
78498
78499             var onClick = function onClick() {
78500               continueTo(closeTownHall);
78501             };
78502
78503             reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
78504               buttonText: _t.html('intro.ok'),
78505               buttonCallback: onClick
78506             });
78507             context.on('exit.intro', function () {
78508               continueTo(clickTownHall);
78509             });
78510             context.history().on('change.intro', function () {
78511               if (!context.hasEntity(hallId)) {
78512                 continueTo(clickTownHall);
78513               }
78514             });
78515
78516             function continueTo(nextStep) {
78517               context.on('exit.intro', null);
78518               context.history().on('change.intro', null);
78519               context.container().select('.inspector-wrap').on('wheel.intro', null);
78520               nextStep();
78521             }
78522           }
78523
78524           function closeTownHall() {
78525             if (!isTownHallSelected()) return clickTownHall();
78526             var selector = '.entity-editor-pane button.close svg use';
78527             var href = select(selector).attr('href') || '#iD-icon-close';
78528             reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
78529               button: icon(href, 'inline')
78530             }));
78531             context.on('exit.intro', function () {
78532               continueTo(searchStreet);
78533             });
78534             context.history().on('change.intro', function () {
78535               // update the close icon in the tooltip if the user edits something.
78536               var selector = '.entity-editor-pane button.close svg use';
78537               var href = select(selector).attr('href') || '#iD-icon-close';
78538               reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
78539                 button: icon(href, 'inline')
78540               }), {
78541                 duration: 0
78542               });
78543             });
78544
78545             function continueTo(nextStep) {
78546               context.on('exit.intro', null);
78547               context.history().on('change.intro', null);
78548               nextStep();
78549             }
78550           }
78551
78552           function searchStreet() {
78553             context.enter(modeBrowse(context));
78554             context.history().reset('initial'); // ensure spring street exists
78555
78556             var msec = transitionTime(springStreet, context.map().center());
78557
78558             if (msec) {
78559               reveal(null, null, {
78560                 duration: 0
78561               });
78562             }
78563
78564             context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
78565
78566             timeout(function () {
78567               reveal('.search-header input', helpHtml('intro.navigation.search_street', {
78568                 name: _t('intro.graph.name.spring-street')
78569               }));
78570               context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
78571             }, msec + 100);
78572           }
78573
78574           function checkSearchResult() {
78575             var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
78576
78577             var firstName = first.select('.entity-name');
78578             var name = _t('intro.graph.name.spring-street');
78579
78580             if (!firstName.empty() && firstName.html() === name) {
78581               reveal(first.node(), helpHtml('intro.navigation.choose_street', {
78582                 name: name
78583               }), {
78584                 duration: 300
78585               });
78586               context.on('exit.intro', function () {
78587                 continueTo(selectedStreet);
78588               });
78589               context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
78590             }
78591
78592             function continueTo(nextStep) {
78593               context.on('exit.intro', null);
78594               context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
78595               nextStep();
78596             }
78597           }
78598
78599           function selectedStreet() {
78600             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
78601               return searchStreet();
78602             }
78603
78604             var onClick = function onClick() {
78605               continueTo(editorStreet);
78606             };
78607
78608             var entity = context.entity(springStreetEndId);
78609             var box = pointBox(entity.loc, context);
78610             box.height = 500;
78611             reveal(box, helpHtml('intro.navigation.selected_street', {
78612               name: _t('intro.graph.name.spring-street')
78613             }), {
78614               duration: 600,
78615               buttonText: _t.html('intro.ok'),
78616               buttonCallback: onClick
78617             });
78618             timeout(function () {
78619               context.map().on('move.intro drawn.intro', function () {
78620                 var entity = context.hasEntity(springStreetEndId);
78621                 if (!entity) return;
78622                 var box = pointBox(entity.loc, context);
78623                 box.height = 500;
78624                 reveal(box, helpHtml('intro.navigation.selected_street', {
78625                   name: _t('intro.graph.name.spring-street')
78626                 }), {
78627                   duration: 0,
78628                   buttonText: _t.html('intro.ok'),
78629                   buttonCallback: onClick
78630                 });
78631               });
78632             }, 600); // after reveal.
78633
78634             context.on('enter.intro', function (mode) {
78635               if (!context.hasEntity(springStreetId)) {
78636                 return continueTo(searchStreet);
78637               }
78638
78639               var ids = context.selectedIDs();
78640
78641               if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
78642                 // keep Spring Street selected..
78643                 context.enter(modeSelect(context, [springStreetId]));
78644               }
78645             });
78646             context.history().on('change.intro', function () {
78647               if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
78648                 timeout(function () {
78649                   continueTo(searchStreet);
78650                 }, 300); // after any transition (e.g. if user deleted intersection)
78651               }
78652             });
78653
78654             function continueTo(nextStep) {
78655               context.map().on('move.intro drawn.intro', null);
78656               context.on('enter.intro', null);
78657               context.history().on('change.intro', null);
78658               nextStep();
78659             }
78660           }
78661
78662           function editorStreet() {
78663             var selector = '.entity-editor-pane button.close svg use';
78664             var href = select(selector).attr('href') || '#iD-icon-close';
78665             reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
78666               button: icon(href, 'inline'),
78667               field1: onewayField.label(),
78668               field2: maxspeedField.label()
78669             }));
78670             context.on('exit.intro', function () {
78671               continueTo(play);
78672             });
78673             context.history().on('change.intro', function () {
78674               // update the close icon in the tooltip if the user edits something.
78675               var selector = '.entity-editor-pane button.close svg use';
78676               var href = select(selector).attr('href') || '#iD-icon-close';
78677               reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
78678                 button: icon(href, 'inline'),
78679                 field1: onewayField.label(),
78680                 field2: maxspeedField.label()
78681               }), {
78682                 duration: 0
78683               });
78684             });
78685
78686             function continueTo(nextStep) {
78687               context.on('exit.intro', null);
78688               context.history().on('change.intro', null);
78689               nextStep();
78690             }
78691           }
78692
78693           function play() {
78694             dispatch$1.call('done');
78695             reveal('.ideditor', helpHtml('intro.navigation.play', {
78696               next: _t('intro.points.title')
78697             }), {
78698               tooltipBox: '.intro-nav-wrap .chapter-point',
78699               buttonText: _t.html('intro.ok'),
78700               buttonCallback: function buttonCallback() {
78701                 reveal('.ideditor');
78702               }
78703             });
78704           }
78705
78706           chapter.enter = function () {
78707             dragMap();
78708           };
78709
78710           chapter.exit = function () {
78711             timeouts.forEach(window.clearTimeout);
78712             context.on('enter.intro exit.intro', null);
78713             context.map().on('move.intro drawn.intro', null);
78714             context.history().on('change.intro', null);
78715             context.container().select('.inspector-wrap').on('wheel.intro', null);
78716             context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
78717           };
78718
78719           chapter.restart = function () {
78720             chapter.exit();
78721             chapter.enter();
78722           };
78723
78724           return utilRebind(chapter, dispatch$1, 'on');
78725         }
78726
78727         function uiIntroPoint(context, reveal) {
78728           var dispatch$1 = dispatch('done');
78729           var timeouts = [];
78730           var intersection = [-85.63279, 41.94394];
78731           var building = [-85.632422, 41.944045];
78732           var cafePreset = _mainPresetIndex.item('amenity/cafe');
78733           var _pointID = null;
78734           var chapter = {
78735             title: 'intro.points.title'
78736           };
78737
78738           function timeout(f, t) {
78739             timeouts.push(window.setTimeout(f, t));
78740           }
78741
78742           function eventCancel(d3_event) {
78743             d3_event.stopPropagation();
78744             d3_event.preventDefault();
78745           }
78746
78747           function addPoint() {
78748             context.enter(modeBrowse(context));
78749             context.history().reset('initial');
78750             var msec = transitionTime(intersection, context.map().center());
78751
78752             if (msec) {
78753               reveal(null, null, {
78754                 duration: 0
78755               });
78756             }
78757
78758             context.map().centerZoomEase(intersection, 19, msec);
78759             timeout(function () {
78760               var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
78761               _pointID = null;
78762               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
78763               context.on('enter.intro', function (mode) {
78764                 if (mode.id !== 'add-point') return;
78765                 continueTo(placePoint);
78766               });
78767             }, msec + 100);
78768
78769             function continueTo(nextStep) {
78770               context.on('enter.intro', null);
78771               nextStep();
78772             }
78773           }
78774
78775           function placePoint() {
78776             if (context.mode().id !== 'add-point') {
78777               return chapter.restart();
78778             }
78779
78780             var pointBox = pad(building, 150, context);
78781             var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
78782             reveal(pointBox, helpHtml('intro.points.' + textId));
78783             context.map().on('move.intro drawn.intro', function () {
78784               pointBox = pad(building, 150, context);
78785               reveal(pointBox, helpHtml('intro.points.' + textId), {
78786                 duration: 0
78787               });
78788             });
78789             context.on('enter.intro', function (mode) {
78790               if (mode.id !== 'select') return chapter.restart();
78791               _pointID = context.mode().selectedIDs()[0];
78792               continueTo(searchPreset);
78793             });
78794
78795             function continueTo(nextStep) {
78796               context.map().on('move.intro drawn.intro', null);
78797               context.on('enter.intro', null);
78798               nextStep();
78799             }
78800           }
78801
78802           function searchPreset() {
78803             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
78804               return addPoint();
78805             } // disallow scrolling
78806
78807
78808             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
78809             context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
78810             reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
78811               preset: cafePreset.name()
78812             }));
78813             context.on('enter.intro', function (mode) {
78814               if (!_pointID || !context.hasEntity(_pointID)) {
78815                 return continueTo(addPoint);
78816               }
78817
78818               var ids = context.selectedIDs();
78819
78820               if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
78821                 // keep the user's point selected..
78822                 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
78823
78824                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
78825                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
78826                 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
78827                   preset: cafePreset.name()
78828                 }));
78829                 context.history().on('change.intro', null);
78830               }
78831             });
78832
78833             function checkPresetSearch() {
78834               var first = context.container().select('.preset-list-item:first-child');
78835
78836               if (first.classed('preset-amenity-cafe')) {
78837                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
78838                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
78839                   preset: cafePreset.name()
78840                 }), {
78841                   duration: 300
78842                 });
78843                 context.history().on('change.intro', function () {
78844                   continueTo(aboutFeatureEditor);
78845                 });
78846               }
78847             }
78848
78849             function continueTo(nextStep) {
78850               context.on('enter.intro', null);
78851               context.history().on('change.intro', null);
78852               context.container().select('.inspector-wrap').on('wheel.intro', null);
78853               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
78854               nextStep();
78855             }
78856           }
78857
78858           function aboutFeatureEditor() {
78859             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
78860               return addPoint();
78861             }
78862
78863             timeout(function () {
78864               reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
78865                 tooltipClass: 'intro-points-describe',
78866                 buttonText: _t.html('intro.ok'),
78867                 buttonCallback: function buttonCallback() {
78868                   continueTo(addName);
78869                 }
78870               });
78871             }, 400);
78872             context.on('exit.intro', function () {
78873               // if user leaves select mode here, just continue with the tutorial.
78874               continueTo(reselectPoint);
78875             });
78876
78877             function continueTo(nextStep) {
78878               context.on('exit.intro', null);
78879               nextStep();
78880             }
78881           }
78882
78883           function addName() {
78884             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
78885               return addPoint();
78886             } // reset pane, in case user happened to change it..
78887
78888
78889             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
78890             var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
78891             timeout(function () {
78892               // It's possible for the user to add a name in a previous step..
78893               // If so, don't tell them to add the name in this step.
78894               // Give them an OK button instead.
78895               var entity = context.entity(_pointID);
78896
78897               if (entity.tags.name) {
78898                 var tooltip = reveal('.entity-editor-pane', addNameString, {
78899                   tooltipClass: 'intro-points-describe',
78900                   buttonText: _t.html('intro.ok'),
78901                   buttonCallback: function buttonCallback() {
78902                     continueTo(addCloseEditor);
78903                   }
78904                 });
78905                 tooltip.select('.instruction').style('display', 'none');
78906               } else {
78907                 reveal('.entity-editor-pane', addNameString, {
78908                   tooltipClass: 'intro-points-describe'
78909                 });
78910               }
78911             }, 400);
78912             context.history().on('change.intro', function () {
78913               continueTo(addCloseEditor);
78914             });
78915             context.on('exit.intro', function () {
78916               // if user leaves select mode here, just continue with the tutorial.
78917               continueTo(reselectPoint);
78918             });
78919
78920             function continueTo(nextStep) {
78921               context.on('exit.intro', null);
78922               context.history().on('change.intro', null);
78923               nextStep();
78924             }
78925           }
78926
78927           function addCloseEditor() {
78928             // reset pane, in case user happened to change it..
78929             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
78930             var selector = '.entity-editor-pane button.close svg use';
78931             var href = select(selector).attr('href') || '#iD-icon-close';
78932             context.on('exit.intro', function () {
78933               continueTo(reselectPoint);
78934             });
78935             reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
78936               button: icon(href, 'inline')
78937             }));
78938
78939             function continueTo(nextStep) {
78940               context.on('exit.intro', null);
78941               nextStep();
78942             }
78943           }
78944
78945           function reselectPoint() {
78946             if (!_pointID) return chapter.restart();
78947             var entity = context.hasEntity(_pointID);
78948             if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
78949
78950             var oldPreset = _mainPresetIndex.match(entity, context.graph());
78951             context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
78952             context.enter(modeBrowse(context));
78953             var msec = transitionTime(entity.loc, context.map().center());
78954
78955             if (msec) {
78956               reveal(null, null, {
78957                 duration: 0
78958               });
78959             }
78960
78961             context.map().centerEase(entity.loc, msec);
78962             timeout(function () {
78963               var box = pointBox(entity.loc, context);
78964               reveal(box, helpHtml('intro.points.reselect'), {
78965                 duration: 600
78966               });
78967               timeout(function () {
78968                 context.map().on('move.intro drawn.intro', function () {
78969                   var entity = context.hasEntity(_pointID);
78970                   if (!entity) return chapter.restart();
78971                   var box = pointBox(entity.loc, context);
78972                   reveal(box, helpHtml('intro.points.reselect'), {
78973                     duration: 0
78974                   });
78975                 });
78976               }, 600); // after reveal..
78977
78978               context.on('enter.intro', function (mode) {
78979                 if (mode.id !== 'select') return;
78980                 continueTo(updatePoint);
78981               });
78982             }, msec + 100);
78983
78984             function continueTo(nextStep) {
78985               context.map().on('move.intro drawn.intro', null);
78986               context.on('enter.intro', null);
78987               nextStep();
78988             }
78989           }
78990
78991           function updatePoint() {
78992             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
78993               return continueTo(reselectPoint);
78994             } // reset pane, in case user happened to untag the point..
78995
78996
78997             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
78998             context.on('exit.intro', function () {
78999               continueTo(reselectPoint);
79000             });
79001             context.history().on('change.intro', function () {
79002               continueTo(updateCloseEditor);
79003             });
79004             timeout(function () {
79005               reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
79006                 tooltipClass: 'intro-points-describe'
79007               });
79008             }, 400);
79009
79010             function continueTo(nextStep) {
79011               context.on('exit.intro', null);
79012               context.history().on('change.intro', null);
79013               nextStep();
79014             }
79015           }
79016
79017           function updateCloseEditor() {
79018             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79019               return continueTo(reselectPoint);
79020             } // reset pane, in case user happened to change it..
79021
79022
79023             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79024             context.on('exit.intro', function () {
79025               continueTo(rightClickPoint);
79026             });
79027             timeout(function () {
79028               reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
79029                 button: icon('#iD-icon-close', 'inline')
79030               }));
79031             }, 500);
79032
79033             function continueTo(nextStep) {
79034               context.on('exit.intro', null);
79035               nextStep();
79036             }
79037           }
79038
79039           function rightClickPoint() {
79040             if (!_pointID) return chapter.restart();
79041             var entity = context.hasEntity(_pointID);
79042             if (!entity) return chapter.restart();
79043             context.enter(modeBrowse(context));
79044             var box = pointBox(entity.loc, context);
79045             var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
79046             reveal(box, helpHtml('intro.points.' + textId), {
79047               duration: 600
79048             });
79049             timeout(function () {
79050               context.map().on('move.intro', function () {
79051                 var entity = context.hasEntity(_pointID);
79052                 if (!entity) return chapter.restart();
79053                 var box = pointBox(entity.loc, context);
79054                 reveal(box, helpHtml('intro.points.' + textId), {
79055                   duration: 0
79056                 });
79057               });
79058             }, 600); // after reveal
79059
79060             context.on('enter.intro', function (mode) {
79061               if (mode.id !== 'select') return;
79062               var ids = context.selectedIDs();
79063               if (ids.length !== 1 || ids[0] !== _pointID) return;
79064               timeout(function () {
79065                 var node = selectMenuItem(context, 'delete').node();
79066                 if (!node) return;
79067                 continueTo(enterDelete);
79068               }, 50); // after menu visible
79069             });
79070
79071             function continueTo(nextStep) {
79072               context.on('enter.intro', null);
79073               context.map().on('move.intro', null);
79074               nextStep();
79075             }
79076           }
79077
79078           function enterDelete() {
79079             if (!_pointID) return chapter.restart();
79080             var entity = context.hasEntity(_pointID);
79081             if (!entity) return chapter.restart();
79082             var node = selectMenuItem(context, 'delete').node();
79083
79084             if (!node) {
79085               return continueTo(rightClickPoint);
79086             }
79087
79088             reveal('.edit-menu', helpHtml('intro.points.delete'), {
79089               padding: 50
79090             });
79091             timeout(function () {
79092               context.map().on('move.intro', function () {
79093                 reveal('.edit-menu', helpHtml('intro.points.delete'), {
79094                   duration: 0,
79095                   padding: 50
79096                 });
79097               });
79098             }, 300); // after menu visible
79099
79100             context.on('exit.intro', function () {
79101               if (!_pointID) return chapter.restart();
79102               var entity = context.hasEntity(_pointID);
79103               if (entity) return continueTo(rightClickPoint); // point still exists
79104             });
79105             context.history().on('change.intro', function (changed) {
79106               if (changed.deleted().length) {
79107                 continueTo(undo);
79108               }
79109             });
79110
79111             function continueTo(nextStep) {
79112               context.map().on('move.intro', null);
79113               context.history().on('change.intro', null);
79114               context.on('exit.intro', null);
79115               nextStep();
79116             }
79117           }
79118
79119           function undo() {
79120             context.history().on('change.intro', function () {
79121               continueTo(play);
79122             });
79123             reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
79124
79125             function continueTo(nextStep) {
79126               context.history().on('change.intro', null);
79127               nextStep();
79128             }
79129           }
79130
79131           function play() {
79132             dispatch$1.call('done');
79133             reveal('.ideditor', helpHtml('intro.points.play', {
79134               next: _t('intro.areas.title')
79135             }), {
79136               tooltipBox: '.intro-nav-wrap .chapter-area',
79137               buttonText: _t.html('intro.ok'),
79138               buttonCallback: function buttonCallback() {
79139                 reveal('.ideditor');
79140               }
79141             });
79142           }
79143
79144           chapter.enter = function () {
79145             addPoint();
79146           };
79147
79148           chapter.exit = function () {
79149             timeouts.forEach(window.clearTimeout);
79150             context.on('enter.intro exit.intro', null);
79151             context.map().on('move.intro drawn.intro', null);
79152             context.history().on('change.intro', null);
79153             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79154             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79155           };
79156
79157           chapter.restart = function () {
79158             chapter.exit();
79159             chapter.enter();
79160           };
79161
79162           return utilRebind(chapter, dispatch$1, 'on');
79163         }
79164
79165         function uiIntroArea(context, reveal) {
79166           var dispatch$1 = dispatch('done');
79167           var playground = [-85.63552, 41.94159];
79168           var playgroundPreset = _mainPresetIndex.item('leisure/playground');
79169           var nameField = _mainPresetIndex.field('name');
79170           var descriptionField = _mainPresetIndex.field('description');
79171           var timeouts = [];
79172
79173           var _areaID;
79174
79175           var chapter = {
79176             title: 'intro.areas.title'
79177           };
79178
79179           function timeout(f, t) {
79180             timeouts.push(window.setTimeout(f, t));
79181           }
79182
79183           function eventCancel(d3_event) {
79184             d3_event.stopPropagation();
79185             d3_event.preventDefault();
79186           }
79187
79188           function revealPlayground(center, text, options) {
79189             var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
79190             var box = pad(center, padding, context);
79191             reveal(box, text, options);
79192           }
79193
79194           function addArea() {
79195             context.enter(modeBrowse(context));
79196             context.history().reset('initial');
79197             _areaID = null;
79198             var msec = transitionTime(playground, context.map().center());
79199
79200             if (msec) {
79201               reveal(null, null, {
79202                 duration: 0
79203               });
79204             }
79205
79206             context.map().centerZoomEase(playground, 19, msec);
79207             timeout(function () {
79208               var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
79209               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
79210               context.on('enter.intro', function (mode) {
79211                 if (mode.id !== 'add-area') return;
79212                 continueTo(startPlayground);
79213               });
79214             }, msec + 100);
79215
79216             function continueTo(nextStep) {
79217               context.on('enter.intro', null);
79218               nextStep();
79219             }
79220           }
79221
79222           function startPlayground() {
79223             if (context.mode().id !== 'add-area') {
79224               return chapter.restart();
79225             }
79226
79227             _areaID = null;
79228             context.map().zoomEase(19.5, 500);
79229             timeout(function () {
79230               var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
79231               var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
79232               revealPlayground(playground, startDrawString, {
79233                 duration: 250
79234               });
79235               timeout(function () {
79236                 context.map().on('move.intro drawn.intro', function () {
79237                   revealPlayground(playground, startDrawString, {
79238                     duration: 0
79239                   });
79240                 });
79241                 context.on('enter.intro', function (mode) {
79242                   if (mode.id !== 'draw-area') return chapter.restart();
79243                   continueTo(continuePlayground);
79244                 });
79245               }, 250); // after reveal
79246             }, 550); // after easing
79247
79248             function continueTo(nextStep) {
79249               context.map().on('move.intro drawn.intro', null);
79250               context.on('enter.intro', null);
79251               nextStep();
79252             }
79253           }
79254
79255           function continuePlayground() {
79256             if (context.mode().id !== 'draw-area') {
79257               return chapter.restart();
79258             }
79259
79260             _areaID = null;
79261             revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
79262               duration: 250
79263             });
79264             timeout(function () {
79265               context.map().on('move.intro drawn.intro', function () {
79266                 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
79267                   duration: 0
79268                 });
79269               });
79270             }, 250); // after reveal
79271
79272             context.on('enter.intro', function (mode) {
79273               if (mode.id === 'draw-area') {
79274                 var entity = context.hasEntity(context.selectedIDs()[0]);
79275
79276                 if (entity && entity.nodes.length >= 6) {
79277                   return continueTo(finishPlayground);
79278                 } else {
79279                   return;
79280                 }
79281               } else if (mode.id === 'select') {
79282                 _areaID = context.selectedIDs()[0];
79283                 return continueTo(searchPresets);
79284               } else {
79285                 return chapter.restart();
79286               }
79287             });
79288
79289             function continueTo(nextStep) {
79290               context.map().on('move.intro drawn.intro', null);
79291               context.on('enter.intro', null);
79292               nextStep();
79293             }
79294           }
79295
79296           function finishPlayground() {
79297             if (context.mode().id !== 'draw-area') {
79298               return chapter.restart();
79299             }
79300
79301             _areaID = null;
79302             var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
79303             revealPlayground(playground, finishString, {
79304               duration: 250
79305             });
79306             timeout(function () {
79307               context.map().on('move.intro drawn.intro', function () {
79308                 revealPlayground(playground, finishString, {
79309                   duration: 0
79310                 });
79311               });
79312             }, 250); // after reveal
79313
79314             context.on('enter.intro', function (mode) {
79315               if (mode.id === 'draw-area') {
79316                 return;
79317               } else if (mode.id === 'select') {
79318                 _areaID = context.selectedIDs()[0];
79319                 return continueTo(searchPresets);
79320               } else {
79321                 return chapter.restart();
79322               }
79323             });
79324
79325             function continueTo(nextStep) {
79326               context.map().on('move.intro drawn.intro', null);
79327               context.on('enter.intro', null);
79328               nextStep();
79329             }
79330           }
79331
79332           function searchPresets() {
79333             if (!_areaID || !context.hasEntity(_areaID)) {
79334               return addArea();
79335             }
79336
79337             var ids = context.selectedIDs();
79338
79339             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
79340               context.enter(modeSelect(context, [_areaID]));
79341             } // disallow scrolling
79342
79343
79344             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79345             timeout(function () {
79346               // reset pane, in case user somehow happened to change it..
79347               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
79348               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79349               reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
79350                 preset: playgroundPreset.name()
79351               }));
79352             }, 400); // after preset list pane visible..
79353
79354             context.on('enter.intro', function (mode) {
79355               if (!_areaID || !context.hasEntity(_areaID)) {
79356                 return continueTo(addArea);
79357               }
79358
79359               var ids = context.selectedIDs();
79360
79361               if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
79362                 // keep the user's area selected..
79363                 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
79364
79365                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
79366
79367                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79368                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79369                 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
79370                   preset: playgroundPreset.name()
79371                 }));
79372                 context.history().on('change.intro', null);
79373               }
79374             });
79375
79376             function checkPresetSearch() {
79377               var first = context.container().select('.preset-list-item:first-child');
79378
79379               if (first.classed('preset-leisure-playground')) {
79380                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
79381                   preset: playgroundPreset.name()
79382                 }), {
79383                   duration: 300
79384                 });
79385                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79386                 context.history().on('change.intro', function () {
79387                   continueTo(clickAddField);
79388                 });
79389               }
79390             }
79391
79392             function continueTo(nextStep) {
79393               context.container().select('.inspector-wrap').on('wheel.intro', null);
79394               context.on('enter.intro', null);
79395               context.history().on('change.intro', null);
79396               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79397               nextStep();
79398             }
79399           }
79400
79401           function clickAddField() {
79402             if (!_areaID || !context.hasEntity(_areaID)) {
79403               return addArea();
79404             }
79405
79406             var ids = context.selectedIDs();
79407
79408             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
79409               return searchPresets();
79410             }
79411
79412             if (!context.container().select('.form-field-description').empty()) {
79413               return continueTo(describePlayground);
79414             } // disallow scrolling
79415
79416
79417             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79418             timeout(function () {
79419               // reset pane, in case user somehow happened to change it..
79420               context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
79421               // If they did this already, just continue to next step.
79422
79423               var entity = context.entity(_areaID);
79424
79425               if (entity.tags.description) {
79426                 return continueTo(play);
79427               } // scroll "Add field" into view
79428
79429
79430               var box = context.container().select('.more-fields').node().getBoundingClientRect();
79431
79432               if (box.top > 300) {
79433                 var pane = context.container().select('.entity-editor-pane .inspector-body');
79434                 var start = pane.node().scrollTop;
79435                 var end = start + (box.top - 300);
79436                 pane.transition().duration(250).tween('scroll.inspector', function () {
79437                   var node = this;
79438                   var i = d3_interpolateNumber(start, end);
79439                   return function (t) {
79440                     node.scrollTop = i(t);
79441                   };
79442                 });
79443               }
79444
79445               timeout(function () {
79446                 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
79447                   name: nameField.label(),
79448                   description: descriptionField.label()
79449                 }), {
79450                   duration: 300
79451                 });
79452                 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
79453                   // Watch for the combobox to appear...
79454                   var watcher;
79455                   watcher = window.setInterval(function () {
79456                     if (!context.container().select('div.combobox').empty()) {
79457                       window.clearInterval(watcher);
79458                       continueTo(chooseDescriptionField);
79459                     }
79460                   }, 300);
79461                 });
79462               }, 300); // after "Add Field" visible
79463             }, 400); // after editor pane visible
79464
79465             context.on('exit.intro', function () {
79466               return continueTo(searchPresets);
79467             });
79468
79469             function continueTo(nextStep) {
79470               context.container().select('.inspector-wrap').on('wheel.intro', null);
79471               context.container().select('.more-fields .combobox-input').on('click.intro', null);
79472               context.on('exit.intro', null);
79473               nextStep();
79474             }
79475           }
79476
79477           function chooseDescriptionField() {
79478             if (!_areaID || !context.hasEntity(_areaID)) {
79479               return addArea();
79480             }
79481
79482             var ids = context.selectedIDs();
79483
79484             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
79485               return searchPresets();
79486             }
79487
79488             if (!context.container().select('.form-field-description').empty()) {
79489               return continueTo(describePlayground);
79490             } // Make sure combobox is ready..
79491
79492
79493             if (context.container().select('div.combobox').empty()) {
79494               return continueTo(clickAddField);
79495             } // Watch for the combobox to go away..
79496
79497
79498             var watcher;
79499             watcher = window.setInterval(function () {
79500               if (context.container().select('div.combobox').empty()) {
79501                 window.clearInterval(watcher);
79502                 timeout(function () {
79503                   if (context.container().select('.form-field-description').empty()) {
79504                     continueTo(retryChooseDescription);
79505                   } else {
79506                     continueTo(describePlayground);
79507                   }
79508                 }, 300); // after description field added.
79509               }
79510             }, 300);
79511             reveal('div.combobox', helpHtml('intro.areas.choose_field', {
79512               field: descriptionField.label()
79513             }), {
79514               duration: 300
79515             });
79516             context.on('exit.intro', function () {
79517               return continueTo(searchPresets);
79518             });
79519
79520             function continueTo(nextStep) {
79521               if (watcher) window.clearInterval(watcher);
79522               context.on('exit.intro', null);
79523               nextStep();
79524             }
79525           }
79526
79527           function describePlayground() {
79528             if (!_areaID || !context.hasEntity(_areaID)) {
79529               return addArea();
79530             }
79531
79532             var ids = context.selectedIDs();
79533
79534             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
79535               return searchPresets();
79536             } // reset pane, in case user happened to change it..
79537
79538
79539             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79540
79541             if (context.container().select('.form-field-description').empty()) {
79542               return continueTo(retryChooseDescription);
79543             }
79544
79545             context.on('exit.intro', function () {
79546               continueTo(play);
79547             });
79548             reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
79549               button: icon('#iD-icon-close', 'inline')
79550             }), {
79551               duration: 300
79552             });
79553
79554             function continueTo(nextStep) {
79555               context.on('exit.intro', null);
79556               nextStep();
79557             }
79558           }
79559
79560           function retryChooseDescription() {
79561             if (!_areaID || !context.hasEntity(_areaID)) {
79562               return addArea();
79563             }
79564
79565             var ids = context.selectedIDs();
79566
79567             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
79568               return searchPresets();
79569             } // reset pane, in case user happened to change it..
79570
79571
79572             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79573             reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
79574               field: descriptionField.label()
79575             }), {
79576               buttonText: _t.html('intro.ok'),
79577               buttonCallback: function buttonCallback() {
79578                 continueTo(clickAddField);
79579               }
79580             });
79581             context.on('exit.intro', function () {
79582               return continueTo(searchPresets);
79583             });
79584
79585             function continueTo(nextStep) {
79586               context.on('exit.intro', null);
79587               nextStep();
79588             }
79589           }
79590
79591           function play() {
79592             dispatch$1.call('done');
79593             reveal('.ideditor', helpHtml('intro.areas.play', {
79594               next: _t('intro.lines.title')
79595             }), {
79596               tooltipBox: '.intro-nav-wrap .chapter-line',
79597               buttonText: _t.html('intro.ok'),
79598               buttonCallback: function buttonCallback() {
79599                 reveal('.ideditor');
79600               }
79601             });
79602           }
79603
79604           chapter.enter = function () {
79605             addArea();
79606           };
79607
79608           chapter.exit = function () {
79609             timeouts.forEach(window.clearTimeout);
79610             context.on('enter.intro exit.intro', null);
79611             context.map().on('move.intro drawn.intro', null);
79612             context.history().on('change.intro', null);
79613             context.container().select('.inspector-wrap').on('wheel.intro', null);
79614             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79615             context.container().select('.more-fields .combobox-input').on('click.intro', null);
79616           };
79617
79618           chapter.restart = function () {
79619             chapter.exit();
79620             chapter.enter();
79621           };
79622
79623           return utilRebind(chapter, dispatch$1, 'on');
79624         }
79625
79626         function uiIntroLine(context, reveal) {
79627           var dispatch$1 = dispatch('done');
79628           var timeouts = [];
79629           var _tulipRoadID = null;
79630           var flowerRoadID = 'w646';
79631           var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
79632           var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
79633           var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
79634           var roadCategory = _mainPresetIndex.item('category-road_minor');
79635           var residentialPreset = _mainPresetIndex.item('highway/residential');
79636           var woodRoadID = 'w525';
79637           var woodRoadEndID = 'n2862';
79638           var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
79639           var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
79640           var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
79641           var washingtonStreetID = 'w522';
79642           var twelfthAvenueID = 'w1';
79643           var eleventhAvenueEndID = 'n3550';
79644           var twelfthAvenueEndID = 'n5';
79645           var _washingtonSegmentID = null;
79646           var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
79647           var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
79648           var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
79649           var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
79650           var chapter = {
79651             title: 'intro.lines.title'
79652           };
79653
79654           function timeout(f, t) {
79655             timeouts.push(window.setTimeout(f, t));
79656           }
79657
79658           function eventCancel(d3_event) {
79659             d3_event.stopPropagation();
79660             d3_event.preventDefault();
79661           }
79662
79663           function addLine() {
79664             context.enter(modeBrowse(context));
79665             context.history().reset('initial');
79666             var msec = transitionTime(tulipRoadStart, context.map().center());
79667
79668             if (msec) {
79669               reveal(null, null, {
79670                 duration: 0
79671               });
79672             }
79673
79674             context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
79675             timeout(function () {
79676               var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
79677               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
79678               context.on('enter.intro', function (mode) {
79679                 if (mode.id !== 'add-line') return;
79680                 continueTo(startLine);
79681               });
79682             }, msec + 100);
79683
79684             function continueTo(nextStep) {
79685               context.on('enter.intro', null);
79686               nextStep();
79687             }
79688           }
79689
79690           function startLine() {
79691             if (context.mode().id !== 'add-line') return chapter.restart();
79692             _tulipRoadID = null;
79693             var padding = 70 * Math.pow(2, context.map().zoom() - 18);
79694             var box = pad(tulipRoadStart, padding, context);
79695             box.height = box.height + 100;
79696             var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
79697             var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
79698             reveal(box, startLineString);
79699             context.map().on('move.intro drawn.intro', function () {
79700               padding = 70 * Math.pow(2, context.map().zoom() - 18);
79701               box = pad(tulipRoadStart, padding, context);
79702               box.height = box.height + 100;
79703               reveal(box, startLineString, {
79704                 duration: 0
79705               });
79706             });
79707             context.on('enter.intro', function (mode) {
79708               if (mode.id !== 'draw-line') return chapter.restart();
79709               continueTo(drawLine);
79710             });
79711
79712             function continueTo(nextStep) {
79713               context.map().on('move.intro drawn.intro', null);
79714               context.on('enter.intro', null);
79715               nextStep();
79716             }
79717           }
79718
79719           function drawLine() {
79720             if (context.mode().id !== 'draw-line') return chapter.restart();
79721             _tulipRoadID = context.mode().selectedIDs()[0];
79722             context.map().centerEase(tulipRoadMidpoint, 500);
79723             timeout(function () {
79724               var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
79725               var box = pad(tulipRoadMidpoint, padding, context);
79726               box.height = box.height * 2;
79727               reveal(box, helpHtml('intro.lines.intersect', {
79728                 name: _t('intro.graph.name.flower-street')
79729               }));
79730               context.map().on('move.intro drawn.intro', function () {
79731                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
79732                 box = pad(tulipRoadMidpoint, padding, context);
79733                 box.height = box.height * 2;
79734                 reveal(box, helpHtml('intro.lines.intersect', {
79735                   name: _t('intro.graph.name.flower-street')
79736                 }), {
79737                   duration: 0
79738                 });
79739               });
79740             }, 550); // after easing..
79741
79742             context.history().on('change.intro', function () {
79743               if (isLineConnected()) {
79744                 continueTo(continueLine);
79745               }
79746             });
79747             context.on('enter.intro', function (mode) {
79748               if (mode.id === 'draw-line') {
79749                 return;
79750               } else if (mode.id === 'select') {
79751                 continueTo(retryIntersect);
79752                 return;
79753               } else {
79754                 return chapter.restart();
79755               }
79756             });
79757
79758             function continueTo(nextStep) {
79759               context.map().on('move.intro drawn.intro', null);
79760               context.history().on('change.intro', null);
79761               context.on('enter.intro', null);
79762               nextStep();
79763             }
79764           }
79765
79766           function isLineConnected() {
79767             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
79768
79769             if (!entity) return false;
79770             var drawNodes = context.graph().childNodes(entity);
79771             return drawNodes.some(function (node) {
79772               return context.graph().parentWays(node).some(function (parent) {
79773                 return parent.id === flowerRoadID;
79774               });
79775             });
79776           }
79777
79778           function retryIntersect() {
79779             select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
79780             var box = pad(tulipRoadIntersection, 80, context);
79781             reveal(box, helpHtml('intro.lines.retry_intersect', {
79782               name: _t('intro.graph.name.flower-street')
79783             }));
79784             timeout(chapter.restart, 3000);
79785           }
79786
79787           function continueLine() {
79788             if (context.mode().id !== 'draw-line') return chapter.restart();
79789
79790             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
79791
79792             if (!entity) return chapter.restart();
79793             context.map().centerEase(tulipRoadIntersection, 500);
79794             var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
79795             reveal('.surface', continueLineText);
79796             context.on('enter.intro', function (mode) {
79797               if (mode.id === 'draw-line') return;else if (mode.id === 'select') return continueTo(chooseCategoryRoad);else return chapter.restart();
79798             });
79799
79800             function continueTo(nextStep) {
79801               context.on('enter.intro', null);
79802               nextStep();
79803             }
79804           }
79805
79806           function chooseCategoryRoad() {
79807             if (context.mode().id !== 'select') return chapter.restart();
79808             context.on('exit.intro', function () {
79809               return chapter.restart();
79810             });
79811             var button = context.container().select('.preset-category-road_minor .preset-list-button');
79812             if (button.empty()) return chapter.restart(); // disallow scrolling
79813
79814             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79815             timeout(function () {
79816               // reset pane, in case user somehow happened to change it..
79817               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
79818               reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
79819                 category: roadCategory.name()
79820               }));
79821               button.on('click.intro', function () {
79822                 continueTo(choosePresetResidential);
79823               });
79824             }, 400); // after editor pane visible
79825
79826             function continueTo(nextStep) {
79827               context.container().select('.inspector-wrap').on('wheel.intro', null);
79828               context.container().select('.preset-list-button').on('click.intro', null);
79829               context.on('exit.intro', null);
79830               nextStep();
79831             }
79832           }
79833
79834           function choosePresetResidential() {
79835             if (context.mode().id !== 'select') return chapter.restart();
79836             context.on('exit.intro', function () {
79837               return chapter.restart();
79838             });
79839             var subgrid = context.container().select('.preset-category-road_minor .subgrid');
79840             if (subgrid.empty()) return chapter.restart();
79841             subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
79842               continueTo(retryPresetResidential);
79843             });
79844             subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
79845               continueTo(nameRoad);
79846             });
79847             timeout(function () {
79848               reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
79849                 preset: residentialPreset.name()
79850               }), {
79851                 tooltipBox: '.preset-highway-residential .preset-list-button',
79852                 duration: 300
79853               });
79854             }, 300);
79855
79856             function continueTo(nextStep) {
79857               context.container().select('.preset-list-button').on('click.intro', null);
79858               context.on('exit.intro', null);
79859               nextStep();
79860             }
79861           } // selected wrong road type
79862
79863
79864           function retryPresetResidential() {
79865             if (context.mode().id !== 'select') return chapter.restart();
79866             context.on('exit.intro', function () {
79867               return chapter.restart();
79868             }); // disallow scrolling
79869
79870             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79871             timeout(function () {
79872               var button = context.container().select('.entity-editor-pane .preset-list-button');
79873               reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
79874                 preset: residentialPreset.name()
79875               }));
79876               button.on('click.intro', function () {
79877                 continueTo(chooseCategoryRoad);
79878               });
79879             }, 500);
79880
79881             function continueTo(nextStep) {
79882               context.container().select('.inspector-wrap').on('wheel.intro', null);
79883               context.container().select('.preset-list-button').on('click.intro', null);
79884               context.on('exit.intro', null);
79885               nextStep();
79886             }
79887           }
79888
79889           function nameRoad() {
79890             context.on('exit.intro', function () {
79891               continueTo(didNameRoad);
79892             });
79893             timeout(function () {
79894               reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
79895                 button: icon('#iD-icon-close', 'inline')
79896               }), {
79897                 tooltipClass: 'intro-lines-name_road'
79898               });
79899             }, 500);
79900
79901             function continueTo(nextStep) {
79902               context.on('exit.intro', null);
79903               nextStep();
79904             }
79905           }
79906
79907           function didNameRoad() {
79908             context.history().checkpoint('doneAddLine');
79909             timeout(function () {
79910               reveal('.surface', helpHtml('intro.lines.did_name_road'), {
79911                 buttonText: _t.html('intro.ok'),
79912                 buttonCallback: function buttonCallback() {
79913                   continueTo(updateLine);
79914                 }
79915               });
79916             }, 500);
79917
79918             function continueTo(nextStep) {
79919               nextStep();
79920             }
79921           }
79922
79923           function updateLine() {
79924             context.history().reset('doneAddLine');
79925
79926             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
79927               return chapter.restart();
79928             }
79929
79930             var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
79931
79932             if (msec) {
79933               reveal(null, null, {
79934                 duration: 0
79935               });
79936             }
79937
79938             context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
79939             timeout(function () {
79940               var padding = 250 * Math.pow(2, context.map().zoom() - 19);
79941               var box = pad(woodRoadDragMidpoint, padding, context);
79942
79943               var advance = function advance() {
79944                 continueTo(addNode);
79945               };
79946
79947               reveal(box, helpHtml('intro.lines.update_line'), {
79948                 buttonText: _t.html('intro.ok'),
79949                 buttonCallback: advance
79950               });
79951               context.map().on('move.intro drawn.intro', function () {
79952                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
79953                 var box = pad(woodRoadDragMidpoint, padding, context);
79954                 reveal(box, helpHtml('intro.lines.update_line'), {
79955                   duration: 0,
79956                   buttonText: _t.html('intro.ok'),
79957                   buttonCallback: advance
79958                 });
79959               });
79960             }, msec + 100);
79961
79962             function continueTo(nextStep) {
79963               context.map().on('move.intro drawn.intro', null);
79964               nextStep();
79965             }
79966           }
79967
79968           function addNode() {
79969             context.history().reset('doneAddLine');
79970
79971             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
79972               return chapter.restart();
79973             }
79974
79975             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
79976             var box = pad(woodRoadAddNode, padding, context);
79977             var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
79978             reveal(box, addNodeString);
79979             context.map().on('move.intro drawn.intro', function () {
79980               var padding = 40 * Math.pow(2, context.map().zoom() - 19);
79981               var box = pad(woodRoadAddNode, padding, context);
79982               reveal(box, addNodeString, {
79983                 duration: 0
79984               });
79985             });
79986             context.history().on('change.intro', function (changed) {
79987               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
79988                 return continueTo(updateLine);
79989               }
79990
79991               if (changed.created().length === 1) {
79992                 timeout(function () {
79993                   continueTo(startDragEndpoint);
79994                 }, 500);
79995               }
79996             });
79997             context.on('enter.intro', function (mode) {
79998               if (mode.id !== 'select') {
79999                 continueTo(updateLine);
80000               }
80001             });
80002
80003             function continueTo(nextStep) {
80004               context.map().on('move.intro drawn.intro', null);
80005               context.history().on('change.intro', null);
80006               context.on('enter.intro', null);
80007               nextStep();
80008             }
80009           }
80010
80011           function startDragEndpoint() {
80012             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80013               return continueTo(updateLine);
80014             }
80015
80016             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80017             var box = pad(woodRoadDragEndpoint, padding, context);
80018             var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
80019             reveal(box, startDragString);
80020             context.map().on('move.intro drawn.intro', function () {
80021               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80022                 return continueTo(updateLine);
80023               }
80024
80025               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80026               var box = pad(woodRoadDragEndpoint, padding, context);
80027               reveal(box, startDragString, {
80028                 duration: 0
80029               });
80030               var entity = context.entity(woodRoadEndID);
80031
80032               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
80033                 continueTo(finishDragEndpoint);
80034               }
80035             });
80036
80037             function continueTo(nextStep) {
80038               context.map().on('move.intro drawn.intro', null);
80039               nextStep();
80040             }
80041           }
80042
80043           function finishDragEndpoint() {
80044             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80045               return continueTo(updateLine);
80046             }
80047
80048             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80049             var box = pad(woodRoadDragEndpoint, padding, context);
80050             var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
80051             reveal(box, finishDragString);
80052             context.map().on('move.intro drawn.intro', function () {
80053               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80054                 return continueTo(updateLine);
80055               }
80056
80057               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80058               var box = pad(woodRoadDragEndpoint, padding, context);
80059               reveal(box, finishDragString, {
80060                 duration: 0
80061               });
80062               var entity = context.entity(woodRoadEndID);
80063
80064               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
80065                 continueTo(startDragEndpoint);
80066               }
80067             });
80068             context.on('enter.intro', function () {
80069               continueTo(startDragMidpoint);
80070             });
80071
80072             function continueTo(nextStep) {
80073               context.map().on('move.intro drawn.intro', null);
80074               context.on('enter.intro', null);
80075               nextStep();
80076             }
80077           }
80078
80079           function startDragMidpoint() {
80080             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80081               return continueTo(updateLine);
80082             }
80083
80084             if (context.selectedIDs().indexOf(woodRoadID) === -1) {
80085               context.enter(modeSelect(context, [woodRoadID]));
80086             }
80087
80088             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
80089             var box = pad(woodRoadDragMidpoint, padding, context);
80090             reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
80091             context.map().on('move.intro drawn.intro', function () {
80092               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80093                 return continueTo(updateLine);
80094               }
80095
80096               var padding = 80 * Math.pow(2, context.map().zoom() - 19);
80097               var box = pad(woodRoadDragMidpoint, padding, context);
80098               reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
80099                 duration: 0
80100               });
80101             });
80102             context.history().on('change.intro', function (changed) {
80103               if (changed.created().length === 1) {
80104                 continueTo(continueDragMidpoint);
80105               }
80106             });
80107             context.on('enter.intro', function (mode) {
80108               if (mode.id !== 'select') {
80109                 // keep Wood Road selected so midpoint triangles are drawn..
80110                 context.enter(modeSelect(context, [woodRoadID]));
80111               }
80112             });
80113
80114             function continueTo(nextStep) {
80115               context.map().on('move.intro drawn.intro', null);
80116               context.history().on('change.intro', null);
80117               context.on('enter.intro', null);
80118               nextStep();
80119             }
80120           }
80121
80122           function continueDragMidpoint() {
80123             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80124               return continueTo(updateLine);
80125             }
80126
80127             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80128             var box = pad(woodRoadDragEndpoint, padding, context);
80129             box.height += 400;
80130
80131             var advance = function advance() {
80132               context.history().checkpoint('doneUpdateLine');
80133               continueTo(deleteLines);
80134             };
80135
80136             reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
80137               buttonText: _t.html('intro.ok'),
80138               buttonCallback: advance
80139             });
80140             context.map().on('move.intro drawn.intro', function () {
80141               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80142                 return continueTo(updateLine);
80143               }
80144
80145               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80146               var box = pad(woodRoadDragEndpoint, padding, context);
80147               box.height += 400;
80148               reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
80149                 duration: 0,
80150                 buttonText: _t.html('intro.ok'),
80151                 buttonCallback: advance
80152               });
80153             });
80154
80155             function continueTo(nextStep) {
80156               context.map().on('move.intro drawn.intro', null);
80157               nextStep();
80158             }
80159           }
80160
80161           function deleteLines() {
80162             context.history().reset('doneUpdateLine');
80163             context.enter(modeBrowse(context));
80164
80165             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80166               return chapter.restart();
80167             }
80168
80169             var msec = transitionTime(deleteLinesLoc, context.map().center());
80170
80171             if (msec) {
80172               reveal(null, null, {
80173                 duration: 0
80174               });
80175             }
80176
80177             context.map().centerZoomEase(deleteLinesLoc, 18, msec);
80178             timeout(function () {
80179               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80180               var box = pad(deleteLinesLoc, padding, context);
80181               box.top -= 200;
80182               box.height += 400;
80183
80184               var advance = function advance() {
80185                 continueTo(rightClickIntersection);
80186               };
80187
80188               reveal(box, helpHtml('intro.lines.delete_lines', {
80189                 street: _t('intro.graph.name.12th-avenue')
80190               }), {
80191                 buttonText: _t.html('intro.ok'),
80192                 buttonCallback: advance
80193               });
80194               context.map().on('move.intro drawn.intro', function () {
80195                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80196                 var box = pad(deleteLinesLoc, padding, context);
80197                 box.top -= 200;
80198                 box.height += 400;
80199                 reveal(box, helpHtml('intro.lines.delete_lines', {
80200                   street: _t('intro.graph.name.12th-avenue')
80201                 }), {
80202                   duration: 0,
80203                   buttonText: _t.html('intro.ok'),
80204                   buttonCallback: advance
80205                 });
80206               });
80207               context.history().on('change.intro', function () {
80208                 timeout(function () {
80209                   continueTo(deleteLines);
80210                 }, 500); // after any transition (e.g. if user deleted intersection)
80211               });
80212             }, msec + 100);
80213
80214             function continueTo(nextStep) {
80215               context.map().on('move.intro drawn.intro', null);
80216               context.history().on('change.intro', null);
80217               nextStep();
80218             }
80219           }
80220
80221           function rightClickIntersection() {
80222             context.history().reset('doneUpdateLine');
80223             context.enter(modeBrowse(context));
80224             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
80225             var rightClickString = helpHtml('intro.lines.split_street', {
80226               street1: _t('intro.graph.name.11th-avenue'),
80227               street2: _t('intro.graph.name.washington-street')
80228             }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
80229             timeout(function () {
80230               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
80231               var box = pad(eleventhAvenueEnd, padding, context);
80232               reveal(box, rightClickString);
80233               context.map().on('move.intro drawn.intro', function () {
80234                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
80235                 var box = pad(eleventhAvenueEnd, padding, context);
80236                 reveal(box, rightClickString, {
80237                   duration: 0
80238                 });
80239               });
80240               context.on('enter.intro', function (mode) {
80241                 if (mode.id !== 'select') return;
80242                 var ids = context.selectedIDs();
80243                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
80244                 timeout(function () {
80245                   var node = selectMenuItem(context, 'split').node();
80246                   if (!node) return;
80247                   continueTo(splitIntersection);
80248                 }, 50); // after menu visible
80249               });
80250               context.history().on('change.intro', function () {
80251                 timeout(function () {
80252                   continueTo(deleteLines);
80253                 }, 300); // after any transition (e.g. if user deleted intersection)
80254               });
80255             }, 600);
80256
80257             function continueTo(nextStep) {
80258               context.map().on('move.intro drawn.intro', null);
80259               context.on('enter.intro', null);
80260               context.history().on('change.intro', null);
80261               nextStep();
80262             }
80263           }
80264
80265           function splitIntersection() {
80266             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80267               return continueTo(deleteLines);
80268             }
80269
80270             var node = selectMenuItem(context, 'split').node();
80271
80272             if (!node) {
80273               return continueTo(rightClickIntersection);
80274             }
80275
80276             var wasChanged = false;
80277             _washingtonSegmentID = null;
80278             reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
80279               street: _t('intro.graph.name.washington-street')
80280             }), {
80281               padding: 50
80282             });
80283             context.map().on('move.intro drawn.intro', function () {
80284               var node = selectMenuItem(context, 'split').node();
80285
80286               if (!wasChanged && !node) {
80287                 return continueTo(rightClickIntersection);
80288               }
80289
80290               reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
80291                 street: _t('intro.graph.name.washington-street')
80292               }), {
80293                 duration: 0,
80294                 padding: 50
80295               });
80296             });
80297             context.history().on('change.intro', function (changed) {
80298               wasChanged = true;
80299               timeout(function () {
80300                 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
80301                   n: 1
80302                 })) {
80303                   _washingtonSegmentID = changed.created()[0].id;
80304                   continueTo(didSplit);
80305                 } else {
80306                   _washingtonSegmentID = null;
80307                   continueTo(retrySplit);
80308                 }
80309               }, 300); // after any transition (e.g. if user deleted intersection)
80310             });
80311
80312             function continueTo(nextStep) {
80313               context.map().on('move.intro drawn.intro', null);
80314               context.history().on('change.intro', null);
80315               nextStep();
80316             }
80317           }
80318
80319           function retrySplit() {
80320             context.enter(modeBrowse(context));
80321             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
80322
80323             var advance = function advance() {
80324               continueTo(rightClickIntersection);
80325             };
80326
80327             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
80328             var box = pad(eleventhAvenueEnd, padding, context);
80329             reveal(box, helpHtml('intro.lines.retry_split'), {
80330               buttonText: _t.html('intro.ok'),
80331               buttonCallback: advance
80332             });
80333             context.map().on('move.intro drawn.intro', function () {
80334               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
80335               var box = pad(eleventhAvenueEnd, padding, context);
80336               reveal(box, helpHtml('intro.lines.retry_split'), {
80337                 duration: 0,
80338                 buttonText: _t.html('intro.ok'),
80339                 buttonCallback: advance
80340               });
80341             });
80342
80343             function continueTo(nextStep) {
80344               context.map().on('move.intro drawn.intro', null);
80345               nextStep();
80346             }
80347           }
80348
80349           function didSplit() {
80350             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80351               return continueTo(rightClickIntersection);
80352             }
80353
80354             var ids = context.selectedIDs();
80355             var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
80356             var street = _t('intro.graph.name.washington-street');
80357             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80358             var box = pad(twelfthAvenue, padding, context);
80359             box.width = box.width / 2;
80360             reveal(box, helpHtml(string, {
80361               street1: street,
80362               street2: street
80363             }), {
80364               duration: 500
80365             });
80366             timeout(function () {
80367               context.map().centerZoomEase(twelfthAvenue, 18, 500);
80368               context.map().on('move.intro drawn.intro', function () {
80369                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80370                 var box = pad(twelfthAvenue, padding, context);
80371                 box.width = box.width / 2;
80372                 reveal(box, helpHtml(string, {
80373                   street1: street,
80374                   street2: street
80375                 }), {
80376                   duration: 0
80377                 });
80378               });
80379             }, 600); // after initial reveal and curtain cut
80380
80381             context.on('enter.intro', function () {
80382               var ids = context.selectedIDs();
80383
80384               if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
80385                 continueTo(multiSelect);
80386               }
80387             });
80388             context.history().on('change.intro', function () {
80389               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80390                 return continueTo(rightClickIntersection);
80391               }
80392             });
80393
80394             function continueTo(nextStep) {
80395               context.map().on('move.intro drawn.intro', null);
80396               context.on('enter.intro', null);
80397               context.history().on('change.intro', null);
80398               nextStep();
80399             }
80400           }
80401
80402           function multiSelect() {
80403             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80404               return continueTo(rightClickIntersection);
80405             }
80406
80407             var ids = context.selectedIDs();
80408             var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
80409             var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
80410
80411             if (hasWashington && hasTwelfth) {
80412               return continueTo(multiRightClick);
80413             } else if (!hasWashington && !hasTwelfth) {
80414               return continueTo(didSplit);
80415             }
80416
80417             context.map().centerZoomEase(twelfthAvenue, 18, 500);
80418             timeout(function () {
80419               var selected, other, padding, box;
80420
80421               if (hasWashington) {
80422                 selected = _t('intro.graph.name.washington-street');
80423                 other = _t('intro.graph.name.12th-avenue');
80424                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
80425                 box = pad(twelfthAvenueEnd, padding, context);
80426                 box.width *= 3;
80427               } else {
80428                 selected = _t('intro.graph.name.12th-avenue');
80429                 other = _t('intro.graph.name.washington-street');
80430                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
80431                 box = pad(twelfthAvenue, padding, context);
80432                 box.width /= 2;
80433               }
80434
80435               reveal(box, helpHtml('intro.lines.multi_select', {
80436                 selected: selected,
80437                 other1: other
80438               }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
80439                 selected: selected,
80440                 other2: other
80441               }));
80442               context.map().on('move.intro drawn.intro', function () {
80443                 if (hasWashington) {
80444                   selected = _t('intro.graph.name.washington-street');
80445                   other = _t('intro.graph.name.12th-avenue');
80446                   padding = 60 * Math.pow(2, context.map().zoom() - 18);
80447                   box = pad(twelfthAvenueEnd, padding, context);
80448                   box.width *= 3;
80449                 } else {
80450                   selected = _t('intro.graph.name.12th-avenue');
80451                   other = _t('intro.graph.name.washington-street');
80452                   padding = 200 * Math.pow(2, context.map().zoom() - 18);
80453                   box = pad(twelfthAvenue, padding, context);
80454                   box.width /= 2;
80455                 }
80456
80457                 reveal(box, helpHtml('intro.lines.multi_select', {
80458                   selected: selected,
80459                   other1: other
80460                 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
80461                   selected: selected,
80462                   other2: other
80463                 }), {
80464                   duration: 0
80465                 });
80466               });
80467               context.on('enter.intro', function () {
80468                 continueTo(multiSelect);
80469               });
80470               context.history().on('change.intro', function () {
80471                 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80472                   return continueTo(rightClickIntersection);
80473                 }
80474               });
80475             }, 600);
80476
80477             function continueTo(nextStep) {
80478               context.map().on('move.intro drawn.intro', null);
80479               context.on('enter.intro', null);
80480               context.history().on('change.intro', null);
80481               nextStep();
80482             }
80483           }
80484
80485           function multiRightClick() {
80486             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80487               return continueTo(rightClickIntersection);
80488             }
80489
80490             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80491             var box = pad(twelfthAvenue, padding, context);
80492             var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
80493             reveal(box, rightClickString);
80494             context.map().on('move.intro drawn.intro', function () {
80495               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80496               var box = pad(twelfthAvenue, padding, context);
80497               reveal(box, rightClickString, {
80498                 duration: 0
80499               });
80500             });
80501             context.ui().editMenu().on('toggled.intro', function (open) {
80502               if (!open) return;
80503               timeout(function () {
80504                 var ids = context.selectedIDs();
80505
80506                 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
80507                   var node = selectMenuItem(context, 'delete').node();
80508                   if (!node) return;
80509                   continueTo(multiDelete);
80510                 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
80511                   return continueTo(multiSelect);
80512                 } else {
80513                   return continueTo(didSplit);
80514                 }
80515               }, 300); // after edit menu visible
80516             });
80517             context.history().on('change.intro', function () {
80518               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80519                 return continueTo(rightClickIntersection);
80520               }
80521             });
80522
80523             function continueTo(nextStep) {
80524               context.map().on('move.intro drawn.intro', null);
80525               context.ui().editMenu().on('toggled.intro', null);
80526               context.history().on('change.intro', null);
80527               nextStep();
80528             }
80529           }
80530
80531           function multiDelete() {
80532             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
80533               return continueTo(rightClickIntersection);
80534             }
80535
80536             var node = selectMenuItem(context, 'delete').node();
80537             if (!node) return continueTo(multiRightClick);
80538             reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
80539               padding: 50
80540             });
80541             context.map().on('move.intro drawn.intro', function () {
80542               reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
80543                 duration: 0,
80544                 padding: 50
80545               });
80546             });
80547             context.on('exit.intro', function () {
80548               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
80549                 return continueTo(multiSelect); // left select mode but roads still exist
80550               }
80551             });
80552             context.history().on('change.intro', function () {
80553               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
80554                 continueTo(retryDelete); // changed something but roads still exist
80555               } else {
80556                 continueTo(play);
80557               }
80558             });
80559
80560             function continueTo(nextStep) {
80561               context.map().on('move.intro drawn.intro', null);
80562               context.on('exit.intro', null);
80563               context.history().on('change.intro', null);
80564               nextStep();
80565             }
80566           }
80567
80568           function retryDelete() {
80569             context.enter(modeBrowse(context));
80570             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
80571             var box = pad(twelfthAvenue, padding, context);
80572             reveal(box, helpHtml('intro.lines.retry_delete'), {
80573               buttonText: _t.html('intro.ok'),
80574               buttonCallback: function buttonCallback() {
80575                 continueTo(multiSelect);
80576               }
80577             });
80578
80579             function continueTo(nextStep) {
80580               nextStep();
80581             }
80582           }
80583
80584           function play() {
80585             dispatch$1.call('done');
80586             reveal('.ideditor', helpHtml('intro.lines.play', {
80587               next: _t('intro.buildings.title')
80588             }), {
80589               tooltipBox: '.intro-nav-wrap .chapter-building',
80590               buttonText: _t.html('intro.ok'),
80591               buttonCallback: function buttonCallback() {
80592                 reveal('.ideditor');
80593               }
80594             });
80595           }
80596
80597           chapter.enter = function () {
80598             addLine();
80599           };
80600
80601           chapter.exit = function () {
80602             timeouts.forEach(window.clearTimeout);
80603             select(window).on('pointerdown.intro mousedown.intro', null, true);
80604             context.on('enter.intro exit.intro', null);
80605             context.map().on('move.intro drawn.intro', null);
80606             context.history().on('change.intro', null);
80607             context.container().select('.inspector-wrap').on('wheel.intro', null);
80608             context.container().select('.preset-list-button').on('click.intro', null);
80609           };
80610
80611           chapter.restart = function () {
80612             chapter.exit();
80613             chapter.enter();
80614           };
80615
80616           return utilRebind(chapter, dispatch$1, 'on');
80617         }
80618
80619         function uiIntroBuilding(context, reveal) {
80620           var dispatch$1 = dispatch('done');
80621           var house = [-85.62815, 41.95638];
80622           var tank = [-85.62732, 41.95347];
80623           var buildingCatetory = _mainPresetIndex.item('category-building');
80624           var housePreset = _mainPresetIndex.item('building/house');
80625           var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
80626           var timeouts = [];
80627           var _houseID = null;
80628           var _tankID = null;
80629           var chapter = {
80630             title: 'intro.buildings.title'
80631           };
80632
80633           function timeout(f, t) {
80634             timeouts.push(window.setTimeout(f, t));
80635           }
80636
80637           function eventCancel(d3_event) {
80638             d3_event.stopPropagation();
80639             d3_event.preventDefault();
80640           }
80641
80642           function revealHouse(center, text, options) {
80643             var padding = 160 * Math.pow(2, context.map().zoom() - 20);
80644             var box = pad(center, padding, context);
80645             reveal(box, text, options);
80646           }
80647
80648           function revealTank(center, text, options) {
80649             var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
80650             var box = pad(center, padding, context);
80651             reveal(box, text, options);
80652           }
80653
80654           function addHouse() {
80655             context.enter(modeBrowse(context));
80656             context.history().reset('initial');
80657             _houseID = null;
80658             var msec = transitionTime(house, context.map().center());
80659
80660             if (msec) {
80661               reveal(null, null, {
80662                 duration: 0
80663               });
80664             }
80665
80666             context.map().centerZoomEase(house, 19, msec);
80667             timeout(function () {
80668               var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
80669               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
80670               context.on('enter.intro', function (mode) {
80671                 if (mode.id !== 'add-area') return;
80672                 continueTo(startHouse);
80673               });
80674             }, msec + 100);
80675
80676             function continueTo(nextStep) {
80677               context.on('enter.intro', null);
80678               nextStep();
80679             }
80680           }
80681
80682           function startHouse() {
80683             if (context.mode().id !== 'add-area') {
80684               return continueTo(addHouse);
80685             }
80686
80687             _houseID = null;
80688             context.map().zoomEase(20, 500);
80689             timeout(function () {
80690               var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
80691               revealHouse(house, startString);
80692               context.map().on('move.intro drawn.intro', function () {
80693                 revealHouse(house, startString, {
80694                   duration: 0
80695                 });
80696               });
80697               context.on('enter.intro', function (mode) {
80698                 if (mode.id !== 'draw-area') return chapter.restart();
80699                 continueTo(continueHouse);
80700               });
80701             }, 550); // after easing
80702
80703             function continueTo(nextStep) {
80704               context.map().on('move.intro drawn.intro', null);
80705               context.on('enter.intro', null);
80706               nextStep();
80707             }
80708           }
80709
80710           function continueHouse() {
80711             if (context.mode().id !== 'draw-area') {
80712               return continueTo(addHouse);
80713             }
80714
80715             _houseID = null;
80716             var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
80717             revealHouse(house, continueString);
80718             context.map().on('move.intro drawn.intro', function () {
80719               revealHouse(house, continueString, {
80720                 duration: 0
80721               });
80722             });
80723             context.on('enter.intro', function (mode) {
80724               if (mode.id === 'draw-area') {
80725                 return;
80726               } else if (mode.id === 'select') {
80727                 var graph = context.graph();
80728                 var way = context.entity(context.selectedIDs()[0]);
80729                 var nodes = graph.childNodes(way);
80730                 var points = utilArrayUniq(nodes).map(function (n) {
80731                   return context.projection(n.loc);
80732                 });
80733
80734                 if (isMostlySquare(points)) {
80735                   _houseID = way.id;
80736                   return continueTo(chooseCategoryBuilding);
80737                 } else {
80738                   return continueTo(retryHouse);
80739                 }
80740               } else {
80741                 return chapter.restart();
80742               }
80743             });
80744
80745             function continueTo(nextStep) {
80746               context.map().on('move.intro drawn.intro', null);
80747               context.on('enter.intro', null);
80748               nextStep();
80749             }
80750           }
80751
80752           function retryHouse() {
80753             var onClick = function onClick() {
80754               continueTo(addHouse);
80755             };
80756
80757             revealHouse(house, helpHtml('intro.buildings.retry_building'), {
80758               buttonText: _t.html('intro.ok'),
80759               buttonCallback: onClick
80760             });
80761             context.map().on('move.intro drawn.intro', function () {
80762               revealHouse(house, helpHtml('intro.buildings.retry_building'), {
80763                 duration: 0,
80764                 buttonText: _t.html('intro.ok'),
80765                 buttonCallback: onClick
80766               });
80767             });
80768
80769             function continueTo(nextStep) {
80770               context.map().on('move.intro drawn.intro', null);
80771               nextStep();
80772             }
80773           }
80774
80775           function chooseCategoryBuilding() {
80776             if (!_houseID || !context.hasEntity(_houseID)) {
80777               return addHouse();
80778             }
80779
80780             var ids = context.selectedIDs();
80781
80782             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
80783               context.enter(modeSelect(context, [_houseID]));
80784             } // disallow scrolling
80785
80786
80787             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80788             timeout(function () {
80789               // reset pane, in case user somehow happened to change it..
80790               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80791               var button = context.container().select('.preset-category-building .preset-list-button');
80792               reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
80793                 category: buildingCatetory.name()
80794               }));
80795               button.on('click.intro', function () {
80796                 button.on('click.intro', null);
80797                 continueTo(choosePresetHouse);
80798               });
80799             }, 400); // after preset list pane visible..
80800
80801             context.on('enter.intro', function (mode) {
80802               if (!_houseID || !context.hasEntity(_houseID)) {
80803                 return continueTo(addHouse);
80804               }
80805
80806               var ids = context.selectedIDs();
80807
80808               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
80809                 return continueTo(chooseCategoryBuilding);
80810               }
80811             });
80812
80813             function continueTo(nextStep) {
80814               context.container().select('.inspector-wrap').on('wheel.intro', null);
80815               context.container().select('.preset-list-button').on('click.intro', null);
80816               context.on('enter.intro', null);
80817               nextStep();
80818             }
80819           }
80820
80821           function choosePresetHouse() {
80822             if (!_houseID || !context.hasEntity(_houseID)) {
80823               return addHouse();
80824             }
80825
80826             var ids = context.selectedIDs();
80827
80828             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
80829               context.enter(modeSelect(context, [_houseID]));
80830             } // disallow scrolling
80831
80832
80833             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80834             timeout(function () {
80835               // reset pane, in case user somehow happened to change it..
80836               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80837               var button = context.container().select('.preset-building-house .preset-list-button');
80838               reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
80839                 preset: housePreset.name()
80840               }), {
80841                 duration: 300
80842               });
80843               button.on('click.intro', function () {
80844                 button.on('click.intro', null);
80845                 continueTo(closeEditorHouse);
80846               });
80847             }, 400); // after preset list pane visible..
80848
80849             context.on('enter.intro', function (mode) {
80850               if (!_houseID || !context.hasEntity(_houseID)) {
80851                 return continueTo(addHouse);
80852               }
80853
80854               var ids = context.selectedIDs();
80855
80856               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
80857                 return continueTo(chooseCategoryBuilding);
80858               }
80859             });
80860
80861             function continueTo(nextStep) {
80862               context.container().select('.inspector-wrap').on('wheel.intro', null);
80863               context.container().select('.preset-list-button').on('click.intro', null);
80864               context.on('enter.intro', null);
80865               nextStep();
80866             }
80867           }
80868
80869           function closeEditorHouse() {
80870             if (!_houseID || !context.hasEntity(_houseID)) {
80871               return addHouse();
80872             }
80873
80874             var ids = context.selectedIDs();
80875
80876             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
80877               context.enter(modeSelect(context, [_houseID]));
80878             }
80879
80880             context.history().checkpoint('hasHouse');
80881             context.on('exit.intro', function () {
80882               continueTo(rightClickHouse);
80883             });
80884             timeout(function () {
80885               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
80886                 button: icon('#iD-icon-close', 'inline')
80887               }));
80888             }, 500);
80889
80890             function continueTo(nextStep) {
80891               context.on('exit.intro', null);
80892               nextStep();
80893             }
80894           }
80895
80896           function rightClickHouse() {
80897             if (!_houseID) return chapter.restart();
80898             context.enter(modeBrowse(context));
80899             context.history().reset('hasHouse');
80900             var zoom = context.map().zoom();
80901
80902             if (zoom < 20) {
80903               zoom = 20;
80904             }
80905
80906             context.map().centerZoomEase(house, zoom, 500);
80907             context.on('enter.intro', function (mode) {
80908               if (mode.id !== 'select') return;
80909               var ids = context.selectedIDs();
80910               if (ids.length !== 1 || ids[0] !== _houseID) return;
80911               timeout(function () {
80912                 var node = selectMenuItem(context, 'orthogonalize').node();
80913                 if (!node) return;
80914                 continueTo(clickSquare);
80915               }, 50); // after menu visible
80916             });
80917             context.map().on('move.intro drawn.intro', function () {
80918               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
80919               revealHouse(house, rightclickString, {
80920                 duration: 0
80921               });
80922             });
80923             context.history().on('change.intro', function () {
80924               continueTo(rightClickHouse);
80925             });
80926
80927             function continueTo(nextStep) {
80928               context.on('enter.intro', null);
80929               context.map().on('move.intro drawn.intro', null);
80930               context.history().on('change.intro', null);
80931               nextStep();
80932             }
80933           }
80934
80935           function clickSquare() {
80936             if (!_houseID) return chapter.restart();
80937             var entity = context.hasEntity(_houseID);
80938             if (!entity) return continueTo(rightClickHouse);
80939             var node = selectMenuItem(context, 'orthogonalize').node();
80940
80941             if (!node) {
80942               return continueTo(rightClickHouse);
80943             }
80944
80945             var wasChanged = false;
80946             reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
80947               padding: 50
80948             });
80949             context.on('enter.intro', function (mode) {
80950               if (mode.id === 'browse') {
80951                 continueTo(rightClickHouse);
80952               } else if (mode.id === 'move' || mode.id === 'rotate') {
80953                 continueTo(retryClickSquare);
80954               }
80955             });
80956             context.map().on('move.intro', function () {
80957               var node = selectMenuItem(context, 'orthogonalize').node();
80958
80959               if (!wasChanged && !node) {
80960                 return continueTo(rightClickHouse);
80961               }
80962
80963               reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
80964                 duration: 0,
80965                 padding: 50
80966               });
80967             });
80968             context.history().on('change.intro', function () {
80969               wasChanged = true;
80970               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
80971
80972               timeout(function () {
80973                 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
80974                   n: 1
80975                 })) {
80976                   continueTo(doneSquare);
80977                 } else {
80978                   continueTo(retryClickSquare);
80979                 }
80980               }, 500); // after transitioned actions
80981             });
80982
80983             function continueTo(nextStep) {
80984               context.on('enter.intro', null);
80985               context.map().on('move.intro', null);
80986               context.history().on('change.intro', null);
80987               nextStep();
80988             }
80989           }
80990
80991           function retryClickSquare() {
80992             context.enter(modeBrowse(context));
80993             revealHouse(house, helpHtml('intro.buildings.retry_square'), {
80994               buttonText: _t.html('intro.ok'),
80995               buttonCallback: function buttonCallback() {
80996                 continueTo(rightClickHouse);
80997               }
80998             });
80999
81000             function continueTo(nextStep) {
81001               nextStep();
81002             }
81003           }
81004
81005           function doneSquare() {
81006             context.history().checkpoint('doneSquare');
81007             revealHouse(house, helpHtml('intro.buildings.done_square'), {
81008               buttonText: _t.html('intro.ok'),
81009               buttonCallback: function buttonCallback() {
81010                 continueTo(addTank);
81011               }
81012             });
81013
81014             function continueTo(nextStep) {
81015               nextStep();
81016             }
81017           }
81018
81019           function addTank() {
81020             context.enter(modeBrowse(context));
81021             context.history().reset('doneSquare');
81022             _tankID = null;
81023             var msec = transitionTime(tank, context.map().center());
81024
81025             if (msec) {
81026               reveal(null, null, {
81027                 duration: 0
81028               });
81029             }
81030
81031             context.map().centerZoomEase(tank, 19.5, msec);
81032             timeout(function () {
81033               reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
81034               context.on('enter.intro', function (mode) {
81035                 if (mode.id !== 'add-area') return;
81036                 continueTo(startTank);
81037               });
81038             }, msec + 100);
81039
81040             function continueTo(nextStep) {
81041               context.on('enter.intro', null);
81042               nextStep();
81043             }
81044           }
81045
81046           function startTank() {
81047             if (context.mode().id !== 'add-area') {
81048               return continueTo(addTank);
81049             }
81050
81051             _tankID = null;
81052             timeout(function () {
81053               var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
81054               revealTank(tank, startString);
81055               context.map().on('move.intro drawn.intro', function () {
81056                 revealTank(tank, startString, {
81057                   duration: 0
81058                 });
81059               });
81060               context.on('enter.intro', function (mode) {
81061                 if (mode.id !== 'draw-area') return chapter.restart();
81062                 continueTo(continueTank);
81063               });
81064             }, 550); // after easing
81065
81066             function continueTo(nextStep) {
81067               context.map().on('move.intro drawn.intro', null);
81068               context.on('enter.intro', null);
81069               nextStep();
81070             }
81071           }
81072
81073           function continueTank() {
81074             if (context.mode().id !== 'draw-area') {
81075               return continueTo(addTank);
81076             }
81077
81078             _tankID = null;
81079             var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
81080             revealTank(tank, continueString);
81081             context.map().on('move.intro drawn.intro', function () {
81082               revealTank(tank, continueString, {
81083                 duration: 0
81084               });
81085             });
81086             context.on('enter.intro', function (mode) {
81087               if (mode.id === 'draw-area') {
81088                 return;
81089               } else if (mode.id === 'select') {
81090                 _tankID = context.selectedIDs()[0];
81091                 return continueTo(searchPresetTank);
81092               } else {
81093                 return continueTo(addTank);
81094               }
81095             });
81096
81097             function continueTo(nextStep) {
81098               context.map().on('move.intro drawn.intro', null);
81099               context.on('enter.intro', null);
81100               nextStep();
81101             }
81102           }
81103
81104           function searchPresetTank() {
81105             if (!_tankID || !context.hasEntity(_tankID)) {
81106               return addTank();
81107             }
81108
81109             var ids = context.selectedIDs();
81110
81111             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
81112               context.enter(modeSelect(context, [_tankID]));
81113             } // disallow scrolling
81114
81115
81116             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81117             timeout(function () {
81118               // reset pane, in case user somehow happened to change it..
81119               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81120               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
81121               reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
81122                 preset: tankPreset.name()
81123               }));
81124             }, 400); // after preset list pane visible..
81125
81126             context.on('enter.intro', function (mode) {
81127               if (!_tankID || !context.hasEntity(_tankID)) {
81128                 return continueTo(addTank);
81129               }
81130
81131               var ids = context.selectedIDs();
81132
81133               if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
81134                 // keep the user's area selected..
81135                 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
81136
81137                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
81138
81139                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81140                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
81141                 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
81142                   preset: tankPreset.name()
81143                 }));
81144                 context.history().on('change.intro', null);
81145               }
81146             });
81147
81148             function checkPresetSearch() {
81149               var first = context.container().select('.preset-list-item:first-child');
81150
81151               if (first.classed('preset-man_made-storage_tank')) {
81152                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
81153                   preset: tankPreset.name()
81154                 }), {
81155                   duration: 300
81156                 });
81157                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
81158                 context.history().on('change.intro', function () {
81159                   continueTo(closeEditorTank);
81160                 });
81161               }
81162             }
81163
81164             function continueTo(nextStep) {
81165               context.container().select('.inspector-wrap').on('wheel.intro', null);
81166               context.on('enter.intro', null);
81167               context.history().on('change.intro', null);
81168               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
81169               nextStep();
81170             }
81171           }
81172
81173           function closeEditorTank() {
81174             if (!_tankID || !context.hasEntity(_tankID)) {
81175               return addTank();
81176             }
81177
81178             var ids = context.selectedIDs();
81179
81180             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
81181               context.enter(modeSelect(context, [_tankID]));
81182             }
81183
81184             context.history().checkpoint('hasTank');
81185             context.on('exit.intro', function () {
81186               continueTo(rightClickTank);
81187             });
81188             timeout(function () {
81189               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
81190                 button: icon('#iD-icon-close', 'inline')
81191               }));
81192             }, 500);
81193
81194             function continueTo(nextStep) {
81195               context.on('exit.intro', null);
81196               nextStep();
81197             }
81198           }
81199
81200           function rightClickTank() {
81201             if (!_tankID) return continueTo(addTank);
81202             context.enter(modeBrowse(context));
81203             context.history().reset('hasTank');
81204             context.map().centerEase(tank, 500);
81205             timeout(function () {
81206               context.on('enter.intro', function (mode) {
81207                 if (mode.id !== 'select') return;
81208                 var ids = context.selectedIDs();
81209                 if (ids.length !== 1 || ids[0] !== _tankID) return;
81210                 timeout(function () {
81211                   var node = selectMenuItem(context, 'circularize').node();
81212                   if (!node) return;
81213                   continueTo(clickCircle);
81214                 }, 50); // after menu visible
81215               });
81216               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
81217               revealTank(tank, rightclickString);
81218               context.map().on('move.intro drawn.intro', function () {
81219                 revealTank(tank, rightclickString, {
81220                   duration: 0
81221                 });
81222               });
81223               context.history().on('change.intro', function () {
81224                 continueTo(rightClickTank);
81225               });
81226             }, 600);
81227
81228             function continueTo(nextStep) {
81229               context.on('enter.intro', null);
81230               context.map().on('move.intro drawn.intro', null);
81231               context.history().on('change.intro', null);
81232               nextStep();
81233             }
81234           }
81235
81236           function clickCircle() {
81237             if (!_tankID) return chapter.restart();
81238             var entity = context.hasEntity(_tankID);
81239             if (!entity) return continueTo(rightClickTank);
81240             var node = selectMenuItem(context, 'circularize').node();
81241
81242             if (!node) {
81243               return continueTo(rightClickTank);
81244             }
81245
81246             var wasChanged = false;
81247             reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
81248               padding: 50
81249             });
81250             context.on('enter.intro', function (mode) {
81251               if (mode.id === 'browse') {
81252                 continueTo(rightClickTank);
81253               } else if (mode.id === 'move' || mode.id === 'rotate') {
81254                 continueTo(retryClickCircle);
81255               }
81256             });
81257             context.map().on('move.intro', function () {
81258               var node = selectMenuItem(context, 'circularize').node();
81259
81260               if (!wasChanged && !node) {
81261                 return continueTo(rightClickTank);
81262               }
81263
81264               reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
81265                 duration: 0,
81266                 padding: 50
81267               });
81268             });
81269             context.history().on('change.intro', function () {
81270               wasChanged = true;
81271               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
81272
81273               timeout(function () {
81274                 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
81275                   n: 1
81276                 })) {
81277                   continueTo(play);
81278                 } else {
81279                   continueTo(retryClickCircle);
81280                 }
81281               }, 500); // after transitioned actions
81282             });
81283
81284             function continueTo(nextStep) {
81285               context.on('enter.intro', null);
81286               context.map().on('move.intro', null);
81287               context.history().on('change.intro', null);
81288               nextStep();
81289             }
81290           }
81291
81292           function retryClickCircle() {
81293             context.enter(modeBrowse(context));
81294             revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
81295               buttonText: _t.html('intro.ok'),
81296               buttonCallback: function buttonCallback() {
81297                 continueTo(rightClickTank);
81298               }
81299             });
81300
81301             function continueTo(nextStep) {
81302               nextStep();
81303             }
81304           }
81305
81306           function play() {
81307             dispatch$1.call('done');
81308             reveal('.ideditor', helpHtml('intro.buildings.play', {
81309               next: _t('intro.startediting.title')
81310             }), {
81311               tooltipBox: '.intro-nav-wrap .chapter-startEditing',
81312               buttonText: _t.html('intro.ok'),
81313               buttonCallback: function buttonCallback() {
81314                 reveal('.ideditor');
81315               }
81316             });
81317           }
81318
81319           chapter.enter = function () {
81320             addHouse();
81321           };
81322
81323           chapter.exit = function () {
81324             timeouts.forEach(window.clearTimeout);
81325             context.on('enter.intro exit.intro', null);
81326             context.map().on('move.intro drawn.intro', null);
81327             context.history().on('change.intro', null);
81328             context.container().select('.inspector-wrap').on('wheel.intro', null);
81329             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
81330             context.container().select('.more-fields .combobox-input').on('click.intro', null);
81331           };
81332
81333           chapter.restart = function () {
81334             chapter.exit();
81335             chapter.enter();
81336           };
81337
81338           return utilRebind(chapter, dispatch$1, 'on');
81339         }
81340
81341         function uiIntroStartEditing(context, reveal) {
81342           var dispatch$1 = dispatch('done', 'startEditing');
81343           var modalSelection = select(null);
81344           var chapter = {
81345             title: 'intro.startediting.title'
81346           };
81347
81348           function showHelp() {
81349             reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
81350               buttonText: _t.html('intro.ok'),
81351               buttonCallback: function buttonCallback() {
81352                 shortcuts();
81353               }
81354             });
81355           }
81356
81357           function shortcuts() {
81358             reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
81359               buttonText: _t.html('intro.ok'),
81360               buttonCallback: function buttonCallback() {
81361                 showSave();
81362               }
81363             });
81364           }
81365
81366           function showSave() {
81367             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
81368
81369             reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
81370               buttonText: _t.html('intro.ok'),
81371               buttonCallback: function buttonCallback() {
81372                 showStart();
81373               }
81374             });
81375           }
81376
81377           function showStart() {
81378             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
81379
81380             modalSelection = uiModal(context.container());
81381             modalSelection.select('.modal').attr('class', 'modal-splash modal');
81382             modalSelection.selectAll('.close').remove();
81383             var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
81384               modalSelection.remove();
81385             });
81386             startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
81387             startbutton.append('h2').html(_t.html('intro.startediting.start'));
81388             dispatch$1.call('startEditing');
81389           }
81390
81391           chapter.enter = function () {
81392             showHelp();
81393           };
81394
81395           chapter.exit = function () {
81396             modalSelection.remove();
81397             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
81398           };
81399
81400           return utilRebind(chapter, dispatch$1, 'on');
81401         }
81402
81403         var chapterUi = {
81404           welcome: uiIntroWelcome,
81405           navigation: uiIntroNavigation,
81406           point: uiIntroPoint,
81407           area: uiIntroArea,
81408           line: uiIntroLine,
81409           building: uiIntroBuilding,
81410           startEditing: uiIntroStartEditing
81411         };
81412         var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
81413         function uiIntro(context) {
81414           var INTRO_IMAGERY = 'EsriWorldImageryClarity';
81415           var _introGraph = {};
81416
81417           var _currChapter;
81418
81419           function intro(selection) {
81420             _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
81421               // create entities for intro graph and localize names
81422               for (var id in dataIntroGraph) {
81423                 if (!_introGraph[id]) {
81424                   _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
81425                 }
81426               }
81427
81428               selection.call(startIntro);
81429             })["catch"](function () {
81430               /* ignore */
81431             });
81432           }
81433
81434           function startIntro(selection) {
81435             context.enter(modeBrowse(context)); // Save current map state
81436
81437             var osm = context.connection();
81438             var history = context.history().toJSON();
81439             var hash = window.location.hash;
81440             var center = context.map().center();
81441             var zoom = context.map().zoom();
81442             var background = context.background().baseLayerSource();
81443             var overlays = context.background().overlayLayerSources();
81444             var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
81445             var caches = osm && osm.caches();
81446             var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
81447             // (this needs to be before `context.inIntro(true)`)
81448
81449             context.ui().sidebar.expand();
81450             context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
81451
81452             context.inIntro(true); // Load semi-real data used in intro
81453
81454             if (osm) {
81455               osm.toggle(false).reset();
81456             }
81457
81458             context.history().reset();
81459             context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
81460             context.history().checkpoint('initial'); // Setup imagery
81461
81462             var imagery = context.background().findSource(INTRO_IMAGERY);
81463
81464             if (imagery) {
81465               context.background().baseLayerSource(imagery);
81466             } else {
81467               context.background().bing();
81468             }
81469
81470             overlays.forEach(function (d) {
81471               return context.background().toggleOverlayLayer(d);
81472             }); // Setup data layers (only OSM)
81473
81474             var layers = context.layers();
81475             layers.all().forEach(function (item) {
81476               // if the layer has the function `enabled`
81477               if (typeof item.layer.enabled === 'function') {
81478                 item.layer.enabled(item.id === 'osm');
81479               }
81480             });
81481             context.container().selectAll('.main-map .layer-background').style('opacity', 1);
81482             var curtain = uiCurtain(context.container().node());
81483             selection.call(curtain); // Store that the user started the walkthrough..
81484
81485             corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
81486
81487             var storedProgress = corePreferences('walkthrough_progress') || '';
81488             var progress = storedProgress.split(';').filter(Boolean);
81489             var chapters = chapterFlow.map(function (chapter, i) {
81490               var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
81491                 buttons.filter(function (d) {
81492                   return d.title === s.title;
81493                 }).classed('finished', true);
81494
81495                 if (i < chapterFlow.length - 1) {
81496                   var next = chapterFlow[i + 1];
81497                   context.container().select("button.chapter-".concat(next)).classed('next', true);
81498                 } // Store walkthrough progress..
81499
81500
81501                 progress.push(chapter);
81502                 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
81503               });
81504               return s;
81505             });
81506             chapters[chapters.length - 1].on('startEditing', function () {
81507               // Store walkthrough progress..
81508               progress.push('startEditing');
81509               corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
81510
81511               var incomplete = utilArrayDifference(chapterFlow, progress);
81512
81513               if (!incomplete.length) {
81514                 corePreferences('walkthrough_completed', 'yes');
81515               }
81516
81517               curtain.remove();
81518               navwrap.remove();
81519               context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
81520               context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
81521
81522               if (osm) {
81523                 osm.toggle(true).reset().caches(caches);
81524               }
81525
81526               context.history().reset().merge(Object.values(baseEntities));
81527               context.background().baseLayerSource(background);
81528               overlays.forEach(function (d) {
81529                 return context.background().toggleOverlayLayer(d);
81530               });
81531
81532               if (history) {
81533                 context.history().fromJSON(history, false);
81534               }
81535
81536               context.map().centerZoom(center, zoom);
81537               window.location.replace(hash);
81538               context.inIntro(false);
81539             });
81540             var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
81541             navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
81542             var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
81543             var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
81544               return "chapter chapter-".concat(chapterFlow[i]);
81545             }).on('click', enterChapter);
81546             buttons.append('span').html(function (d) {
81547               return _t.html(d.title);
81548             });
81549             buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
81550             enterChapter(null, chapters[0]);
81551
81552             function enterChapter(d3_event, newChapter) {
81553               if (_currChapter) {
81554                 _currChapter.exit();
81555               }
81556
81557               context.enter(modeBrowse(context));
81558               _currChapter = newChapter;
81559
81560               _currChapter.enter();
81561
81562               buttons.classed('next', false).classed('active', function (d) {
81563                 return d.title === _currChapter.title;
81564               });
81565             }
81566           }
81567
81568           return intro;
81569         }
81570
81571         function uiIssuesInfo(context) {
81572           var warningsItem = {
81573             id: 'warnings',
81574             count: 0,
81575             iconID: 'iD-icon-alert',
81576             descriptionID: 'issues.warnings_and_errors'
81577           };
81578           var resolvedItem = {
81579             id: 'resolved',
81580             count: 0,
81581             iconID: 'iD-icon-apply',
81582             descriptionID: 'issues.user_resolved_issues'
81583           };
81584
81585           function update(selection) {
81586             var shownItems = [];
81587             var liveIssues = context.validator().getIssues({
81588               what: corePreferences('validate-what') || 'edited',
81589               where: corePreferences('validate-where') || 'all'
81590             });
81591
81592             if (liveIssues.length) {
81593               warningsItem.count = liveIssues.length;
81594               shownItems.push(warningsItem);
81595             }
81596
81597             if (corePreferences('validate-what') === 'all') {
81598               var resolvedIssues = context.validator().getResolvedIssues();
81599
81600               if (resolvedIssues.length) {
81601                 resolvedItem.count = resolvedIssues.length;
81602                 shownItems.push(resolvedItem);
81603               }
81604             }
81605
81606             var chips = selection.selectAll('.chip').data(shownItems, function (d) {
81607               return d.id;
81608             });
81609             chips.exit().remove();
81610             var enter = chips.enter().append('a').attr('class', function (d) {
81611               return 'chip ' + d.id + '-count';
81612             }).attr('href', '#').each(function (d) {
81613               var chipSelection = select(this);
81614               var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
81615               chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
81616                 d3_event.preventDefault();
81617                 tooltipBehavior.hide(select(this)); // open the Issues pane
81618
81619                 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
81620               });
81621               chipSelection.call(svgIcon('#' + d.iconID));
81622             });
81623             enter.append('span').attr('class', 'count');
81624             enter.merge(chips).selectAll('span.count').html(function (d) {
81625               return d.count.toString();
81626             });
81627           }
81628
81629           return function (selection) {
81630             update(selection);
81631             context.validator().on('validated.infobox', function () {
81632               update(selection);
81633             });
81634           };
81635         }
81636
81637         function uiMapInMap(context) {
81638           function mapInMap(selection) {
81639             var backgroundLayer = rendererTileLayer(context);
81640             var overlayLayers = {};
81641             var projection = geoRawMercator();
81642             var dataLayer = svgData(projection, context).showLabels(false);
81643             var debugLayer = svgDebug(projection, context);
81644             var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
81645             var wrap = select(null);
81646             var tiles = select(null);
81647             var viewport = select(null);
81648             var _isTransformed = false;
81649             var _isHidden = true;
81650             var _skipEvents = false;
81651             var _gesture = null;
81652             var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
81653
81654             var _dMini; // dimensions of minimap
81655
81656
81657             var _cMini; // center pixel of minimap
81658
81659
81660             var _tStart; // transform at start of gesture
81661
81662
81663             var _tCurr; // transform at most recent event
81664
81665
81666             var _timeoutID;
81667
81668             function zoomStarted() {
81669               if (_skipEvents) return;
81670               _tStart = _tCurr = projection.transform();
81671               _gesture = null;
81672             }
81673
81674             function zoomed(d3_event) {
81675               if (_skipEvents) return;
81676               var x = d3_event.transform.x;
81677               var y = d3_event.transform.y;
81678               var k = d3_event.transform.k;
81679               var isZooming = k !== _tStart.k;
81680               var isPanning = x !== _tStart.x || y !== _tStart.y;
81681
81682               if (!isZooming && !isPanning) {
81683                 return; // no change
81684               } // lock in either zooming or panning, don't allow both in minimap.
81685
81686
81687               if (!_gesture) {
81688                 _gesture = isZooming ? 'zoom' : 'pan';
81689               }
81690
81691               var tMini = projection.transform();
81692               var tX, tY, scale;
81693
81694               if (_gesture === 'zoom') {
81695                 scale = k / tMini.k;
81696                 tX = (_cMini[0] / scale - _cMini[0]) * scale;
81697                 tY = (_cMini[1] / scale - _cMini[1]) * scale;
81698               } else {
81699                 k = tMini.k;
81700                 scale = 1;
81701                 tX = x - tMini.x;
81702                 tY = y - tMini.y;
81703               }
81704
81705               utilSetTransform(tiles, tX, tY, scale);
81706               utilSetTransform(viewport, 0, 0, scale);
81707               _isTransformed = true;
81708               _tCurr = identity$2.translate(x, y).scale(k);
81709               var zMain = geoScaleToZoom(context.projection.scale());
81710               var zMini = geoScaleToZoom(k);
81711               _zDiff = zMain - zMini;
81712               queueRedraw();
81713             }
81714
81715             function zoomEnded() {
81716               if (_skipEvents) return;
81717               if (_gesture !== 'pan') return;
81718               updateProjection();
81719               _gesture = null;
81720               context.map().center(projection.invert(_cMini)); // recenter main map..
81721             }
81722
81723             function updateProjection() {
81724               var loc = context.map().center();
81725               var tMain = context.projection.transform();
81726               var zMain = geoScaleToZoom(tMain.k);
81727               var zMini = Math.max(zMain - _zDiff, 0.5);
81728               var kMini = geoZoomToScale(zMini);
81729               projection.translate([tMain.x, tMain.y]).scale(kMini);
81730               var point = projection(loc);
81731               var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
81732               var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
81733               var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
81734               projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
81735               _tCurr = projection.transform();
81736
81737               if (_isTransformed) {
81738                 utilSetTransform(tiles, 0, 0);
81739                 utilSetTransform(viewport, 0, 0);
81740                 _isTransformed = false;
81741               }
81742
81743               zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
81744               _skipEvents = true;
81745               wrap.call(zoom.transform, _tCurr);
81746               _skipEvents = false;
81747             }
81748
81749             function redraw() {
81750               clearTimeout(_timeoutID);
81751               if (_isHidden) return;
81752               updateProjection();
81753               var zMini = geoScaleToZoom(projection.scale()); // setup tile container
81754
81755               tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
81756               tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
81757
81758               backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
81759               var background = tiles.selectAll('.map-in-map-background').data([0]);
81760               background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
81761
81762               var overlaySources = context.background().overlayLayerSources();
81763               var activeOverlayLayers = [];
81764
81765               for (var i = 0; i < overlaySources.length; i++) {
81766                 if (overlaySources[i].validZoom(zMini)) {
81767                   if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
81768                   activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
81769                 }
81770               }
81771
81772               var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
81773               overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
81774               var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
81775                 return d.source().name();
81776               });
81777               overlays.exit().remove();
81778               overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
81779                 select(this).call(layer);
81780               });
81781               var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
81782               dataLayers.exit().remove();
81783               dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
81784
81785               if (_gesture !== 'pan') {
81786                 var getPath = d3_geoPath(projection);
81787                 var bbox = {
81788                   type: 'Polygon',
81789                   coordinates: [context.map().extent().polygon()]
81790                 };
81791                 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
81792                 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
81793                 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
81794                 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
81795                   return getPath.area(d) < 30;
81796                 });
81797               }
81798             }
81799
81800             function queueRedraw() {
81801               clearTimeout(_timeoutID);
81802               _timeoutID = setTimeout(function () {
81803                 redraw();
81804               }, 750);
81805             }
81806
81807             function toggle(d3_event) {
81808               if (d3_event) d3_event.preventDefault();
81809               _isHidden = !_isHidden;
81810               context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
81811
81812               if (_isHidden) {
81813                 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
81814                   selection.selectAll('.map-in-map').style('display', 'none');
81815                 });
81816               } else {
81817                 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
81818                   redraw();
81819                 });
81820               }
81821             }
81822
81823             uiMapInMap.toggle = toggle;
81824             wrap = selection.selectAll('.map-in-map').data([0]);
81825             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..
81826
81827             _dMini = [200, 150]; //utilGetDimensions(wrap);
81828
81829             _cMini = geoVecScale(_dMini, 0.5);
81830             context.map().on('drawn.map-in-map', function (drawn) {
81831               if (drawn.full === true) {
81832                 redraw();
81833               }
81834             });
81835             redraw();
81836             context.keybinding().on(_t('background.minimap.key'), toggle);
81837           }
81838
81839           return mapInMap;
81840         }
81841
81842         function uiNotice(context) {
81843           return function (selection) {
81844             var div = selection.append('div').attr('class', 'notice');
81845             var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
81846               context.map().zoomEase(context.minEditableZoom());
81847             }).on('wheel', function (d3_event) {
81848               // let wheel events pass through #4482
81849               var e2 = new WheelEvent(d3_event.type, d3_event);
81850               context.surface().node().dispatchEvent(e2);
81851             });
81852             button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
81853
81854             function disableTooHigh() {
81855               var canEdit = context.map().zoom() >= context.minEditableZoom();
81856               div.style('display', canEdit ? 'none' : 'block');
81857             }
81858
81859             context.map().on('move.notice', debounce(disableTooHigh, 500));
81860             disableTooHigh();
81861           };
81862         }
81863
81864         function uiPhotoviewer(context) {
81865           var dispatch$1 = dispatch('resize');
81866
81867           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
81868
81869           function photoviewer(selection) {
81870             selection.append('button').attr('class', 'thumb-hide').on('click', function () {
81871               if (services.streetside) {
81872                 services.streetside.hideViewer(context);
81873               }
81874
81875               if (services.mapillary) {
81876                 services.mapillary.hideViewer(context);
81877               }
81878
81879               if (services.openstreetcam) {
81880                 services.openstreetcam.hideViewer(context);
81881               }
81882             }).append('div').call(svgIcon('#iD-icon-close'));
81883
81884             function preventDefault(d3_event) {
81885               d3_event.preventDefault();
81886             }
81887
81888             selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
81889               resizeOnX: true,
81890               resizeOnY: true
81891             }));
81892             selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
81893               resizeOnX: true
81894             }));
81895             selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
81896               resizeOnY: true
81897             }));
81898
81899             function buildResizeListener(target, eventName, dispatch, options) {
81900               var resizeOnX = !!options.resizeOnX;
81901               var resizeOnY = !!options.resizeOnY;
81902               var minHeight = options.minHeight || 240;
81903               var minWidth = options.minWidth || 320;
81904               var pointerId;
81905               var startX;
81906               var startY;
81907               var startWidth;
81908               var startHeight;
81909
81910               function startResize(d3_event) {
81911                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
81912                 d3_event.preventDefault();
81913                 d3_event.stopPropagation();
81914                 var mapSize = context.map().dimensions();
81915
81916                 if (resizeOnX) {
81917                   var maxWidth = mapSize[0];
81918                   var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
81919                   target.style('width', newWidth + 'px');
81920                 }
81921
81922                 if (resizeOnY) {
81923                   var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
81924
81925                   var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
81926                   target.style('height', newHeight + 'px');
81927                 }
81928
81929                 dispatch.call(eventName, target, utilGetDimensions(target, true));
81930               }
81931
81932               function clamp(num, min, max) {
81933                 return Math.max(min, Math.min(num, max));
81934               }
81935
81936               function stopResize(d3_event) {
81937                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
81938                 d3_event.preventDefault();
81939                 d3_event.stopPropagation(); // remove all the listeners we added
81940
81941                 select(window).on('.' + eventName, null);
81942               }
81943
81944               return function initResize(d3_event) {
81945                 d3_event.preventDefault();
81946                 d3_event.stopPropagation();
81947                 pointerId = d3_event.pointerId || 'mouse';
81948                 startX = d3_event.clientX;
81949                 startY = d3_event.clientY;
81950                 var targetRect = target.node().getBoundingClientRect();
81951                 startWidth = targetRect.width;
81952                 startHeight = targetRect.height;
81953                 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
81954
81955                 if (_pointerPrefix === 'pointer') {
81956                   select(window).on('pointercancel.' + eventName, stopResize, false);
81957                 }
81958               };
81959             }
81960           }
81961
81962           photoviewer.onMapResize = function () {
81963             var photoviewer = context.container().select('.photoviewer');
81964             var content = context.container().select('.main-content');
81965             var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
81966             // (-90 preserves space at top and bottom of map used by menus)
81967
81968             var photoDimensions = utilGetDimensions(photoviewer, true);
81969
81970             if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
81971               var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
81972               photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
81973               dispatch$1.call('resize', photoviewer, setPhotoDimensions);
81974             }
81975           };
81976
81977           return utilRebind(photoviewer, dispatch$1, 'on');
81978         }
81979
81980         function uiRestore(context) {
81981           return function (selection) {
81982             if (!context.history().hasRestorableChanges()) return;
81983             var modalSelection = uiModal(selection, true);
81984             modalSelection.select('.modal').attr('class', 'modal fillL');
81985             var introModal = modalSelection.select('.content');
81986             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
81987             introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
81988             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
81989             var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
81990               context.history().restore();
81991               modalSelection.remove();
81992             });
81993             restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
81994             restore.append('div').html(_t.html('restore.restore'));
81995             var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
81996               context.history().clearSaved();
81997               modalSelection.remove();
81998             });
81999             reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
82000             reset.append('div').html(_t.html('restore.reset'));
82001             restore.node().focus();
82002           };
82003         }
82004
82005         function uiScale(context) {
82006           var projection = context.projection,
82007               isImperial = !_mainLocalizer.usesMetric(),
82008               maxLength = 180,
82009               tickHeight = 8;
82010
82011           function scaleDefs(loc1, loc2) {
82012             var lat = (loc2[1] + loc1[1]) / 2,
82013                 conversion = isImperial ? 3.28084 : 1,
82014                 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
82015                 scale = {
82016               dist: 0,
82017               px: 0,
82018               text: ''
82019             },
82020                 buckets,
82021                 i,
82022                 val,
82023                 dLon;
82024
82025             if (isImperial) {
82026               buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
82027             } else {
82028               buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
82029             } // determine a user-friendly endpoint for the scale
82030
82031
82032             for (i = 0; i < buckets.length; i++) {
82033               val = buckets[i];
82034
82035               if (dist >= val) {
82036                 scale.dist = Math.floor(dist / val) * val;
82037                 break;
82038               } else {
82039                 scale.dist = +dist.toFixed(2);
82040               }
82041             }
82042
82043             dLon = geoMetersToLon(scale.dist / conversion, lat);
82044             scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
82045             scale.text = displayLength(scale.dist / conversion, isImperial);
82046             return scale;
82047           }
82048
82049           function update(selection) {
82050             // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
82051             var dims = context.map().dimensions(),
82052                 loc1 = projection.invert([0, dims[1]]),
82053                 loc2 = projection.invert([maxLength, dims[1]]),
82054                 scale = scaleDefs(loc1, loc2);
82055             selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
82056             selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
82057           }
82058
82059           return function (selection) {
82060             function switchUnits() {
82061               isImperial = !isImperial;
82062               selection.call(update);
82063             }
82064
82065             var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
82066             scalegroup.append('path').attr('class', 'scale-path');
82067             selection.append('div').attr('class', 'scale-text');
82068             selection.call(update);
82069             context.map().on('move.scale', function () {
82070               update(selection);
82071             });
82072           };
82073         }
82074
82075         function uiShortcuts(context) {
82076           var detected = utilDetect();
82077           var _activeTab = 0;
82078
82079           var _modalSelection;
82080
82081           var _selection = select(null);
82082
82083           var _dataShortcuts;
82084
82085           function shortcutsModal(_modalSelection) {
82086             _modalSelection.select('.modal').classed('modal-shortcuts', true);
82087
82088             var content = _modalSelection.select('.content');
82089
82090             content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
82091             _mainFileFetcher.get('shortcuts').then(function (data) {
82092               _dataShortcuts = data;
82093               content.call(render);
82094             })["catch"](function () {
82095               /* ignore */
82096             });
82097           }
82098
82099           function render(selection) {
82100             if (!_dataShortcuts) return;
82101             var wrapper = selection.selectAll('.wrapper').data([0]);
82102             var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
82103             var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
82104             var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
82105             wrapper = wrapper.merge(wrapperEnter);
82106             var tabs = tabsBar.selectAll('.tab').data(_dataShortcuts);
82107             var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event, d) {
82108               d3_event.preventDefault();
82109
82110               var i = _dataShortcuts.indexOf(d);
82111
82112               _activeTab = i;
82113               render(selection);
82114             });
82115             tabsEnter.append('span').html(function (d) {
82116               return _t.html(d.text);
82117             }); // Update
82118
82119             wrapper.selectAll('.tab').classed('active', function (d, i) {
82120               return i === _activeTab;
82121             });
82122             var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(_dataShortcuts);
82123             var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
82124               return 'shortcut-tab shortcut-tab-' + d.tab;
82125             });
82126             var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
82127               return d.columns;
82128             }).enter().append('table').attr('class', 'shortcut-column');
82129             var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
82130               return d.rows;
82131             }).enter().append('tr').attr('class', 'shortcut-row');
82132             var sectionRows = rowsEnter.filter(function (d) {
82133               return !d.shortcuts;
82134             });
82135             sectionRows.append('td');
82136             sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
82137               return _t.html(d.text);
82138             });
82139             var shortcutRows = rowsEnter.filter(function (d) {
82140               return d.shortcuts;
82141             });
82142             var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
82143             var modifierKeys = shortcutKeys.filter(function (d) {
82144               return d.modifiers;
82145             });
82146             modifierKeys.selectAll('kbd.modifier').data(function (d) {
82147               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
82148                 return ['⌘'];
82149               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
82150                 return [];
82151               } else {
82152                 return d.modifiers;
82153               }
82154             }).enter().each(function () {
82155               var selection = select(this);
82156               selection.append('kbd').attr('class', 'modifier').html(function (d) {
82157                 return uiCmd.display(d);
82158               });
82159               selection.append('span').html('+');
82160             });
82161             shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
82162               var arr = d.shortcuts;
82163
82164               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
82165                 arr = ['Y'];
82166               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
82167                 arr = ['F11'];
82168               } // replace translations
82169
82170
82171               arr = arr.map(function (s) {
82172                 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
82173               });
82174               return utilArrayUniq(arr).map(function (s) {
82175                 return {
82176                   shortcut: s,
82177                   separator: d.separator,
82178                   suffix: d.suffix
82179                 };
82180               });
82181             }).enter().each(function (d, i, nodes) {
82182               var selection = select(this);
82183               var click = d.shortcut.toLowerCase().match(/(.*).click/);
82184
82185               if (click && click[1]) {
82186                 // replace "left_click", "right_click" with mouse icon
82187                 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
82188               } else if (d.shortcut.toLowerCase() === 'long-press') {
82189                 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
82190               } else if (d.shortcut.toLowerCase() === 'tap') {
82191                 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
82192               } else {
82193                 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
82194                   return d.shortcut;
82195                 });
82196               }
82197
82198               if (i < nodes.length - 1) {
82199                 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
82200               } else if (i === nodes.length - 1 && d.suffix) {
82201                 selection.append('span').html(d.suffix);
82202               }
82203             });
82204             shortcutKeys.filter(function (d) {
82205               return d.gesture;
82206             }).each(function () {
82207               var selection = select(this);
82208               selection.append('span').html('+');
82209               selection.append('span').attr('class', 'gesture').html(function (d) {
82210                 return _t.html(d.gesture);
82211               });
82212             });
82213             shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
82214               return d.text ? _t.html(d.text) : "\xA0";
82215             }); // Update
82216
82217             wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
82218               return i === _activeTab ? 'flex' : 'none';
82219             });
82220           }
82221
82222           return function (selection, show) {
82223             _selection = selection;
82224
82225             if (show) {
82226               _modalSelection = uiModal(selection);
82227
82228               _modalSelection.call(shortcutsModal);
82229             } else {
82230               context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
82231                 if (context.container().selectAll('.modal-shortcuts').size()) {
82232                   // already showing
82233                   if (_modalSelection) {
82234                     _modalSelection.close();
82235
82236                     _modalSelection = null;
82237                   }
82238                 } else {
82239                   _modalSelection = uiModal(_selection);
82240
82241                   _modalSelection.call(shortcutsModal);
82242                 }
82243               });
82244             }
82245           };
82246         }
82247
82248         var pair_1 = pair;
82249
82250         function search(input, dims) {
82251           if (!dims) dims = 'NSEW';
82252           if (typeof input !== 'string') return null;
82253           input = input.toUpperCase();
82254           var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
82255           var m = input.match(regex);
82256           if (!m) return null; // no match
82257
82258           var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
82259
82260           var dim;
82261
82262           if (m[1] && m[5]) {
82263             // if matched both..
82264             dim = m[1]; // keep leading
82265
82266             matched = matched.slice(0, -1); // remove trailing dimension from match
82267           } else {
82268             dim = m[1] || m[5];
82269           } // if unrecognized dimension
82270
82271
82272           if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
82273
82274           var deg = m[2] ? parseFloat(m[2]) : 0;
82275           var min = m[3] ? parseFloat(m[3]) / 60 : 0;
82276           var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
82277           var sign = deg < 0 ? -1 : 1;
82278           if (dim === 'S' || dim === 'W') sign *= -1;
82279           return {
82280             val: (Math.abs(deg) + min + sec) * sign,
82281             dim: dim,
82282             matched: matched,
82283             remain: input.slice(matched.length)
82284           };
82285         }
82286
82287         function pair(input, dims) {
82288           input = input.trim();
82289           var one = search(input, dims);
82290           if (!one) return null;
82291           input = one.remain.trim();
82292           var two = search(input, dims);
82293           if (!two || two.remain) return null;
82294
82295           if (one.dim) {
82296             return swapdim(one.val, two.val, one.dim);
82297           } else {
82298             return [one.val, two.val];
82299           }
82300         }
82301
82302         function swapdim(a, b, dim) {
82303           if (dim === 'N' || dim === 'S') return [a, b];
82304           if (dim === 'W' || dim === 'E') return [b, a];
82305         }
82306
82307         function uiFeatureList(context) {
82308           var _geocodeResults;
82309
82310           function featureList(selection) {
82311             var header = selection.append('div').attr('class', 'header fillL');
82312             header.append('h3').html(_t.html('inspector.feature_list'));
82313             var searchWrap = selection.append('div').attr('class', 'search-header');
82314             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
82315             var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
82316             var listWrap = selection.append('div').attr('class', 'inspector-body');
82317             var list = listWrap.append('div').attr('class', 'feature-list');
82318             context.on('exit.feature-list', clearSearch);
82319             context.map().on('drawn.feature-list', mapDrawn);
82320             context.keybinding().on(uiCmd('⌘F'), focusSearch);
82321
82322             function focusSearch(d3_event) {
82323               var mode = context.mode() && context.mode().id;
82324               if (mode !== 'browse') return;
82325               d3_event.preventDefault();
82326               search.node().focus();
82327             }
82328
82329             function keydown(d3_event) {
82330               if (d3_event.keyCode === 27) {
82331                 // escape
82332                 search.node().blur();
82333               }
82334             }
82335
82336             function keypress(d3_event) {
82337               var q = search.property('value'),
82338                   items = list.selectAll('.feature-list-item');
82339
82340               if (d3_event.keyCode === 13 && // ↩ Return
82341               q.length && items.size()) {
82342                 click(items.datum());
82343               }
82344             }
82345
82346             function inputevent() {
82347               _geocodeResults = undefined;
82348               drawList();
82349             }
82350
82351             function clearSearch() {
82352               search.property('value', '');
82353               drawList();
82354             }
82355
82356             function mapDrawn(e) {
82357               if (e.full) {
82358                 drawList();
82359               }
82360             }
82361
82362             function features() {
82363               var result = [];
82364               var graph = context.graph();
82365               var visibleCenter = context.map().extent().center();
82366               var q = search.property('value').toLowerCase();
82367               if (!q) return result;
82368               var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
82369
82370               if (locationMatch) {
82371                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
82372                 result.push({
82373                   id: -1,
82374                   geometry: 'point',
82375                   type: _t('inspector.location'),
82376                   name: dmsCoordinatePair([loc[1], loc[0]]),
82377                   location: loc
82378                 });
82379               } // A location search takes priority over an ID search
82380
82381
82382               var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
82383
82384               if (idMatch) {
82385                 var elemType = idMatch[1].charAt(0);
82386                 var elemId = idMatch[2];
82387                 result.push({
82388                   id: elemType + elemId,
82389                   geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
82390                   type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
82391                   name: elemId
82392                 });
82393               }
82394
82395               var allEntities = graph.entities;
82396               var localResults = [];
82397
82398               for (var id in allEntities) {
82399                 var entity = allEntities[id];
82400                 if (!entity) continue;
82401                 var name = utilDisplayName(entity) || '';
82402                 if (name.toLowerCase().indexOf(q) < 0) continue;
82403                 var matched = _mainPresetIndex.match(entity, graph);
82404                 var type = matched && matched.name() || utilDisplayType(entity.id);
82405                 var extent = entity.extent(graph);
82406                 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
82407                 localResults.push({
82408                   id: entity.id,
82409                   entity: entity,
82410                   geometry: entity.geometry(graph),
82411                   type: type,
82412                   name: name,
82413                   distance: distance
82414                 });
82415                 if (localResults.length > 100) break;
82416               }
82417
82418               localResults = localResults.sort(function byDistance(a, b) {
82419                 return a.distance - b.distance;
82420               });
82421               result = result.concat(localResults);
82422
82423               (_geocodeResults || []).forEach(function (d) {
82424                 if (d.osm_type && d.osm_id) {
82425                   // some results may be missing these - #1890
82426                   // Make a temporary osmEntity so we can preset match
82427                   // and better localize the search result - #4725
82428                   var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
82429                   var tags = {};
82430                   tags[d["class"]] = d.type;
82431                   var attrs = {
82432                     id: id,
82433                     type: d.osm_type,
82434                     tags: tags
82435                   };
82436
82437                   if (d.osm_type === 'way') {
82438                     // for ways, add some fake closed nodes
82439                     attrs.nodes = ['a', 'a']; // so that geometry area is possible
82440                   }
82441
82442                   var tempEntity = osmEntity(attrs);
82443                   var tempGraph = coreGraph([tempEntity]);
82444                   var matched = _mainPresetIndex.match(tempEntity, tempGraph);
82445                   var type = matched && matched.name() || utilDisplayType(id);
82446                   result.push({
82447                     id: tempEntity.id,
82448                     geometry: tempEntity.geometry(tempGraph),
82449                     type: type,
82450                     name: d.display_name,
82451                     extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
82452                   });
82453                 }
82454               });
82455
82456               if (q.match(/^[0-9]+$/)) {
82457                 // if query is just a number, possibly an OSM ID without a prefix
82458                 result.push({
82459                   id: 'n' + q,
82460                   geometry: 'point',
82461                   type: _t('inspector.node'),
82462                   name: q
82463                 });
82464                 result.push({
82465                   id: 'w' + q,
82466                   geometry: 'line',
82467                   type: _t('inspector.way'),
82468                   name: q
82469                 });
82470                 result.push({
82471                   id: 'r' + q,
82472                   geometry: 'relation',
82473                   type: _t('inspector.relation'),
82474                   name: q
82475                 });
82476               }
82477
82478               return result;
82479             }
82480
82481             function drawList() {
82482               var value = search.property('value');
82483               var results = features();
82484               list.classed('filtered', value.length);
82485               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'));
82486               resultsIndicator.append('span').attr('class', 'entity-name');
82487               list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
82488
82489               if (services.geocoder) {
82490                 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'));
82491               }
82492
82493               list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
82494               list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
82495               list.selectAll('.feature-list-item').data([-1]).remove();
82496               var items = list.selectAll('.feature-list-item').data(results, function (d) {
82497                 return d.id;
82498               });
82499               var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
82500               var label = enter.append('div').attr('class', 'label');
82501               label.each(function (d) {
82502                 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
82503               });
82504               label.append('span').attr('class', 'entity-type').html(function (d) {
82505                 return d.type;
82506               });
82507               label.append('span').attr('class', 'entity-name').html(function (d) {
82508                 return d.name;
82509               });
82510               enter.style('opacity', 0).transition().style('opacity', 1);
82511               items.order();
82512               items.exit().remove();
82513             }
82514
82515             function mouseover(d3_event, d) {
82516               if (d.id === -1) return;
82517               utilHighlightEntities([d.id], true, context);
82518             }
82519
82520             function mouseout(d3_event, d) {
82521               if (d.id === -1) return;
82522               utilHighlightEntities([d.id], false, context);
82523             }
82524
82525             function click(d3_event, d) {
82526               d3_event.preventDefault();
82527
82528               if (d.location) {
82529                 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
82530               } else if (d.entity) {
82531                 utilHighlightEntities([d.id], false, context);
82532                 context.enter(modeSelect(context, [d.entity.id]));
82533                 context.map().zoomToEase(d.entity);
82534               } else {
82535                 // download, zoom to, and select the entity with the given ID
82536                 context.zoomToEntity(d.id);
82537               }
82538             }
82539
82540             function geocoderSearch() {
82541               services.geocoder.search(search.property('value'), function (err, resp) {
82542                 _geocodeResults = resp || [];
82543                 drawList();
82544               });
82545             }
82546           }
82547
82548           return featureList;
82549         }
82550
82551         var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
82552
82553
82554
82555
82556
82557
82558         var nativeStartsWith = ''.startsWith;
82559         var min$9 = Math.min;
82560
82561         var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('startsWith');
82562         // https://github.com/zloirock/core-js/pull/702
82563         var MDN_POLYFILL_BUG =  !CORRECT_IS_REGEXP_LOGIC && !!function () {
82564           var descriptor = getOwnPropertyDescriptor$4(String.prototype, 'startsWith');
82565           return descriptor && !descriptor.writable;
82566         }();
82567
82568         // `String.prototype.startsWith` method
82569         // https://tc39.es/ecma262/#sec-string.prototype.startswith
82570         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
82571           startsWith: function startsWith(searchString /* , position = 0 */) {
82572             var that = String(requireObjectCoercible(this));
82573             notARegexp(searchString);
82574             var index = toLength(min$9(arguments.length > 1 ? arguments[1] : undefined, that.length));
82575             var search = String(searchString);
82576             return nativeStartsWith
82577               ? nativeStartsWith.call(that, search, index)
82578               : that.slice(index, index + search.length) === search;
82579           }
82580         });
82581
82582         function uiSectionEntityIssues(context) {
82583           var _entityIDs = [];
82584           var _issues = [];
82585
82586           var _activeIssueID;
82587
82588           var section = uiSection('entity-issues', context).shouldDisplay(function () {
82589             return _issues.length > 0;
82590           }).label(function () {
82591             return _t('inspector.title_count', {
82592               title: _t.html('issues.list_title'),
82593               count: _issues.length
82594             });
82595           }).disclosureContent(renderDisclosureContent);
82596           context.validator().on('validated.entity_issues', function () {
82597             // Refresh on validated events
82598             reloadIssues();
82599             section.reRender();
82600           }).on('focusedIssue.entity_issues', function (issue) {
82601             makeActiveIssue(issue.id);
82602           });
82603
82604           function reloadIssues() {
82605             _issues = context.validator().getSharedEntityIssues(_entityIDs, {
82606               includeDisabledRules: true
82607             });
82608           }
82609
82610           function makeActiveIssue(issueID) {
82611             _activeIssueID = issueID;
82612             section.selection().selectAll('.issue-container').classed('active', function (d) {
82613               return d.id === _activeIssueID;
82614             });
82615           }
82616
82617           function renderDisclosureContent(selection) {
82618             selection.classed('grouped-items-area', true);
82619             _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
82620             var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
82621               return d.id;
82622             }); // Exit
82623
82624             containers.exit().remove(); // Enter
82625
82626             var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
82627             var itemsEnter = containersEnter.append('div').attr('class', function (d) {
82628               return 'issue severity-' + d.severity;
82629             }).on('mouseover.highlight', function (d3_event, d) {
82630               // don't hover-highlight the selected entity
82631               var ids = d.entityIds.filter(function (e) {
82632                 return _entityIDs.indexOf(e) === -1;
82633               });
82634               utilHighlightEntities(ids, true, context);
82635             }).on('mouseout.highlight', function (d3_event, d) {
82636               var ids = d.entityIds.filter(function (e) {
82637                 return _entityIDs.indexOf(e) === -1;
82638               });
82639               utilHighlightEntities(ids, false, context);
82640             });
82641             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
82642             var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
82643               makeActiveIssue(d.id); // expand only the clicked item
82644
82645               var extent = d.extent(context.graph());
82646
82647               if (extent) {
82648                 var setZoom = Math.max(context.map().zoom(), 19);
82649                 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
82650               }
82651             });
82652             textEnter.each(function (d) {
82653               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
82654               select(this).call(svgIcon(iconName, 'issue-icon'));
82655             });
82656             textEnter.append('span').attr('class', 'issue-message');
82657             var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
82658             infoButton.on('click', function (d3_event) {
82659               d3_event.stopPropagation();
82660               d3_event.preventDefault();
82661               this.blur(); // avoid keeping focus on the button - #4641
82662
82663               var container = select(this.parentNode.parentNode.parentNode);
82664               var info = container.selectAll('.issue-info');
82665               var isExpanded = info.classed('expanded');
82666
82667               if (isExpanded) {
82668                 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
82669                   info.classed('expanded', false);
82670                 });
82671               } else {
82672                 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
82673                   info.style('max-height', null);
82674                 });
82675               }
82676             });
82677             itemsEnter.append('ul').attr('class', 'issue-fix-list');
82678             containersEnter.append('div').attr('class', 'issue-info').style('max-height', '0').style('opacity', '0').each(function (d) {
82679               if (typeof d.reference === 'function') {
82680                 select(this).call(d.reference);
82681               } else {
82682                 select(this).html(_t.html('inspector.no_documentation_key'));
82683               }
82684             }); // Update
82685
82686             containers = containers.merge(containersEnter).classed('active', function (d) {
82687               return d.id === _activeIssueID;
82688             });
82689             containers.selectAll('.issue-message').html(function (d) {
82690               return d.message(context);
82691             }); // fixes
82692
82693             var fixLists = containers.selectAll('.issue-fix-list');
82694             var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
82695               return d.fixes ? d.fixes(context) : [];
82696             }, function (fix) {
82697               return fix.id;
82698             });
82699             fixes.exit().remove();
82700             var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
82701             var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
82702               // not all fixes are actionable
82703               if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
82704               // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
82705
82706               if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
82707               d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
82708
82709               utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
82710               new Promise(function (resolve, reject) {
82711                 d.onClick(context, resolve, reject);
82712
82713                 if (d.onClick.length <= 1) {
82714                   // if the fix doesn't take any completion parameters then consider it resolved
82715                   resolve();
82716                 }
82717               }).then(function () {
82718                 // revalidate whenever the fix has finished running successfully
82719                 context.validator().validate();
82720               });
82721             }).on('mouseover.highlight', function (d3_event, d) {
82722               utilHighlightEntities(d.entityIds, true, context);
82723             }).on('mouseout.highlight', function (d3_event, d) {
82724               utilHighlightEntities(d.entityIds, false, context);
82725             });
82726             buttons.each(function (d) {
82727               var iconName = d.icon || 'iD-icon-wrench';
82728
82729               if (iconName.startsWith('maki')) {
82730                 iconName += '-15';
82731               }
82732
82733               select(this).call(svgIcon('#' + iconName, 'fix-icon'));
82734             });
82735             buttons.append('span').attr('class', 'fix-message').html(function (d) {
82736               return d.title;
82737             });
82738             fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
82739               return d.onClick;
82740             }).attr('disabled', function (d) {
82741               return d.onClick ? null : 'true';
82742             }).attr('title', function (d) {
82743               if (d.disabledReason) {
82744                 return d.disabledReason;
82745               }
82746
82747               return null;
82748             });
82749           }
82750
82751           section.entityIDs = function (val) {
82752             if (!arguments.length) return _entityIDs;
82753
82754             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
82755               _entityIDs = val;
82756               _activeIssueID = null;
82757               reloadIssues();
82758             }
82759
82760             return section;
82761           };
82762
82763           return section;
82764         }
82765
82766         function uiPresetIcon() {
82767           var _preset;
82768
82769           var _geometry;
82770
82771           var _sizeClass = 'medium';
82772
82773           function isSmall() {
82774             return _sizeClass === 'small';
82775           }
82776
82777           function presetIcon(selection) {
82778             selection.each(render);
82779           }
82780
82781           function getIcon(p, geom) {
82782             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';
82783           }
82784
82785           function renderPointBorder(container, drawPoint) {
82786             var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
82787             pointBorder.exit().remove();
82788             var pointBorderEnter = pointBorder.enter();
82789             var w = 40;
82790             var h = 40;
82791             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');
82792             pointBorder = pointBorderEnter.merge(pointBorder);
82793           }
82794
82795           function renderCircleFill(container, drawVertex) {
82796             var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
82797             vertexFill.exit().remove();
82798             var vertexFillEnter = vertexFill.enter();
82799             var w = 60;
82800             var h = 60;
82801             var d = 40;
82802             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);
82803             vertexFill = vertexFillEnter.merge(vertexFill);
82804           }
82805
82806           function renderSquareFill(container, drawArea, tagClasses) {
82807             var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
82808             fill.exit().remove();
82809             var fillEnter = fill.enter();
82810             var d = isSmall() ? 40 : 60;
82811             var w = d;
82812             var h = d;
82813             var l = d * 2 / 3;
82814             var c1 = (w - l) / 2;
82815             var c2 = c1 + l;
82816             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));
82817             ['fill', 'stroke'].forEach(function (klass) {
82818               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));
82819             });
82820             var rVertex = 2.5;
82821             [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
82822               fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
82823             });
82824
82825             if (!isSmall()) {
82826               var rMidpoint = 1.25;
82827               [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
82828                 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
82829               });
82830             }
82831
82832             fill = fillEnter.merge(fill);
82833             fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
82834             fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
82835           }
82836
82837           function renderLine(container, drawLine, tagClasses) {
82838             var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
82839             line.exit().remove();
82840             var lineEnter = line.enter();
82841             var d = isSmall() ? 40 : 60; // draw the line parametrically
82842
82843             var w = d;
82844             var h = d;
82845             var y = Math.round(d * 0.72);
82846             var l = Math.round(d * 0.6);
82847             var r = 2.5;
82848             var x1 = (w - l) / 2;
82849             var x2 = x1 + l;
82850             lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
82851             ['casing', 'stroke'].forEach(function (klass) {
82852               lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
82853             });
82854             [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
82855               lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
82856             });
82857             line = lineEnter.merge(line);
82858             line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
82859             line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
82860           }
82861
82862           function renderRoute(container, drawRoute, p) {
82863             var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
82864             route.exit().remove();
82865             var routeEnter = route.enter();
82866             var d = isSmall() ? 40 : 60; // draw the route parametrically
82867
82868             var w = d;
82869             var h = d;
82870             var y1 = Math.round(d * 0.80);
82871             var y2 = Math.round(d * 0.68);
82872             var l = Math.round(d * 0.6);
82873             var r = 2;
82874             var x1 = (w - l) / 2;
82875             var x2 = x1 + l / 3;
82876             var x3 = x2 + l / 3;
82877             var x4 = x3 + l / 3;
82878             routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
82879             ['casing', 'stroke'].forEach(function (klass) {
82880               routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
82881               routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
82882               routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
82883             });
82884             [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
82885               routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
82886             });
82887             route = routeEnter.merge(route);
82888
82889             if (drawRoute) {
82890               var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
82891               var segmentPresetIDs = routeSegments[routeType];
82892
82893               for (var i in segmentPresetIDs) {
82894                 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
82895                 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
82896                 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
82897                 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
82898               }
82899             }
82900           } // Route icons are drawn with a zigzag annotation underneath:
82901           //     o   o
82902           //    / \ /
82903           //   o   o
82904           // This dataset defines the styles that are used to draw the zigzag segments.
82905
82906
82907           var routeSegments = {
82908             bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
82909             bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
82910             trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
82911             detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
82912             ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
82913             foot: ['highway/footway', 'highway/footway', 'highway/footway'],
82914             hiking: ['highway/path', 'highway/path', 'highway/path'],
82915             horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
82916             light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
82917             monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
82918             pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
82919             piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
82920             power: ['power/line', 'power/line', 'power/line'],
82921             road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
82922             subway: ['railway/subway', 'railway/subway', 'railway/subway'],
82923             train: ['railway/rail', 'railway/rail', 'railway/rail'],
82924             tram: ['railway/tram', 'railway/tram', 'railway/tram'],
82925             waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
82926           };
82927
82928           function render() {
82929             var p = _preset.apply(this, arguments);
82930
82931             var geom = _geometry ? _geometry.apply(this, arguments) : null;
82932
82933             if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
82934               geom = 'route';
82935             }
82936
82937             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
82938             var isFallback = isSmall() && p.isFallback && p.isFallback();
82939             var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
82940             var picon = getIcon(p, geom);
82941             var isMaki = picon && /^maki-/.test(picon);
82942             var isTemaki = picon && /^temaki-/.test(picon);
82943             var isFa = picon && /^fa[srb]-/.test(picon);
82944             var isiDIcon = picon && !(isMaki || isTemaki || isFa);
82945             var isCategory = !p.setTags;
82946             var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
82947             var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
82948             var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
82949             var drawArea = picon && geom === 'area' && !isFallback;
82950             var drawRoute = picon && geom === 'route';
82951             var isFramed = drawVertex || drawArea || drawLine || drawRoute;
82952             var tags = !isCategory ? p.setTags({}, geom) : {};
82953
82954             for (var k in tags) {
82955               if (tags[k] === '*') {
82956                 tags[k] = 'yes';
82957               }
82958             }
82959
82960             var tagClasses = svgTagClasses().getClassesString(tags, '');
82961             var selection = select(this);
82962             var container = selection.selectAll('.preset-icon-container').data([0]);
82963             container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
82964             container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
82965             renderPointBorder(container, drawPoint);
82966             renderCircleFill(container, drawVertex);
82967             renderSquareFill(container, drawArea, tagClasses);
82968             renderLine(container, drawLine, tagClasses);
82969             renderRoute(container, drawRoute, p);
82970             var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
82971             icon.exit().remove();
82972             icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
82973             icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
82974             icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
82975             icon.selectAll('use').attr('href', '#' + picon + (isMaki ? isSmall() && geom === 'point' ? '-11' : '-15' : ''));
82976             var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
82977             imageIcon.exit().remove();
82978             imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
82979               return container.classed('showing-img', true);
82980             }).on('error', function () {
82981               return container.classed('showing-img', false);
82982             }).merge(imageIcon);
82983             imageIcon.attr('src', imageURL);
82984           }
82985
82986           presetIcon.preset = function (val) {
82987             if (!arguments.length) return _preset;
82988             _preset = utilFunctor(val);
82989             return presetIcon;
82990           };
82991
82992           presetIcon.geometry = function (val) {
82993             if (!arguments.length) return _geometry;
82994             _geometry = utilFunctor(val);
82995             return presetIcon;
82996           };
82997
82998           presetIcon.sizeClass = function (val) {
82999             if (!arguments.length) return _sizeClass;
83000             _sizeClass = val;
83001             return presetIcon;
83002           };
83003
83004           return presetIcon;
83005         }
83006
83007         function uiSectionFeatureType(context) {
83008           var dispatch$1 = dispatch('choose');
83009           var _entityIDs = [];
83010           var _presets = [];
83011
83012           var _tagReference;
83013
83014           var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
83015
83016           function renderDisclosureContent(selection) {
83017             selection.classed('preset-list-item', true);
83018             selection.classed('mixed-types', _presets.length > 1);
83019             var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
83020             var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
83021             presetButton.append('div').attr('class', 'preset-icon-container');
83022             presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
83023             presetButtonWrap.append('div').attr('class', 'accessory-buttons');
83024             var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
83025             tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
83026
83027             if (_tagReference) {
83028               selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
83029               tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
83030             }
83031
83032             selection.selectAll('.preset-reset').on('click', function () {
83033               dispatch$1.call('choose', this, _presets);
83034             }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
83035               d3_event.preventDefault();
83036               d3_event.stopPropagation();
83037             });
83038             var geometries = entityGeometries();
83039             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')));
83040             var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
83041             var label = selection.select('.label-inner');
83042             var nameparts = label.selectAll('.namepart').data(names, function (d) {
83043               return d;
83044             });
83045             nameparts.exit().remove();
83046             nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
83047               return d;
83048             });
83049           }
83050
83051           section.entityIDs = function (val) {
83052             if (!arguments.length) return _entityIDs;
83053             _entityIDs = val;
83054             return section;
83055           };
83056
83057           section.presets = function (val) {
83058             if (!arguments.length) return _presets; // don't reload the same preset
83059
83060             if (!utilArrayIdentical(val, _presets)) {
83061               _presets = val;
83062
83063               if (_presets.length === 1) {
83064                 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
83065               }
83066             }
83067
83068             return section;
83069           };
83070
83071           function entityGeometries() {
83072             var counts = {};
83073
83074             for (var i in _entityIDs) {
83075               var geometry = context.graph().geometry(_entityIDs[i]);
83076               if (!counts[geometry]) counts[geometry] = 0;
83077               counts[geometry] += 1;
83078             }
83079
83080             return Object.keys(counts).sort(function (geom1, geom2) {
83081               return counts[geom2] - counts[geom1];
83082             });
83083           }
83084
83085           return utilRebind(section, dispatch$1, 'on');
83086         }
83087
83088         // It borrows some code from uiHelp
83089
83090         function uiFieldHelp(context, fieldName) {
83091           var fieldHelp = {};
83092
83093           var _inspector = select(null);
83094
83095           var _wrap = select(null);
83096
83097           var _body = select(null);
83098
83099           var fieldHelpKeys = {
83100             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']]]
83101           };
83102           var fieldHelpHeadings = {};
83103           var replacements = {
83104             distField: _t.html('restriction.controls.distance'),
83105             viaField: _t.html('restriction.controls.via'),
83106             fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
83107             allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
83108             restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
83109             onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
83110             allowTurn: icon('#iD-turn-yes', 'inline turn'),
83111             restrictTurn: icon('#iD-turn-no', 'inline turn'),
83112             onlyTurn: icon('#iD-turn-only', 'inline turn')
83113           }; // For each section, squash all the texts into a single markdown document
83114
83115           var docs = fieldHelpKeys[fieldName].map(function (key) {
83116             var helpkey = 'help.field.' + fieldName + '.' + key[0];
83117             var text = key[1].reduce(function (all, part) {
83118               var subkey = helpkey + '.' + part;
83119               var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
83120
83121               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
83122
83123               return all + hhh + _t.html(subkey, replacements) + '\n\n';
83124             }, '');
83125             return {
83126               key: helpkey,
83127               title: _t.html(helpkey + '.title'),
83128               html: marked_1(text.trim())
83129             };
83130           });
83131
83132           function show() {
83133             updatePosition();
83134
83135             _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
83136           }
83137
83138           function hide() {
83139             _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
83140               _body.classed('hide', true);
83141             });
83142           }
83143
83144           function clickHelp(index) {
83145             var d = docs[index];
83146             var tkeys = fieldHelpKeys[fieldName][index][1];
83147
83148             _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
83149               return i === index;
83150             });
83151
83152             var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
83153
83154
83155             content.selectAll('p').attr('class', function (d, i) {
83156               return tkeys[i];
83157             }); // insert special content for certain help sections
83158
83159             if (d.key === 'help.field.restrictions.inspecting') {
83160               content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
83161             } else if (d.key === 'help.field.restrictions.modifying') {
83162               content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
83163             }
83164           }
83165
83166           fieldHelp.button = function (selection) {
83167             if (_body.empty()) return;
83168             var button = selection.selectAll('.field-help-button').data([0]); // enter/update
83169
83170             button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
83171               d3_event.stopPropagation();
83172               d3_event.preventDefault();
83173
83174               if (_body.classed('hide')) {
83175                 show();
83176               } else {
83177                 hide();
83178               }
83179             });
83180           };
83181
83182           function updatePosition() {
83183             var wrap = _wrap.node();
83184
83185             var inspector = _inspector.node();
83186
83187             var wRect = wrap.getBoundingClientRect();
83188             var iRect = inspector.getBoundingClientRect();
83189
83190             _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
83191           }
83192
83193           fieldHelp.body = function (selection) {
83194             // This control expects the field to have a form-field-input-wrap div
83195             _wrap = selection.selectAll('.form-field-input-wrap');
83196             if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
83197
83198             _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
83199             if (_inspector.empty()) return;
83200             _body = _inspector.selectAll('.field-help-body').data([0]);
83201
83202             var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
83203
83204
83205             var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
83206             titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
83207             titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
83208               d3_event.stopPropagation();
83209               d3_event.preventDefault();
83210               hide();
83211             }).call(svgIcon('#iD-icon-close'));
83212             var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
83213             var titles = docs.map(function (d) {
83214               return d.title;
83215             });
83216             navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
83217               return d;
83218             }).on('click', function (d3_event, d) {
83219               d3_event.stopPropagation();
83220               d3_event.preventDefault();
83221               clickHelp(titles.indexOf(d));
83222             });
83223             enter.append('div').attr('class', 'field-help-content');
83224             _body = _body.merge(enter);
83225             clickHelp(0);
83226           };
83227
83228           return fieldHelp;
83229         }
83230
83231         function uiFieldCheck(field, context) {
83232           var dispatch$1 = dispatch('change');
83233           var options = field.strings && field.strings.options;
83234           var values = [];
83235           var texts = [];
83236
83237           var _tags;
83238
83239           var input = select(null);
83240           var text = select(null);
83241           var label = select(null);
83242           var reverser = select(null);
83243
83244           var _impliedYes;
83245
83246           var _entityIDs = [];
83247
83248           var _value;
83249
83250           if (options) {
83251             for (var k in options) {
83252               values.push(k === 'undefined' ? undefined : k);
83253               texts.push(field.t.html('options.' + k, {
83254                 'default': options[k]
83255               }));
83256             }
83257           } else {
83258             values = [undefined, 'yes'];
83259             texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
83260
83261             if (field.type !== 'defaultCheck') {
83262               values.push('no');
83263               texts.push(_t.html('inspector.check.no'));
83264             }
83265           } // Checks tags to see whether an undefined value is "Assumed to be Yes"
83266
83267
83268           function checkImpliedYes() {
83269             _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
83270             // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
83271
83272             if (field.id === 'oneway') {
83273               var entity = context.entity(_entityIDs[0]);
83274
83275               for (var key in entity.tags) {
83276                 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
83277                   _impliedYes = true;
83278                   texts[0] = _t.html('presets.fields.oneway_yes.options.undefined');
83279                   break;
83280                 }
83281               }
83282             }
83283           }
83284
83285           function reverserHidden() {
83286             if (!context.container().select('div.inspector-hover').empty()) return true;
83287             return !(_value === 'yes' || _impliedYes && !_value);
83288           }
83289
83290           function reverserSetText(selection) {
83291             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
83292             if (reverserHidden() || !entity) return selection;
83293             var first = entity.first();
83294             var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
83295             var pseudoDirection = first < last;
83296             var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
83297             selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
83298             return selection;
83299           }
83300
83301           var check = function check(selection) {
83302             checkImpliedYes();
83303             label = selection.selectAll('.form-field-input-wrap').data([0]);
83304             var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
83305             enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
83306             enter.append('span').html(texts[0]).attr('class', 'value');
83307
83308             if (field.type === 'onewayCheck') {
83309               enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
83310             }
83311
83312             label = label.merge(enter);
83313             input = label.selectAll('input');
83314             text = label.selectAll('span.value');
83315             input.on('click', function (d3_event) {
83316               d3_event.stopPropagation();
83317               var t = {};
83318
83319               if (Array.isArray(_tags[field.key])) {
83320                 if (values.indexOf('yes') !== -1) {
83321                   t[field.key] = 'yes';
83322                 } else {
83323                   t[field.key] = values[0];
83324                 }
83325               } else {
83326                 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
83327               } // Don't cycle through `alternating` or `reversible` states - #4970
83328               // (They are supported as translated strings, but should not toggle with clicks)
83329
83330
83331               if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
83332                 t[field.key] = values[0];
83333               }
83334
83335               dispatch$1.call('change', this, t);
83336             });
83337
83338             if (field.type === 'onewayCheck') {
83339               reverser = label.selectAll('.reverser');
83340               reverser.call(reverserSetText).on('click', function (d3_event) {
83341                 d3_event.preventDefault();
83342                 d3_event.stopPropagation();
83343                 context.perform(function (graph) {
83344                   for (var i in _entityIDs) {
83345                     graph = actionReverse(_entityIDs[i])(graph);
83346                   }
83347
83348                   return graph;
83349                 }, _t('operations.reverse.annotation.line', {
83350                   n: 1
83351                 })); // must manually revalidate since no 'change' event was called
83352
83353                 context.validator().validate();
83354                 select(this).call(reverserSetText);
83355               });
83356             }
83357           };
83358
83359           check.entityIDs = function (val) {
83360             if (!arguments.length) return _entityIDs;
83361             _entityIDs = val;
83362             return check;
83363           };
83364
83365           check.tags = function (tags) {
83366             _tags = tags;
83367
83368             function isChecked(val) {
83369               return val !== 'no' && val !== '' && val !== undefined && val !== null;
83370             }
83371
83372             function textFor(val) {
83373               if (val === '') val = undefined;
83374               var index = values.indexOf(val);
83375               return index !== -1 ? texts[index] : '"' + val + '"';
83376             }
83377
83378             checkImpliedYes();
83379             var isMixed = Array.isArray(tags[field.key]);
83380             _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
83381
83382             if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
83383               _value = 'yes';
83384             }
83385
83386             input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
83387             text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
83388             label.classed('set', !!_value);
83389
83390             if (field.type === 'onewayCheck') {
83391               reverser.classed('hide', reverserHidden()).call(reverserSetText);
83392             }
83393           };
83394
83395           check.focus = function () {
83396             input.node().focus();
83397           };
83398
83399           return utilRebind(check, dispatch$1, 'on');
83400         }
83401
83402         function uiFieldCombo(field, context) {
83403           var dispatch$1 = dispatch('change');
83404
83405           var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
83406
83407           var _isNetwork = field.type === 'networkCombo';
83408
83409           var _isSemi = field.type === 'semiCombo';
83410
83411           var _optstrings = field.strings && field.strings.options;
83412
83413           var _optarray = field.options;
83414
83415           var _snake_case = field.snake_case || field.snake_case === undefined;
83416
83417           var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
83418
83419           var _container = select(null);
83420
83421           var _inputWrap = select(null);
83422
83423           var _input = select(null);
83424
83425           var _comboData = [];
83426           var _multiData = [];
83427           var _entityIDs = [];
83428
83429           var _tags;
83430
83431           var _countryCode;
83432
83433           var _staticPlaceholder; // initialize deprecated tags array
83434
83435
83436           var _dataDeprecated = [];
83437           _mainFileFetcher.get('deprecated').then(function (d) {
83438             _dataDeprecated = d;
83439           })["catch"](function () {
83440             /* ignore */
83441           }); // ensure multiCombo field.key ends with a ':'
83442
83443           if (_isMulti && field.key && /[^:]$/.test(field.key)) {
83444             field.key += ':';
83445           }
83446
83447           function snake(s) {
83448             return s.replace(/\s+/g, '_');
83449           }
83450
83451           function unsnake(s) {
83452             return s.replace(/_+/g, ' ');
83453           }
83454
83455           function clean(s) {
83456             return s.split(';').map(function (s) {
83457               return s.trim();
83458             }).join(';');
83459           } // returns the tag value for a display value
83460           // (for multiCombo, dval should be the key suffix, not the entire key)
83461
83462
83463           function tagValue(dval) {
83464             dval = clean(dval || '');
83465
83466             if (_optstrings) {
83467               var found = _comboData.find(function (o) {
83468                 return o.key && clean(o.value) === dval;
83469               });
83470
83471               if (found) {
83472                 return found.key;
83473               }
83474             }
83475
83476             if (field.type === 'typeCombo' && !dval) {
83477               return 'yes';
83478             }
83479
83480             return (_snake_case ? snake(dval) : dval) || undefined;
83481           } // returns the display value for a tag value
83482           // (for multiCombo, tval should be the key suffix, not the entire key)
83483
83484
83485           function displayValue(tval) {
83486             tval = tval || '';
83487
83488             if (_optstrings) {
83489               var found = _comboData.find(function (o) {
83490                 return o.key === tval && o.value;
83491               });
83492
83493               if (found) {
83494                 return found.value;
83495               }
83496             }
83497
83498             if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
83499               return '';
83500             }
83501
83502             return _snake_case ? unsnake(tval) : tval;
83503           } // Compute the difference between arrays of objects by `value` property
83504           //
83505           // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
83506           // > [{value:1}, {value:3}]
83507           //
83508
83509
83510           function objectDifference(a, b) {
83511             return a.filter(function (d1) {
83512               return !b.some(function (d2) {
83513                 return !d2.isMixed && d1.value === d2.value;
83514               });
83515             });
83516           }
83517
83518           function initCombo(selection, attachTo) {
83519             if (_optstrings) {
83520               selection.attr('readonly', 'readonly');
83521               selection.call(_combobox, attachTo);
83522               setStaticValues(setPlaceholder);
83523             } else if (_optarray) {
83524               selection.call(_combobox, attachTo);
83525               setStaticValues(setPlaceholder);
83526             } else if (services.taginfo) {
83527               selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
83528               setTaginfoValues('', setPlaceholder);
83529             }
83530           }
83531
83532           function setStaticValues(callback) {
83533             if (!(_optstrings || _optarray)) return;
83534
83535             if (_optstrings) {
83536               _comboData = Object.keys(_optstrings).map(function (k) {
83537                 var v = field.t('options.' + k, {
83538                   'default': _optstrings[k]
83539                 });
83540                 return {
83541                   key: k,
83542                   value: v,
83543                   title: v,
83544                   display: field.t.html('options.' + k, {
83545                     'default': _optstrings[k]
83546                   })
83547                 };
83548               });
83549             } else if (_optarray) {
83550               _comboData = _optarray.map(function (k) {
83551                 var v = _snake_case ? unsnake(k) : k;
83552                 return {
83553                   key: k,
83554                   value: v,
83555                   title: v
83556                 };
83557               });
83558             }
83559
83560             _combobox.data(objectDifference(_comboData, _multiData));
83561
83562             if (callback) callback(_comboData);
83563           }
83564
83565           function setTaginfoValues(q, callback) {
83566             var fn = _isMulti ? 'multikeys' : 'values';
83567             var query = (_isMulti ? field.key : '') + q;
83568             var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
83569
83570             if (hasCountryPrefix) {
83571               query = _countryCode + ':';
83572             }
83573
83574             var params = {
83575               debounce: q !== '',
83576               key: field.key,
83577               query: query
83578             };
83579
83580             if (_entityIDs.length) {
83581               params.geometry = context.graph().geometry(_entityIDs[0]);
83582             }
83583
83584             services.taginfo[fn](params, function (err, data) {
83585               if (err) return;
83586               data = data.filter(function (d) {
83587                 if (field.type === 'typeCombo' && d.value === 'yes') {
83588                   // don't show the fallback value
83589                   return false;
83590                 } // don't show values with very low usage
83591
83592
83593                 return !d.count || d.count > 10;
83594               });
83595               var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
83596
83597               if (deprecatedValues) {
83598                 // don't suggest deprecated tag values
83599                 data = data.filter(function (d) {
83600                   return deprecatedValues.indexOf(d.value) === -1;
83601                 });
83602               }
83603
83604               if (hasCountryPrefix) {
83605                 data = data.filter(function (d) {
83606                   return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
83607                 });
83608               } // hide the caret if there are no suggestions
83609
83610
83611               _container.classed('empty-combobox', data.length === 0);
83612
83613               _comboData = data.map(function (d) {
83614                 var k = d.value;
83615                 if (_isMulti) k = k.replace(field.key, '');
83616                 var v = _snake_case ? unsnake(k) : k;
83617                 return {
83618                   key: k,
83619                   value: v,
83620                   title: _isMulti ? v : d.title
83621                 };
83622               });
83623               _comboData = objectDifference(_comboData, _multiData);
83624               if (callback) callback(_comboData);
83625             });
83626           }
83627
83628           function setPlaceholder(values) {
83629             if (_isMulti || _isSemi) {
83630               _staticPlaceholder = field.placeholder() || _t('inspector.add');
83631             } else {
83632               var vals = values.map(function (d) {
83633                 return d.value;
83634               }).filter(function (s) {
83635                 return s.length < 20;
83636               });
83637               var placeholders = vals.length > 1 ? vals : values.map(function (d) {
83638                 return d.key;
83639               });
83640               _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
83641             }
83642
83643             if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
83644               _staticPlaceholder += '…';
83645             }
83646
83647             var ph;
83648
83649             if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
83650               ph = _t('inspector.multiple_values');
83651             } else {
83652               ph = _staticPlaceholder;
83653             }
83654
83655             _container.selectAll('input').attr('placeholder', ph);
83656           }
83657
83658           function change() {
83659             var t = {};
83660             var val;
83661
83662             if (_isMulti || _isSemi) {
83663               val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
83664
83665               _container.classed('active', false);
83666
83667               utilGetSetValue(_input, '');
83668               var vals = val.split(';').filter(Boolean);
83669               if (!vals.length) return;
83670
83671               if (_isMulti) {
83672                 utilArrayUniq(vals).forEach(function (v) {
83673                   var key = (field.key || '') + v;
83674
83675                   if (_tags) {
83676                     // don't set a multicombo value to 'yes' if it already has a non-'no' value
83677                     // e.g. `language:de=main`
83678                     var old = _tags[key];
83679                     if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
83680                   }
83681
83682                   key = context.cleanTagKey(key);
83683                   field.keys.push(key);
83684                   t[key] = 'yes';
83685                 });
83686               } else if (_isSemi) {
83687                 var arr = _multiData.map(function (d) {
83688                   return d.key;
83689                 });
83690
83691                 arr = arr.concat(vals);
83692                 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
83693               }
83694
83695               window.setTimeout(function () {
83696                 _input.node().focus();
83697               }, 10);
83698             } else {
83699               var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
83700
83701               if (!rawValue && Array.isArray(_tags[field.key])) return;
83702               val = context.cleanTagValue(tagValue(rawValue));
83703               t[field.key] = val || undefined;
83704             }
83705
83706             dispatch$1.call('change', this, t);
83707           }
83708
83709           function removeMultikey(d3_event, d) {
83710             d3_event.preventDefault();
83711             d3_event.stopPropagation();
83712             var t = {};
83713
83714             if (_isMulti) {
83715               t[d.key] = undefined;
83716             } else if (_isSemi) {
83717               var arr = _multiData.map(function (md) {
83718                 return md.key === d.key ? null : md.key;
83719               }).filter(Boolean);
83720
83721               arr = utilArrayUniq(arr);
83722               t[field.key] = arr.length ? arr.join(';') : undefined;
83723             }
83724
83725             dispatch$1.call('change', this, t);
83726           }
83727
83728           function combo(selection) {
83729             _container = selection.selectAll('.form-field-input-wrap').data([0]);
83730             var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
83731             _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
83732
83733             if (_isMulti || _isSemi) {
83734               _container = _container.selectAll('.chiplist').data([0]);
83735               var listClass = 'chiplist'; // Use a separate line for each value in the Destinations field
83736               // to mimic highway exit signs
83737
83738               if (field.key === 'destination') {
83739                 listClass += ' full-line-chips';
83740               }
83741
83742               _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
83743                 window.setTimeout(function () {
83744                   _input.node().focus();
83745                 }, 10);
83746               }).merge(_container);
83747               _inputWrap = _container.selectAll('.input-wrap').data([0]);
83748               _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
83749               _input = _inputWrap.selectAll('input').data([0]);
83750             } else {
83751               _input = _container.selectAll('input').data([0]);
83752             }
83753
83754             _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
83755
83756             if (_isNetwork) {
83757               var extent = combinedEntityExtent();
83758               var countryCode = extent && iso1A2Code(extent.center());
83759               _countryCode = countryCode && countryCode.toLowerCase();
83760             }
83761
83762             _input.on('change', change).on('blur', change);
83763
83764             _input.on('keydown.field', function (d3_event) {
83765               switch (d3_event.keyCode) {
83766                 case 13:
83767                   // ↩ Return
83768                   _input.node().blur(); // blurring also enters the value
83769
83770
83771                   d3_event.stopPropagation();
83772                   break;
83773               }
83774             });
83775
83776             if (_isMulti || _isSemi) {
83777               _combobox.on('accept', function () {
83778                 _input.node().blur();
83779
83780                 _input.node().focus();
83781               });
83782
83783               _input.on('focus', function () {
83784                 _container.classed('active', true);
83785               });
83786             }
83787           }
83788
83789           combo.tags = function (tags) {
83790             _tags = tags;
83791
83792             if (_isMulti || _isSemi) {
83793               _multiData = [];
83794               var maxLength;
83795
83796               if (_isMulti) {
83797                 // Build _multiData array containing keys already set..
83798                 for (var k in tags) {
83799                   if (field.key && k.indexOf(field.key) !== 0) continue;
83800                   if (!field.key && field.keys.indexOf(k) === -1) continue;
83801                   var v = tags[k];
83802                   if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
83803                   var suffix = field.key ? k.substr(field.key.length) : k;
83804
83805                   _multiData.push({
83806                     key: k,
83807                     value: displayValue(suffix),
83808                     isMixed: Array.isArray(v)
83809                   });
83810                 }
83811
83812                 if (field.key) {
83813                   // Set keys for form-field modified (needed for undo and reset buttons)..
83814                   field.keys = _multiData.map(function (d) {
83815                     return d.key;
83816                   }); // limit the input length so it fits after prepending the key prefix
83817
83818                   maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
83819                 } else {
83820                   maxLength = context.maxCharsForTagKey();
83821                 }
83822               } else if (_isSemi) {
83823                 var allValues = [];
83824                 var commonValues;
83825
83826                 if (Array.isArray(tags[field.key])) {
83827                   tags[field.key].forEach(function (tagVal) {
83828                     var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
83829                     allValues = allValues.concat(thisVals);
83830
83831                     if (!commonValues) {
83832                       commonValues = thisVals;
83833                     } else {
83834                       commonValues = commonValues.filter(function (value) {
83835                         return thisVals.includes(value);
83836                       });
83837                     }
83838                   });
83839                   allValues = utilArrayUniq(allValues).filter(Boolean);
83840                 } else {
83841                   allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
83842                   commonValues = allValues;
83843                 }
83844
83845                 _multiData = allValues.map(function (v) {
83846                   return {
83847                     key: v,
83848                     value: displayValue(v),
83849                     isMixed: !commonValues.includes(v)
83850                   };
83851                 });
83852                 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
83853
83854                 maxLength = context.maxCharsForTagValue() - currLength;
83855
83856                 if (currLength > 0) {
83857                   // account for the separator if a new value will be appended to existing
83858                   maxLength -= 1;
83859                 }
83860               } // a negative maxlength doesn't make sense
83861
83862
83863               maxLength = Math.max(0, maxLength);
83864               var allowDragAndDrop = _isSemi // only semiCombo values are ordered
83865               && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
83866
83867               var available = objectDifference(_comboData, _multiData);
83868
83869               _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
83870               // translateable _optstrings and they're all currently used,
83871               // or if the field is already at its character limit
83872
83873
83874               var hideAdd = _optstrings && !available.length || maxLength <= 0;
83875
83876               _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
83877
83878
83879               var chips = _container.selectAll('.chip').data(_multiData);
83880
83881               chips.exit().remove();
83882               var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
83883               enter.append('span');
83884               enter.append('a');
83885               chips = chips.merge(enter).order().classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
83886                 return d.isMixed;
83887               }).attr('title', function (d) {
83888                 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
83889               });
83890
83891               if (allowDragAndDrop) {
83892                 registerDragAndDrop(chips);
83893               }
83894
83895               chips.select('span').html(function (d) {
83896                 return d.value;
83897               });
83898               chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
83899             } else {
83900               var isMixed = Array.isArray(tags[field.key]);
83901               var mixedValues = isMixed && tags[field.key].map(function (val) {
83902                 return displayValue(val);
83903               }).filter(Boolean);
83904               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);
83905             }
83906           };
83907
83908           function registerDragAndDrop(selection) {
83909             // allow drag and drop re-ordering of chips
83910             var dragOrigin, targetIndex;
83911             selection.call(d3_drag().on('start', function (d3_event) {
83912               dragOrigin = {
83913                 x: d3_event.x,
83914                 y: d3_event.y
83915               };
83916               targetIndex = null;
83917             }).on('drag', function (d3_event) {
83918               var x = d3_event.x - dragOrigin.x,
83919                   y = d3_event.y - dragOrigin.y;
83920               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
83921               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
83922               var index = selection.nodes().indexOf(this);
83923               select(this).classed('dragging', true);
83924               targetIndex = null;
83925               var targetIndexOffsetTop = null;
83926               var draggedTagWidth = select(this).node().offsetWidth;
83927
83928               if (field.key === 'destination') {
83929                 // meaning tags are full width
83930                 _container.selectAll('.chip').style('transform', function (d2, index2) {
83931                   var node = select(this).node();
83932
83933                   if (index === index2) {
83934                     return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
83935                   } else if (index2 > index && d3_event.y > node.offsetTop) {
83936                     if (targetIndex === null || index2 > targetIndex) {
83937                       targetIndex = index2;
83938                     }
83939
83940                     return 'translateY(-100%)'; // move the dragged tag down the order
83941                   } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
83942                     if (targetIndex === null || index2 < targetIndex) {
83943                       targetIndex = index2;
83944                     }
83945
83946                     return 'translateY(100%)';
83947                   }
83948
83949                   return null;
83950                 });
83951               } else {
83952                 _container.selectAll('.chip').each(function (d2, index2) {
83953                   var node = select(this).node(); // check the cursor is in the bounding box
83954
83955                   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) {
83956                     targetIndex = index2;
83957                     targetIndexOffsetTop = node.offsetTop;
83958                   }
83959                 }).style('transform', function (d2, index2) {
83960                   var node = select(this).node();
83961
83962                   if (index === index2) {
83963                     return 'translate(' + x + 'px, ' + y + 'px)';
83964                   } // only translate tags in the same row
83965
83966
83967                   if (node.offsetTop === targetIndexOffsetTop) {
83968                     if (index2 < index && index2 >= targetIndex) {
83969                       return 'translateX(' + draggedTagWidth + 'px)';
83970                     } else if (index2 > index && index2 <= targetIndex) {
83971                       return 'translateX(-' + draggedTagWidth + 'px)';
83972                     }
83973                   }
83974
83975                   return null;
83976                 });
83977               }
83978             }).on('end', function () {
83979               if (!select(this).classed('dragging')) {
83980                 return;
83981               }
83982
83983               var index = selection.nodes().indexOf(this);
83984               select(this).classed('dragging', false);
83985
83986               _container.selectAll('.chip').style('transform', null);
83987
83988               if (typeof targetIndex === 'number') {
83989                 var element = _multiData[index];
83990
83991                 _multiData.splice(index, 1);
83992
83993                 _multiData.splice(targetIndex, 0, element);
83994
83995                 var t = {};
83996
83997                 if (_multiData.length) {
83998                   t[field.key] = _multiData.map(function (element) {
83999                     return element.key;
84000                   }).join(';');
84001                 } else {
84002                   t[field.key] = undefined;
84003                 }
84004
84005                 dispatch$1.call('change', this, t);
84006               }
84007
84008               dragOrigin = undefined;
84009               targetIndex = undefined;
84010             }));
84011           }
84012
84013           combo.focus = function () {
84014             _input.node().focus();
84015           };
84016
84017           combo.entityIDs = function (val) {
84018             if (!arguments.length) return _entityIDs;
84019             _entityIDs = val;
84020             return combo;
84021           };
84022
84023           function combinedEntityExtent() {
84024             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84025           }
84026
84027           return utilRebind(combo, dispatch$1, 'on');
84028         }
84029
84030         function uiFieldText(field, context) {
84031           var dispatch$1 = dispatch('change');
84032           var input = select(null);
84033           var outlinkButton = select(null);
84034           var _entityIDs = [];
84035
84036           var _tags;
84037
84038           var _phoneFormats = {};
84039
84040           if (field.type === 'tel') {
84041             _mainFileFetcher.get('phone_formats').then(function (d) {
84042               _phoneFormats = d;
84043               updatePhonePlaceholder();
84044             })["catch"](function () {
84045               /* ignore */
84046             });
84047           }
84048
84049           function i(selection) {
84050             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84051             var preset = entity && _mainPresetIndex.match(entity, context.graph());
84052             var isLocked = preset && preset.suggestion && field.id === 'brand';
84053             field.locked(isLocked);
84054             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84055             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84056             input = wrap.selectAll('input').data([0]);
84057             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);
84058             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
84059
84060             if (field.type === 'tel') {
84061               updatePhonePlaceholder();
84062             } else if (field.type === 'number') {
84063               var rtl = _mainLocalizer.textDirection() === 'rtl';
84064               input.attr('type', 'text');
84065               var inc = field.increment;
84066               var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
84067               buttons.enter().append('button').attr('class', function (d) {
84068                 var which = d > 0 ? 'increment' : 'decrement';
84069                 return 'form-field-button ' + which;
84070               }).merge(buttons).on('click', function (d3_event, d) {
84071                 d3_event.preventDefault();
84072                 var raw_vals = input.node().value || '0';
84073                 var vals = raw_vals.split(';');
84074                 vals = vals.map(function (v) {
84075                   var num = parseFloat(v.trim(), 10);
84076                   return isFinite(num) ? clamped(num + d) : v.trim();
84077                 });
84078                 input.node().value = vals.join(';');
84079                 change()();
84080               });
84081             } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
84082               input.attr('type', 'text');
84083               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
84084               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
84085                 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
84086
84087                 if (domainResults.length >= 2 && domainResults[1]) {
84088                   var domain = domainResults[1];
84089                   return _t('icons.view_on', {
84090                     domain: domain
84091                   });
84092                 }
84093
84094                 return '';
84095               }).on('click', function (d3_event) {
84096                 d3_event.preventDefault();
84097                 var value = validIdentifierValueForLink();
84098
84099                 if (value) {
84100                   var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
84101                   window.open(url, '_blank');
84102                 }
84103               }).merge(outlinkButton);
84104             }
84105           }
84106
84107           function updatePhonePlaceholder() {
84108             if (input.empty() || !Object.keys(_phoneFormats).length) return;
84109             var extent = combinedEntityExtent();
84110             var countryCode = extent && iso1A2Code(extent.center());
84111
84112             var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
84113
84114             if (format) input.attr('placeholder', format);
84115           }
84116
84117           function validIdentifierValueForLink() {
84118             if (field.type === 'identifier' && field.pattern) {
84119               var value = utilGetSetValue(input).trim().split(';')[0];
84120               return value && value.match(new RegExp(field.pattern));
84121             }
84122
84123             return null;
84124           } // clamp number to min/max
84125
84126
84127           function clamped(num) {
84128             if (field.minValue !== undefined) {
84129               num = Math.max(num, field.minValue);
84130             }
84131
84132             if (field.maxValue !== undefined) {
84133               num = Math.min(num, field.maxValue);
84134             }
84135
84136             return num;
84137           }
84138
84139           function change(onInput) {
84140             return function () {
84141               var t = {};
84142               var val = utilGetSetValue(input);
84143               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
84144
84145               if (!val && Array.isArray(_tags[field.key])) return;
84146
84147               if (!onInput) {
84148                 if (field.type === 'number' && val) {
84149                   var vals = val.split(';');
84150                   vals = vals.map(function (v) {
84151                     var num = parseFloat(v.trim(), 10);
84152                     return isFinite(num) ? clamped(num) : v.trim();
84153                   });
84154                   val = vals.join(';');
84155                 }
84156
84157                 utilGetSetValue(input, val);
84158               }
84159
84160               t[field.key] = val || undefined;
84161               dispatch$1.call('change', this, t, onInput);
84162             };
84163           }
84164
84165           i.entityIDs = function (val) {
84166             if (!arguments.length) return _entityIDs;
84167             _entityIDs = val;
84168             return i;
84169           };
84170
84171           i.tags = function (tags) {
84172             _tags = tags;
84173             var isMixed = Array.isArray(tags[field.key]);
84174             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);
84175
84176             if (outlinkButton && !outlinkButton.empty()) {
84177               var disabled = !validIdentifierValueForLink();
84178               outlinkButton.classed('disabled', disabled);
84179             }
84180           };
84181
84182           i.focus = function () {
84183             var node = input.node();
84184             if (node) node.focus();
84185           };
84186
84187           function combinedEntityExtent() {
84188             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84189           }
84190
84191           return utilRebind(i, dispatch$1, 'on');
84192         }
84193
84194         function uiFieldAccess(field, context) {
84195           var dispatch$1 = dispatch('change');
84196           var items = select(null);
84197
84198           var _tags;
84199
84200           function access(selection) {
84201             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84202             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84203             var list = wrap.selectAll('ul').data([0]);
84204             list = list.enter().append('ul').attr('class', 'rows').merge(list);
84205             items = list.selectAll('li').data(field.keys); // Enter
84206
84207             var enter = items.enter().append('li').attr('class', function (d) {
84208               return 'labeled-input preset-access-' + d;
84209             });
84210             enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
84211               return 'preset-input-access-' + d;
84212             }).html(function (d) {
84213               return field.t.html('types.' + d);
84214             });
84215             enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
84216               return 'preset-input-access preset-input-access-' + d;
84217             }).call(utilNoAuto).each(function (d) {
84218               select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
84219             }); // Update
84220
84221             items = items.merge(enter);
84222             wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
84223           }
84224
84225           function change(d3_event, d) {
84226             var tag = {};
84227             var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
84228
84229             if (!value && typeof _tags[d] !== 'string') return;
84230             tag[d] = value || undefined;
84231             dispatch$1.call('change', this, tag);
84232           }
84233
84234           access.options = function (type) {
84235             var options = ['no', 'permissive', 'private', 'permit', 'destination'];
84236
84237             if (type !== 'access') {
84238               options.unshift('yes');
84239               options.push('designated');
84240
84241               if (type === 'bicycle') {
84242                 options.push('dismount');
84243               }
84244             }
84245
84246             return options.map(function (option) {
84247               return {
84248                 title: field.t('options.' + option + '.description'),
84249                 value: option
84250               };
84251             });
84252           };
84253
84254           var placeholdersByHighway = {
84255             footway: {
84256               foot: 'designated',
84257               motor_vehicle: 'no'
84258             },
84259             steps: {
84260               foot: 'yes',
84261               motor_vehicle: 'no',
84262               bicycle: 'no',
84263               horse: 'no'
84264             },
84265             pedestrian: {
84266               foot: 'yes',
84267               motor_vehicle: 'no'
84268             },
84269             cycleway: {
84270               motor_vehicle: 'no',
84271               bicycle: 'designated'
84272             },
84273             bridleway: {
84274               motor_vehicle: 'no',
84275               horse: 'designated'
84276             },
84277             path: {
84278               foot: 'yes',
84279               motor_vehicle: 'no',
84280               bicycle: 'yes',
84281               horse: 'yes'
84282             },
84283             motorway: {
84284               foot: 'no',
84285               motor_vehicle: 'yes',
84286               bicycle: 'no',
84287               horse: 'no'
84288             },
84289             trunk: {
84290               motor_vehicle: 'yes'
84291             },
84292             primary: {
84293               foot: 'yes',
84294               motor_vehicle: 'yes',
84295               bicycle: 'yes',
84296               horse: 'yes'
84297             },
84298             secondary: {
84299               foot: 'yes',
84300               motor_vehicle: 'yes',
84301               bicycle: 'yes',
84302               horse: 'yes'
84303             },
84304             tertiary: {
84305               foot: 'yes',
84306               motor_vehicle: 'yes',
84307               bicycle: 'yes',
84308               horse: 'yes'
84309             },
84310             residential: {
84311               foot: 'yes',
84312               motor_vehicle: 'yes',
84313               bicycle: 'yes',
84314               horse: 'yes'
84315             },
84316             unclassified: {
84317               foot: 'yes',
84318               motor_vehicle: 'yes',
84319               bicycle: 'yes',
84320               horse: 'yes'
84321             },
84322             service: {
84323               foot: 'yes',
84324               motor_vehicle: 'yes',
84325               bicycle: 'yes',
84326               horse: 'yes'
84327             },
84328             motorway_link: {
84329               foot: 'no',
84330               motor_vehicle: 'yes',
84331               bicycle: 'no',
84332               horse: 'no'
84333             },
84334             trunk_link: {
84335               motor_vehicle: 'yes'
84336             },
84337             primary_link: {
84338               foot: 'yes',
84339               motor_vehicle: 'yes',
84340               bicycle: 'yes',
84341               horse: 'yes'
84342             },
84343             secondary_link: {
84344               foot: 'yes',
84345               motor_vehicle: 'yes',
84346               bicycle: 'yes',
84347               horse: 'yes'
84348             },
84349             tertiary_link: {
84350               foot: 'yes',
84351               motor_vehicle: 'yes',
84352               bicycle: 'yes',
84353               horse: 'yes'
84354             }
84355           };
84356
84357           access.tags = function (tags) {
84358             _tags = tags;
84359             utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
84360               return typeof tags[d] === 'string' ? tags[d] : '';
84361             }).classed('mixed', function (d) {
84362               return tags[d] && Array.isArray(tags[d]);
84363             }).attr('title', function (d) {
84364               return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
84365             }).attr('placeholder', function (d) {
84366               if (tags[d] && Array.isArray(tags[d])) {
84367                 return _t('inspector.multiple_values');
84368               }
84369
84370               if (d === 'access') {
84371                 return 'yes';
84372               }
84373
84374               if (tags.access && typeof tags.access === 'string') {
84375                 return tags.access;
84376               }
84377
84378               if (tags.highway) {
84379                 if (typeof tags.highway === 'string') {
84380                   if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
84381                     return placeholdersByHighway[tags.highway][d];
84382                   }
84383                 } else {
84384                   var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
84385                     return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
84386                   }).filter(Boolean);
84387
84388                   if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
84389                     // if all the highway values have the same implied access for this type then use that
84390                     return impliedAccesses[0];
84391                   }
84392                 }
84393               }
84394
84395               return field.placeholder();
84396             });
84397           };
84398
84399           access.focus = function () {
84400             items.selectAll('.preset-input-access').node().focus();
84401           };
84402
84403           return utilRebind(access, dispatch$1, 'on');
84404         }
84405
84406         function uiFieldAddress(field, context) {
84407           var dispatch$1 = dispatch('change');
84408
84409           var _selection = select(null);
84410
84411           var _wrap = select(null);
84412
84413           var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
84414
84415           var _entityIDs = [];
84416
84417           var _tags;
84418
84419           var _countryCode;
84420
84421           var _addressFormats = [{
84422             format: [['housenumber', 'street'], ['city', 'postcode']]
84423           }];
84424           _mainFileFetcher.get('address_formats').then(function (d) {
84425             _addressFormats = d;
84426
84427             if (!_selection.empty()) {
84428               _selection.call(address);
84429             }
84430           })["catch"](function () {
84431             /* ignore */
84432           });
84433
84434           function getNearStreets() {
84435             var extent = combinedEntityExtent();
84436             var l = extent.center();
84437             var box = geoExtent(l).padByMeters(200);
84438             var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
84439               var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
84440               var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
84441               return {
84442                 title: d.tags.name,
84443                 value: d.tags.name,
84444                 dist: choice.distance
84445               };
84446             }).sort(function (a, b) {
84447               return a.dist - b.dist;
84448             });
84449             return utilArrayUniqBy(streets, 'value');
84450
84451             function isAddressable(d) {
84452               return d.tags.highway && d.tags.name && d.type === 'way';
84453             }
84454           }
84455
84456           function getNearCities() {
84457             var extent = combinedEntityExtent();
84458             var l = extent.center();
84459             var box = geoExtent(l).padByMeters(200);
84460             var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
84461               return {
84462                 title: d.tags['addr:city'] || d.tags.name,
84463                 value: d.tags['addr:city'] || d.tags.name,
84464                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
84465               };
84466             }).sort(function (a, b) {
84467               return a.dist - b.dist;
84468             });
84469             return utilArrayUniqBy(cities, 'value');
84470
84471             function isAddressable(d) {
84472               if (d.tags.name) {
84473                 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
84474                 if (d.tags.border_type === 'city') return true;
84475                 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
84476               }
84477
84478               if (d.tags['addr:city']) return true;
84479               return false;
84480             }
84481           }
84482
84483           function getNearValues(key) {
84484             var extent = combinedEntityExtent();
84485             var l = extent.center();
84486             var box = geoExtent(l).padByMeters(200);
84487             var results = context.history().intersects(box).filter(function hasTag(d) {
84488               return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
84489             }).map(function (d) {
84490               return {
84491                 title: d.tags[key],
84492                 value: d.tags[key],
84493                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
84494               };
84495             }).sort(function (a, b) {
84496               return a.dist - b.dist;
84497             });
84498             return utilArrayUniqBy(results, 'value');
84499           }
84500
84501           function updateForCountryCode() {
84502             if (!_countryCode) return;
84503             var addressFormat;
84504
84505             for (var i = 0; i < _addressFormats.length; i++) {
84506               var format = _addressFormats[i];
84507
84508               if (!format.countryCodes) {
84509                 addressFormat = format; // choose the default format, keep going
84510               } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
84511                 addressFormat = format; // choose the country format, stop here
84512
84513                 break;
84514               }
84515             }
84516
84517             var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
84518             var widths = addressFormat.widths || {
84519               housenumber: 1 / 3,
84520               street: 2 / 3,
84521               city: 2 / 3,
84522               state: 1 / 4,
84523               postcode: 1 / 3
84524             };
84525
84526             function row(r) {
84527               // Normalize widths.
84528               var total = r.reduce(function (sum, key) {
84529                 return sum + (widths[key] || 0.5);
84530               }, 0);
84531               return r.map(function (key) {
84532                 return {
84533                   id: key,
84534                   width: (widths[key] || 0.5) / total
84535                 };
84536               });
84537             }
84538
84539             var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
84540               return d.toString();
84541             });
84542
84543             rows.exit().remove();
84544             rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
84545               return 'addr-' + d.id;
84546             }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
84547               return d.width * 100 + '%';
84548             });
84549
84550             function addDropdown(d) {
84551               if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
84552
84553               var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
84554               select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
84555                 callback(nearValues('addr:' + d.id));
84556               }));
84557             }
84558
84559             _wrap.selectAll('input').on('blur', change()).on('change', change());
84560
84561             _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
84562
84563             if (_tags) updateTags(_tags);
84564           }
84565
84566           function address(selection) {
84567             _selection = selection;
84568             _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84569             _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
84570             var extent = combinedEntityExtent();
84571
84572             if (extent) {
84573               var countryCode;
84574
84575               if (context.inIntro()) {
84576                 // localize the address format for the walkthrough
84577                 countryCode = _t('intro.graph.countrycode');
84578               } else {
84579                 var center = extent.center();
84580                 countryCode = iso1A2Code(center);
84581               }
84582
84583               if (countryCode) {
84584                 _countryCode = countryCode.toLowerCase();
84585                 updateForCountryCode();
84586               }
84587             }
84588           }
84589
84590           function change(onInput) {
84591             return function () {
84592               var tags = {};
84593
84594               _wrap.selectAll('input').each(function (subfield) {
84595                 var key = field.key + ':' + subfield.id;
84596                 var value = this.value;
84597                 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
84598
84599                 if (Array.isArray(_tags[key]) && !value) return;
84600                 tags[key] = value || undefined;
84601               });
84602
84603               dispatch$1.call('change', this, tags, onInput);
84604             };
84605           }
84606
84607           function updatePlaceholder(inputSelection) {
84608             return inputSelection.attr('placeholder', function (subfield) {
84609               if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
84610                 return _t('inspector.multiple_values');
84611               }
84612
84613               if (_countryCode) {
84614                 var localkey = subfield.id + '!' + _countryCode;
84615                 var tkey = addrField.strings.placeholders[localkey] ? localkey : subfield.id;
84616                 return addrField.t('placeholders.' + tkey);
84617               }
84618             });
84619           }
84620
84621           function updateTags(tags) {
84622             utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
84623               var val = tags[field.key + ':' + subfield.id];
84624               return typeof val === 'string' ? val : '';
84625             }).attr('title', function (subfield) {
84626               var val = tags[field.key + ':' + subfield.id];
84627               return val && Array.isArray(val) && val.filter(Boolean).join('\n');
84628             }).classed('mixed', function (subfield) {
84629               return Array.isArray(tags[field.key + ':' + subfield.id]);
84630             }).call(updatePlaceholder);
84631           }
84632
84633           function combinedEntityExtent() {
84634             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84635           }
84636
84637           address.entityIDs = function (val) {
84638             if (!arguments.length) return _entityIDs;
84639             _entityIDs = val;
84640             return address;
84641           };
84642
84643           address.tags = function (tags) {
84644             _tags = tags;
84645             updateTags(tags);
84646           };
84647
84648           address.focus = function () {
84649             var node = _wrap.selectAll('input').node();
84650
84651             if (node) node.focus();
84652           };
84653
84654           return utilRebind(address, dispatch$1, 'on');
84655         }
84656
84657         function uiFieldCycleway(field, context) {
84658           var dispatch$1 = dispatch('change');
84659           var items = select(null);
84660           var wrap = select(null);
84661
84662           var _tags;
84663
84664           function cycleway(selection) {
84665             function stripcolon(s) {
84666               return s.replace(':', '');
84667             }
84668
84669             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84670             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84671             var div = wrap.selectAll('ul').data([0]);
84672             div = div.enter().append('ul').attr('class', 'rows').merge(div);
84673             var keys = ['cycleway:left', 'cycleway:right'];
84674             items = div.selectAll('li').data(keys);
84675             var enter = items.enter().append('li').attr('class', function (d) {
84676               return 'labeled-input preset-cycleway-' + stripcolon(d);
84677             });
84678             enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
84679               return 'preset-input-cycleway-' + stripcolon(d);
84680             }).html(function (d) {
84681               return field.t.html('types.' + d);
84682             });
84683             enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
84684               return 'preset-input-cycleway preset-input-' + stripcolon(d);
84685             }).call(utilNoAuto).each(function (d) {
84686               select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
84687             });
84688             items = items.merge(enter); // Update
84689
84690             wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
84691           }
84692
84693           function change(d3_event, key) {
84694             var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
84695
84696             if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
84697
84698             if (newValue === 'none' || newValue === '') {
84699               newValue = undefined;
84700             }
84701
84702             var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
84703             var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
84704
84705             if (otherValue && Array.isArray(otherValue)) {
84706               // we must always have an explicit value for comparison
84707               otherValue = otherValue[0];
84708             }
84709
84710             if (otherValue === 'none' || otherValue === '') {
84711               otherValue = undefined;
84712             }
84713
84714             var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
84715             // sides the same way
84716
84717             if (newValue === otherValue) {
84718               tag = {
84719                 cycleway: newValue,
84720                 'cycleway:left': undefined,
84721                 'cycleway:right': undefined
84722               };
84723             } else {
84724               // Always set both left and right as changing one can affect the other
84725               tag = {
84726                 cycleway: undefined
84727               };
84728               tag[key] = newValue;
84729               tag[otherKey] = otherValue;
84730             }
84731
84732             dispatch$1.call('change', this, tag);
84733           }
84734
84735           cycleway.options = function () {
84736             return Object.keys(field.strings.options).map(function (option) {
84737               return {
84738                 title: field.t('options.' + option + '.description'),
84739                 value: option
84740               };
84741             });
84742           };
84743
84744           cycleway.tags = function (tags) {
84745             _tags = tags; // If cycleway is set, use that instead of individual values
84746
84747             var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
84748             utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
84749               if (commonValue) return commonValue;
84750               return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
84751             }).attr('title', function (d) {
84752               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
84753                 var vals = [];
84754
84755                 if (Array.isArray(tags.cycleway)) {
84756                   vals = vals.concat(tags.cycleway);
84757                 }
84758
84759                 if (Array.isArray(tags[d])) {
84760                   vals = vals.concat(tags[d]);
84761                 }
84762
84763                 return vals.filter(Boolean).join('\n');
84764               }
84765
84766               return null;
84767             }).attr('placeholder', function (d) {
84768               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
84769                 return _t('inspector.multiple_values');
84770               }
84771
84772               return field.placeholder();
84773             }).classed('mixed', function (d) {
84774               return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
84775             });
84776           };
84777
84778           cycleway.focus = function () {
84779             var node = wrap.selectAll('input').node();
84780             if (node) node.focus();
84781           };
84782
84783           return utilRebind(cycleway, dispatch$1, 'on');
84784         }
84785
84786         function uiFieldLanes(field, context) {
84787           var dispatch$1 = dispatch('change');
84788           var LANE_WIDTH = 40;
84789           var LANE_HEIGHT = 200;
84790           var _entityIDs = [];
84791
84792           function lanes(selection) {
84793             var lanesData = context.entity(_entityIDs[0]).lanes();
84794
84795             if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
84796               selection.call(lanes.off);
84797               return;
84798             }
84799
84800             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84801             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84802             var surface = wrap.selectAll('.surface').data([0]);
84803             var d = utilGetDimensions(wrap);
84804             var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
84805             surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
84806             var lanesSelection = surface.selectAll('.lanes').data([0]);
84807             lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
84808             lanesSelection.attr('transform', function () {
84809               return 'translate(' + freeSpace / 2 + ', 0)';
84810             });
84811             var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
84812             lane.exit().remove();
84813             var enter = lane.enter().append('g').attr('class', 'lane');
84814             enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
84815             enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
84816             enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
84817             enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
84818             lane = lane.merge(enter);
84819             lane.attr('transform', function (d) {
84820               return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
84821             });
84822             lane.select('.forward').style('visibility', function (d) {
84823               return d.direction === 'forward' ? 'visible' : 'hidden';
84824             });
84825             lane.select('.bothways').style('visibility', function (d) {
84826               return d.direction === 'bothways' ? 'visible' : 'hidden';
84827             });
84828             lane.select('.backward').style('visibility', function (d) {
84829               return d.direction === 'backward' ? 'visible' : 'hidden';
84830             });
84831           }
84832
84833           lanes.entityIDs = function (val) {
84834             _entityIDs = val;
84835           };
84836
84837           lanes.tags = function () {};
84838
84839           lanes.focus = function () {};
84840
84841           lanes.off = function () {};
84842
84843           return utilRebind(lanes, dispatch$1, 'on');
84844         }
84845         uiFieldLanes.supportsMultiselection = false;
84846
84847         var _languagesArray = [];
84848         function uiFieldLocalized(field, context) {
84849           var dispatch$1 = dispatch('change', 'input');
84850           var wikipedia = services.wikipedia;
84851           var input = select(null);
84852           var localizedInputs = select(null);
84853
84854           var _countryCode;
84855
84856           var _tags; // A concern here in switching to async data means that _languagesArray will not
84857           // be available the first time through, so things like the fetchers and
84858           // the language() function will not work immediately.
84859
84860
84861           _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
84862             /* ignore */
84863           });
84864           var _territoryLanguages = {};
84865           _mainFileFetcher.get('territory_languages').then(function (d) {
84866             _territoryLanguages = d;
84867           })["catch"](function () {
84868             /* ignore */
84869           });
84870           var allSuggestions = _mainPresetIndex.collection.filter(function (p) {
84871             return p.suggestion === true;
84872           }); // reuse these combos
84873
84874           var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
84875           var brandCombo = uiCombobox(context, 'localized-brand').canAutocomplete(false).minItems(1);
84876
84877           var _selection = select(null);
84878
84879           var _multilingual = [];
84880
84881           var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
84882
84883           var _wikiTitles;
84884
84885           var _entityIDs = [];
84886
84887           function loadLanguagesArray(dataLanguages) {
84888             if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
84889
84890             var replacements = {
84891               sr: 'sr-Cyrl',
84892               // in OSM, `sr` implies Cyrillic
84893               'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
84894
84895             };
84896
84897             for (var code in dataLanguages) {
84898               if (replacements[code] === false) continue;
84899               var metaCode = code;
84900               if (replacements[code]) metaCode = replacements[code];
84901
84902               _languagesArray.push({
84903                 localName: _mainLocalizer.languageName(metaCode, {
84904                   localOnly: true
84905                 }),
84906                 nativeName: dataLanguages[metaCode].nativeName,
84907                 code: code,
84908                 label: _mainLocalizer.languageName(metaCode)
84909               });
84910             }
84911           }
84912
84913           function calcLocked() {
84914             // only lock the Name field
84915             var isLocked = field.id === 'name' && _entityIDs.length && // lock the field if any feature needs it
84916             _entityIDs.some(function (entityID) {
84917               var entity = context.graph().hasEntity(entityID);
84918               if (!entity) return false;
84919
84920               var original = context.graph().base().entities[_entityIDs[0]];
84921
84922               var hasOriginalName = original && entity.tags.name && entity.tags.name === original.tags.name; // if the name was already edited manually then allow further editing
84923
84924               if (!hasOriginalName) return false; // features linked to Wikidata are likely important and should be protected
84925
84926               if (entity.tags.wikidata) return true; // assume the name has already been confirmed if its source has been researched
84927
84928               if (entity.tags['name:etymology:wikidata']) return true;
84929               var preset = _mainPresetIndex.match(entity, context.graph());
84930               var isSuggestion = preset && preset.suggestion;
84931               var showsBrand = preset && preset.originalFields.filter(function (d) {
84932                 return d.id === 'brand';
84933               }).length; // protect standardized brand names
84934
84935               return isSuggestion && !showsBrand;
84936             });
84937
84938             field.locked(isLocked);
84939           } // update _multilingual, maintaining the existing order
84940
84941
84942           function calcMultilingual(tags) {
84943             var existingLangsOrdered = _multilingual.map(function (item) {
84944               return item.lang;
84945             });
84946
84947             var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
84948
84949             for (var k in tags) {
84950               var m = k.match(/^(.*):(.+)$/);
84951
84952               if (m && m[1] === field.key && m[2]) {
84953                 var item = {
84954                   lang: m[2],
84955                   value: tags[k]
84956                 };
84957
84958                 if (existingLangs.has(item.lang)) {
84959                   // update the value
84960                   _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
84961                   existingLangs["delete"](item.lang);
84962                 } else {
84963                   _multilingual.push(item);
84964                 }
84965               }
84966             }
84967
84968             _multilingual = _multilingual.filter(function (item) {
84969               return !item.lang || !existingLangs.has(item.lang);
84970             });
84971           }
84972
84973           function localized(selection) {
84974             _selection = selection;
84975             calcLocked();
84976             var isLocked = field.locked();
84977             var singularEntity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
84978             var preset = singularEntity && _mainPresetIndex.match(singularEntity, context.graph());
84979             var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
84980
84981             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84982             input = wrap.selectAll('.localized-main').data([0]); // enter/update
84983
84984             input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
84985
84986             if (preset && field.id === 'name') {
84987               var pTag = preset.id.split('/', 2);
84988               var pKey = pTag[0];
84989               var pValue = pTag[1];
84990
84991               if (!preset.suggestion) {
84992                 // Not a suggestion preset - Add a suggestions dropdown if it makes sense to.
84993                 // This code attempts to determine if the matched preset is the
84994                 // kind of preset that even can benefit from name suggestions..
84995                 // - true = shops, cafes, hotels, etc. (also generic and fallback presets)
84996                 // - false = churches, parks, hospitals, etc. (things not in the index)
84997                 var isFallback = preset.isFallback();
84998                 var goodSuggestions = allSuggestions.filter(function (s) {
84999                   if (isFallback) return true;
85000                   var sTag = s.id.split('/', 2);
85001                   var sKey = sTag[0];
85002                   var sValue = sTag[1];
85003                   return pKey === sKey && (!pValue || pValue === sValue);
85004                 }); // Show the suggestions.. If the user picks one, change the tags..
85005
85006                 if (allSuggestions.length && goodSuggestions.length) {
85007                   input.on('blur.localized', checkBrandOnBlur).call(brandCombo.fetcher(fetchBrandNames(preset, allSuggestions)).on('accept', acceptBrand).on('cancel', cancelBrand));
85008                 }
85009               }
85010             }
85011
85012             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
85013             var translateButton = wrap.selectAll('.localized-add').data([0]);
85014             translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
85015             translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
85016
85017             if (_tags && !_multilingual.length) {
85018               calcMultilingual(_tags);
85019             }
85020
85021             localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
85022             localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
85023             localizedInputs.call(renderMultilingual);
85024             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.
85025             // (This can happen if the user actives the combo, arrows down, and then clicks off to blur)
85026             // So compare the current field value against the suggestions one last time.
85027
85028             function checkBrandOnBlur() {
85029               var latest = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85030               if (!latest) return; // deleting the entity blurred the field?
85031
85032               var preset = _mainPresetIndex.match(latest, context.graph());
85033               if (preset && preset.suggestion) return; // already accepted
85034
85035               var name = utilGetSetValue(input).trim();
85036               var matched = allSuggestions.filter(function (s) {
85037                 return name === s.name();
85038               });
85039
85040               if (matched.length === 1) {
85041                 acceptBrand({
85042                   suggestion: matched[0]
85043                 });
85044               } else {
85045                 cancelBrand();
85046               }
85047             }
85048
85049             function acceptBrand(d) {
85050               var entity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85051
85052               if (!d || !entity) {
85053                 cancelBrand();
85054                 return;
85055               }
85056
85057               var tags = entity.tags;
85058               var geometry = entity.geometry(context.graph());
85059               var removed = preset.unsetTags(tags, geometry);
85060
85061               for (var k in tags) {
85062                 tags[k] = removed[k]; // set removed tags to `undefined`
85063               }
85064
85065               tags = d.suggestion.setTags(tags, geometry);
85066               utilGetSetValue(input, tags.name);
85067               dispatch$1.call('change', this, tags);
85068             } // user hit escape
85069
85070
85071             function cancelBrand() {
85072               var name = utilGetSetValue(input);
85073               dispatch$1.call('change', this, {
85074                 name: name
85075               });
85076             }
85077
85078             function fetchBrandNames(preset, suggestions) {
85079               var pTag = preset.id.split('/', 2);
85080               var pKey = pTag[0];
85081               var pValue = pTag[1];
85082               return function (value, callback) {
85083                 var results = [];
85084
85085                 if (value && value.length > 2) {
85086                   for (var i = 0; i < suggestions.length; i++) {
85087                     var s = suggestions[i]; // don't suggest brands from incompatible countries
85088
85089                     if (_countryCode && s.countryCodes && s.countryCodes.indexOf(_countryCode) === -1) continue;
85090                     var sTag = s.id.split('/', 2);
85091                     var sKey = sTag[0];
85092                     var sValue = sTag[1];
85093                     var subtitle = s.subtitle();
85094                     var name = s.name();
85095                     if (subtitle) name += ' – ' + subtitle;
85096                     var dist = utilEditDistance(value, name.substring(0, value.length));
85097                     var matchesPreset = pKey === sKey && (!pValue || pValue === sValue);
85098
85099                     if (dist < 1 || matchesPreset && dist < 3) {
85100                       var obj = {
85101                         value: s.name(),
85102                         title: name,
85103                         display: s.nameLabel() + (subtitle ? ' – ' + s.subtitleLabel() : ''),
85104                         suggestion: s,
85105                         dist: dist + (matchesPreset ? 0 : 1) // penalize if not matched preset
85106
85107                       };
85108                       results.push(obj);
85109                     }
85110                   }
85111
85112                   results.sort(function (a, b) {
85113                     return a.dist - b.dist;
85114                   });
85115                 }
85116
85117                 results = results.slice(0, 10);
85118                 callback(results);
85119               };
85120             }
85121
85122             function addNew(d3_event) {
85123               d3_event.preventDefault();
85124               if (field.locked()) return;
85125               var defaultLang = _mainLocalizer.languageCode().toLowerCase();
85126
85127               var langExists = _multilingual.find(function (datum) {
85128                 return datum.lang === defaultLang;
85129               });
85130
85131               var isLangEn = defaultLang.indexOf('en') > -1;
85132
85133               if (isLangEn || langExists) {
85134                 defaultLang = '';
85135                 langExists = _multilingual.find(function (datum) {
85136                   return datum.lang === defaultLang;
85137                 });
85138               }
85139
85140               if (!langExists) {
85141                 // prepend the value so it appears at the top
85142                 _multilingual.unshift({
85143                   lang: defaultLang,
85144                   value: ''
85145                 });
85146
85147                 localizedInputs.call(renderMultilingual);
85148               }
85149             }
85150
85151             function change(onInput) {
85152               return function (d3_event) {
85153                 if (field.locked()) {
85154                   d3_event.preventDefault();
85155                   return;
85156                 }
85157
85158                 var val = utilGetSetValue(select(this));
85159                 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
85160
85161                 if (!val && Array.isArray(_tags[field.key])) return;
85162                 var t = {};
85163                 t[field.key] = val || undefined;
85164                 dispatch$1.call('change', this, t, onInput);
85165               };
85166             }
85167           }
85168
85169           function key(lang) {
85170             return field.key + ':' + lang;
85171           }
85172
85173           function changeLang(d3_event, d) {
85174             var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
85175
85176             var lang = utilGetSetValue(select(this)).toLowerCase();
85177
85178             var language = _languagesArray.find(function (d) {
85179               return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
85180             });
85181
85182             if (language) lang = language.code;
85183
85184             if (d.lang && d.lang !== lang) {
85185               tags[key(d.lang)] = undefined;
85186             }
85187
85188             var newKey = lang && context.cleanTagKey(key(lang));
85189             var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
85190
85191             if (newKey && value) {
85192               tags[newKey] = value;
85193             } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
85194               tags[newKey] = _wikiTitles[d.lang];
85195             }
85196
85197             d.lang = lang;
85198             dispatch$1.call('change', this, tags);
85199           }
85200
85201           function changeValue(d3_event, d) {
85202             if (!d.lang) return;
85203             var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
85204
85205             if (!value && Array.isArray(d.value)) return;
85206             var t = {};
85207             t[key(d.lang)] = value;
85208             d.value = value;
85209             dispatch$1.call('change', this, t);
85210           }
85211
85212           function fetchLanguages(value, cb) {
85213             var v = value.toLowerCase(); // show the user's language first
85214
85215             var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
85216
85217             if (_countryCode && _territoryLanguages[_countryCode]) {
85218               langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
85219             }
85220
85221             var langItems = [];
85222             langCodes.forEach(function (code) {
85223               var langItem = _languagesArray.find(function (item) {
85224                 return item.code === code;
85225               });
85226
85227               if (langItem) langItems.push(langItem);
85228             });
85229             langItems = utilArrayUniq(langItems.concat(_languagesArray));
85230             cb(langItems.filter(function (d) {
85231               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;
85232             }).map(function (d) {
85233               return {
85234                 value: d.label
85235               };
85236             }));
85237           }
85238
85239           function renderMultilingual(selection) {
85240             var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
85241               return d.lang;
85242             });
85243             entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
85244             var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
85245               var wrap = select(this);
85246               var domId = utilUniqueDomId(index);
85247               var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
85248               var text = label.append('span').attr('class', 'label-text');
85249               text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
85250               text.append('span').attr('class', 'label-textannotation');
85251               label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
85252                 if (field.locked()) return;
85253                 d3_event.preventDefault();
85254
85255                 if (!d.lang || !d.value) {
85256                   _multilingual.splice(index, 1);
85257
85258                   renderMultilingual(selection);
85259                 } else {
85260                   // remove from entity tags
85261                   var t = {};
85262                   t[key(d.lang)] = undefined;
85263                   dispatch$1.call('change', this, t);
85264                 }
85265               }).call(svgIcon('#iD-operation-delete'));
85266               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);
85267               wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
85268             });
85269             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 () {
85270               select(this).style('max-height', '').style('overflow', 'visible');
85271             });
85272             entries = entries.merge(entriesEnter);
85273             entries.order();
85274             entries.classed('present', function (d) {
85275               return d.lang && d.value;
85276             });
85277             utilGetSetValue(entries.select('.localized-lang'), function (d) {
85278               var langItem = _languagesArray.find(function (item) {
85279                 return item.code === d.lang;
85280               });
85281
85282               if (langItem) return langItem.label;
85283               return d.lang;
85284             });
85285             utilGetSetValue(entries.select('.localized-value'), function (d) {
85286               return typeof d.value === 'string' ? d.value : '';
85287             }).attr('title', function (d) {
85288               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
85289             }).attr('placeholder', function (d) {
85290               return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
85291             }).classed('mixed', function (d) {
85292               return Array.isArray(d.value);
85293             });
85294           }
85295
85296           localized.tags = function (tags) {
85297             _tags = tags; // Fetch translations from wikipedia
85298
85299             if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
85300               _wikiTitles = {};
85301               var wm = tags.wikipedia.match(/([^:]+):(.+)/);
85302
85303               if (wm && wm[0] && wm[1]) {
85304                 wikipedia.translations(wm[1], wm[2], function (err, d) {
85305                   if (err || !d) return;
85306                   _wikiTitles = d;
85307                 });
85308               }
85309             }
85310
85311             var isMixed = Array.isArray(tags[field.key]);
85312             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);
85313             calcMultilingual(tags);
85314
85315             _selection.call(localized);
85316           };
85317
85318           localized.focus = function () {
85319             input.node().focus();
85320           };
85321
85322           localized.entityIDs = function (val) {
85323             if (!arguments.length) return _entityIDs;
85324             _entityIDs = val;
85325             _multilingual = [];
85326             loadCountryCode();
85327             return localized;
85328           };
85329
85330           function loadCountryCode() {
85331             var extent = combinedEntityExtent();
85332             var countryCode = extent && iso1A2Code(extent.center());
85333             _countryCode = countryCode && countryCode.toLowerCase();
85334           }
85335
85336           function combinedEntityExtent() {
85337             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85338           }
85339
85340           return utilRebind(localized, dispatch$1, 'on');
85341         }
85342
85343         function uiFieldMaxspeed(field, context) {
85344           var dispatch$1 = dispatch('change');
85345           var unitInput = select(null);
85346           var input = select(null);
85347           var _entityIDs = [];
85348
85349           var _tags;
85350
85351           var _isImperial;
85352
85353           var speedCombo = uiCombobox(context, 'maxspeed');
85354           var unitCombo = uiCombobox(context, 'maxspeed-unit').data(['km/h', 'mph'].map(comboValues));
85355           var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
85356           var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
85357
85358           function maxspeed(selection) {
85359             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85360             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85361             input = wrap.selectAll('input.maxspeed-number').data([0]);
85362             input = input.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
85363             input.on('change', change).on('blur', change);
85364             var loc = combinedEntityExtent().center();
85365             _isImperial = roadSpeedUnit(loc) === 'mph';
85366             unitInput = wrap.selectAll('input.maxspeed-unit').data([0]);
85367             unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-unit').call(unitCombo).merge(unitInput);
85368             unitInput.on('blur', changeUnits).on('change', changeUnits);
85369
85370             function changeUnits() {
85371               _isImperial = utilGetSetValue(unitInput) === 'mph';
85372               utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
85373               setUnitSuggestions();
85374               change();
85375             }
85376           }
85377
85378           function setUnitSuggestions() {
85379             speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
85380             utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
85381           }
85382
85383           function comboValues(d) {
85384             return {
85385               value: d.toString(),
85386               title: d.toString()
85387             };
85388           }
85389
85390           function change() {
85391             var tag = {};
85392             var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
85393
85394             if (!value && Array.isArray(_tags[field.key])) return;
85395
85396             if (!value) {
85397               tag[field.key] = undefined;
85398             } else if (isNaN(value) || !_isImperial) {
85399               tag[field.key] = context.cleanTagValue(value);
85400             } else {
85401               tag[field.key] = context.cleanTagValue(value + ' mph');
85402             }
85403
85404             dispatch$1.call('change', this, tag);
85405           }
85406
85407           maxspeed.tags = function (tags) {
85408             _tags = tags;
85409             var value = tags[field.key];
85410             var isMixed = Array.isArray(value);
85411
85412             if (!isMixed) {
85413               if (value && value.indexOf('mph') >= 0) {
85414                 value = parseInt(value, 10).toString();
85415                 _isImperial = true;
85416               } else if (value) {
85417                 _isImperial = false;
85418               }
85419             }
85420
85421             setUnitSuggestions();
85422             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);
85423           };
85424
85425           maxspeed.focus = function () {
85426             input.node().focus();
85427           };
85428
85429           maxspeed.entityIDs = function (val) {
85430             _entityIDs = val;
85431           };
85432
85433           function combinedEntityExtent() {
85434             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85435           }
85436
85437           return utilRebind(maxspeed, dispatch$1, 'on');
85438         }
85439
85440         function uiFieldRadio(field, context) {
85441           var dispatch$1 = dispatch('change');
85442           var placeholder = select(null);
85443           var wrap = select(null);
85444           var labels = select(null);
85445           var radios = select(null);
85446           var radioData = (field.options || field.strings && field.strings.options && Object.keys(field.strings.options) || field.keys).slice(); // shallow copy
85447
85448           var typeField;
85449           var layerField;
85450           var _oldType = {};
85451           var _entityIDs = [];
85452
85453           function selectedKey() {
85454             var node = wrap.selectAll('.form-field-input-radio label.active input');
85455             return !node.empty() && node.datum();
85456           }
85457
85458           function radio(selection) {
85459             selection.classed('preset-radio', true);
85460             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85461             var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
85462             enter.append('span').attr('class', 'placeholder');
85463             wrap = wrap.merge(enter);
85464             placeholder = wrap.selectAll('.placeholder');
85465             labels = wrap.selectAll('label').data(radioData);
85466             enter = labels.enter().append('label');
85467             enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
85468               return field.t('options.' + d, {
85469                 'default': d
85470               });
85471             }).attr('checked', false);
85472             enter.append('span').html(function (d) {
85473               return field.t.html('options.' + d, {
85474                 'default': d
85475               });
85476             });
85477             labels = labels.merge(enter);
85478             radios = labels.selectAll('input').on('change', changeRadio);
85479           }
85480
85481           function structureExtras(selection, tags) {
85482             var selected = selectedKey() || tags.layer !== undefined;
85483             var type = _mainPresetIndex.field(selected);
85484             var layer = _mainPresetIndex.field('layer');
85485             var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
85486             var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
85487             extrasWrap.exit().remove();
85488             extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
85489             var list = extrasWrap.selectAll('ul').data([0]);
85490             list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
85491
85492             if (type) {
85493               if (!typeField || typeField.id !== selected) {
85494                 typeField = uiField(context, type, _entityIDs, {
85495                   wrap: false
85496                 }).on('change', changeType);
85497               }
85498
85499               typeField.tags(tags);
85500             } else {
85501               typeField = null;
85502             }
85503
85504             var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
85505               return d.id;
85506             }); // Exit
85507
85508             typeItem.exit().remove(); // Enter
85509
85510             var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
85511             typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
85512             typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
85513
85514             typeItem = typeItem.merge(typeEnter);
85515
85516             if (typeField) {
85517               typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
85518             } // Layer
85519
85520
85521             if (layer && showLayer) {
85522               if (!layerField) {
85523                 layerField = uiField(context, layer, _entityIDs, {
85524                   wrap: false
85525                 }).on('change', changeLayer);
85526               }
85527
85528               layerField.tags(tags);
85529               field.keys = utilArrayUnion(field.keys, ['layer']);
85530             } else {
85531               layerField = null;
85532               field.keys = field.keys.filter(function (k) {
85533                 return k !== 'layer';
85534               });
85535             }
85536
85537             var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
85538
85539             layerItem.exit().remove(); // Enter
85540
85541             var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
85542             layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
85543             layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
85544
85545             layerItem = layerItem.merge(layerEnter);
85546
85547             if (layerField) {
85548               layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
85549             }
85550           }
85551
85552           function changeType(t, onInput) {
85553             var key = selectedKey();
85554             if (!key) return;
85555             var val = t[key];
85556
85557             if (val !== 'no') {
85558               _oldType[key] = val;
85559             }
85560
85561             if (field.type === 'structureRadio') {
85562               // remove layer if it should not be set
85563               if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
85564                 t.layer = undefined;
85565               } // add layer if it should be set
85566
85567
85568               if (t.layer === undefined) {
85569                 if (key === 'bridge' && val !== 'no') {
85570                   t.layer = '1';
85571                 }
85572
85573                 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
85574                   t.layer = '-1';
85575                 }
85576               }
85577             }
85578
85579             dispatch$1.call('change', this, t, onInput);
85580           }
85581
85582           function changeLayer(t, onInput) {
85583             if (t.layer === '0') {
85584               t.layer = undefined;
85585             }
85586
85587             dispatch$1.call('change', this, t, onInput);
85588           }
85589
85590           function changeRadio() {
85591             var t = {};
85592             var activeKey;
85593
85594             if (field.key) {
85595               t[field.key] = undefined;
85596             }
85597
85598             radios.each(function (d) {
85599               var active = select(this).property('checked');
85600               if (active) activeKey = d;
85601
85602               if (field.key) {
85603                 if (active) t[field.key] = d;
85604               } else {
85605                 var val = _oldType[activeKey] || 'yes';
85606                 t[d] = active ? val : undefined;
85607               }
85608             });
85609
85610             if (field.type === 'structureRadio') {
85611               if (activeKey === 'bridge') {
85612                 t.layer = '1';
85613               } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
85614                 t.layer = '-1';
85615               } else {
85616                 t.layer = undefined;
85617               }
85618             }
85619
85620             dispatch$1.call('change', this, t);
85621           }
85622
85623           radio.tags = function (tags) {
85624             radios.property('checked', function (d) {
85625               if (field.key) {
85626                 return tags[field.key] === d;
85627               }
85628
85629               return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
85630             });
85631
85632             function isMixed(d) {
85633               if (field.key) {
85634                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
85635               }
85636
85637               return Array.isArray(tags[d]);
85638             }
85639
85640             labels.classed('active', function (d) {
85641               if (field.key) {
85642                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
85643               }
85644
85645               return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
85646             }).classed('mixed', isMixed).attr('title', function (d) {
85647               return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
85648             });
85649             var selection = radios.filter(function () {
85650               return this.checked;
85651             });
85652
85653             if (selection.empty()) {
85654               placeholder.html(_t.html('inspector.none'));
85655             } else {
85656               placeholder.html(selection.attr('value'));
85657               _oldType[selection.datum()] = tags[selection.datum()];
85658             }
85659
85660             if (field.type === 'structureRadio') {
85661               // For waterways without a tunnel tag, set 'culvert' as
85662               // the _oldType to default to if the user picks 'tunnel'
85663               if (!!tags.waterway && !_oldType.tunnel) {
85664                 _oldType.tunnel = 'culvert';
85665               }
85666
85667               wrap.call(structureExtras, tags);
85668             }
85669           };
85670
85671           radio.focus = function () {
85672             radios.node().focus();
85673           };
85674
85675           radio.entityIDs = function (val) {
85676             if (!arguments.length) return _entityIDs;
85677             _entityIDs = val;
85678             _oldType = {};
85679             return radio;
85680           };
85681
85682           radio.isAllowed = function () {
85683             return _entityIDs.length === 1;
85684           };
85685
85686           return utilRebind(radio, dispatch$1, 'on');
85687         }
85688
85689         function uiFieldRestrictions(field, context) {
85690           var dispatch$1 = dispatch('change');
85691           var breathe = behaviorBreathe();
85692           corePreferences('turn-restriction-via-way', null); // remove old key
85693
85694           var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
85695
85696           var storedDistance = corePreferences('turn-restriction-distance');
85697
85698           var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
85699
85700           var _maxDistance = storedDistance ? +storedDistance : 30;
85701
85702           var _initialized = false;
85703
85704           var _parent = select(null); // the entire field
85705
85706
85707           var _container = select(null); // just the map
85708
85709
85710           var _oldTurns;
85711
85712           var _graph;
85713
85714           var _vertexID;
85715
85716           var _intersection;
85717
85718           var _fromWayID;
85719
85720           var _lastXPos;
85721
85722           function restrictions(selection) {
85723             _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
85724
85725             if (_vertexID && (context.graph() !== _graph || !_intersection)) {
85726               _graph = context.graph();
85727               _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
85728             } // It's possible for there to be no actual intersection here.
85729             // for example, a vertex of two `highway=path`
85730             // In this case, hide the field.
85731
85732
85733             var isOK = _intersection && _intersection.vertices.length && // has vertices
85734             _intersection.vertices // has the vertex that the user selected
85735             .filter(function (vertex) {
85736               return vertex.id === _vertexID;
85737             }).length && _intersection.ways.length > 2 && // has more than 2 ways
85738             _intersection.ways // has more than 1 TO way
85739             .filter(function (way) {
85740               return way.__to;
85741             }).length > 1; // Also hide in the case where
85742
85743             select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
85744
85745             if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
85746               selection.call(restrictions.off);
85747               return;
85748             }
85749
85750             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85751             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85752             var container = wrap.selectAll('.restriction-container').data([0]); // enter
85753
85754             var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
85755             containerEnter.append('div').attr('class', 'restriction-help'); // update
85756
85757             _container = containerEnter.merge(container).call(renderViewer);
85758             var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
85759
85760             controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
85761           }
85762
85763           function renderControls(selection) {
85764             var distControl = selection.selectAll('.restriction-distance').data([0]);
85765             distControl.exit().remove();
85766             var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
85767             distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
85768             distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
85769             distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
85770
85771             selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
85772               var val = select(this).property('value');
85773               _maxDistance = +val;
85774               _intersection = null;
85775
85776               _container.selectAll('.layer-osm .layer-turns *').remove();
85777
85778               corePreferences('turn-restriction-distance', _maxDistance);
85779
85780               _parent.call(restrictions);
85781             });
85782             selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
85783             var viaControl = selection.selectAll('.restriction-via-way').data([0]);
85784             viaControl.exit().remove();
85785             var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
85786             viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
85787             viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
85788             viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
85789
85790             selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
85791               var val = select(this).property('value');
85792               _maxViaWay = +val;
85793
85794               _container.selectAll('.layer-osm .layer-turns *').remove();
85795
85796               corePreferences('turn-restriction-via-way0', _maxViaWay);
85797
85798               _parent.call(restrictions);
85799             });
85800             selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
85801           }
85802
85803           function renderViewer(selection) {
85804             if (!_intersection) return;
85805             var vgraph = _intersection.graph;
85806             var filter = utilFunctor(true);
85807             var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
85808             // Instead of asking the restriction-container for its dimensions,
85809             //  we can ask the .sidebar, which can have its dimensions cached.
85810             // width: calc as sidebar - padding
85811             // height: hardcoded (from `80_app.css`)
85812             // var d = utilGetDimensions(selection);
85813
85814             var sdims = utilGetDimensions(context.container().select('.sidebar'));
85815             var d = [sdims[0] - 50, 370];
85816             var c = geoVecScale(d, 0.5);
85817             var z = 22;
85818             projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
85819
85820             var extent = geoExtent();
85821
85822             for (var i = 0; i < _intersection.vertices.length; i++) {
85823               extent._extend(_intersection.vertices[i].extent());
85824             } // If this is a large intersection, adjust zoom to fit extent
85825
85826
85827             if (_intersection.vertices.length > 1) {
85828               var padding = 180; // in z22 pixels
85829
85830               var tl = projection([extent[0][0], extent[1][1]]);
85831               var br = projection([extent[1][0], extent[0][1]]);
85832               var hFactor = (br[0] - tl[0]) / (d[0] - padding);
85833               var vFactor = (br[1] - tl[1]) / (d[1] - padding);
85834               var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
85835               var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
85836               z = z - Math.max(hZoomDiff, vZoomDiff);
85837               projection.scale(geoZoomToScale(z));
85838             }
85839
85840             var padTop = 35; // reserve top space for hint text
85841
85842             var extentCenter = projection(extent.center());
85843             extentCenter[1] = extentCenter[1] - padTop;
85844             projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
85845             var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
85846             var drawVertices = svgVertices(projection, context);
85847             var drawLines = svgLines(projection, context);
85848             var drawTurns = svgTurns(projection, context);
85849             var firstTime = selection.selectAll('.surface').empty();
85850             selection.call(drawLayers);
85851             var surface = selection.selectAll('.surface').classed('tr', true);
85852
85853             if (firstTime) {
85854               _initialized = true;
85855               surface.call(breathe);
85856             } // This can happen if we've lowered the detail while a FROM way
85857             // is selected, and that way is no longer part of the intersection.
85858
85859
85860             if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
85861               _fromWayID = null;
85862               _oldTurns = null;
85863             }
85864
85865             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));
85866             surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
85867             surface.selectAll('.selected').classed('selected', false);
85868             surface.selectAll('.related').classed('related', false);
85869             var way;
85870
85871             if (_fromWayID) {
85872               way = vgraph.entity(_fromWayID);
85873               surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
85874             }
85875
85876             document.addEventListener('resizeWindow', function () {
85877               utilSetDimensions(_container, null);
85878               redraw(1);
85879             }, false);
85880             updateHints(null);
85881
85882             function click(d3_event) {
85883               surface.call(breathe.off).call(breathe);
85884               var datum = d3_event.target.__data__;
85885               var entity = datum && datum.properties && datum.properties.entity;
85886
85887               if (entity) {
85888                 datum = entity;
85889               }
85890
85891               if (datum instanceof osmWay && (datum.__from || datum.__via)) {
85892                 _fromWayID = datum.id;
85893                 _oldTurns = null;
85894                 redraw();
85895               } else if (datum instanceof osmTurn) {
85896                 var actions, extraActions, turns, i;
85897                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
85898
85899                 if (datum.restrictionID && !datum.direct) {
85900                   return;
85901                 } else if (datum.restrictionID && !datum.only) {
85902                   // NO -> ONLY
85903                   var seen = {};
85904                   var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
85905
85906                   datumOnly.only = true; // but change this property
85907
85908                   restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
85909                   // We will remember them in _oldTurns, and restore them if the user clicks again.
85910
85911                   turns = _intersection.turns(_fromWayID, 2);
85912                   extraActions = [];
85913                   _oldTurns = [];
85914
85915                   for (i = 0; i < turns.length; i++) {
85916                     var turn = turns[i];
85917                     if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
85918
85919                     if (turn.direct && turn.path[1] === datum.path[1]) {
85920                       seen[turns[i].restrictionID] = true;
85921                       turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
85922
85923                       _oldTurns.push(turn);
85924
85925                       extraActions.push(actionUnrestrictTurn(turn));
85926                     }
85927                   }
85928
85929                   actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
85930                 } else if (datum.restrictionID) {
85931                   // ONLY -> Allowed
85932                   // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
85933                   // This relies on the assumption that the intersection was already split up when we
85934                   // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
85935                   turns = _oldTurns || [];
85936                   extraActions = [];
85937
85938                   for (i = 0; i < turns.length; i++) {
85939                     if (turns[i].key !== datum.key) {
85940                       extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
85941                     }
85942                   }
85943
85944                   _oldTurns = null;
85945                   actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
85946                 } else {
85947                   // Allowed -> NO
85948                   actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
85949                 }
85950
85951                 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
85952                 // Refresh it and update the help..
85953
85954                 var s = surface.selectAll('.' + datum.key);
85955                 datum = s.empty() ? null : s.datum();
85956                 updateHints(datum);
85957               } else {
85958                 _fromWayID = null;
85959                 _oldTurns = null;
85960                 redraw();
85961               }
85962             }
85963
85964             function mouseover(d3_event) {
85965               var datum = d3_event.target.__data__;
85966               updateHints(datum);
85967             }
85968
85969             _lastXPos = _lastXPos || sdims[0];
85970
85971             function redraw(minChange) {
85972               var xPos = -1;
85973
85974               if (minChange) {
85975                 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
85976               }
85977
85978               if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
85979                 if (context.hasEntity(_vertexID)) {
85980                   _lastXPos = xPos;
85981
85982                   _container.call(renderViewer);
85983                 }
85984               }
85985             }
85986
85987             function highlightPathsFrom(wayID) {
85988               surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
85989               surface.selectAll('.' + wayID).classed('related', true);
85990
85991               if (wayID) {
85992                 var turns = _intersection.turns(wayID, _maxViaWay);
85993
85994                 for (var i = 0; i < turns.length; i++) {
85995                   var turn = turns[i];
85996                   var ids = [turn.to.way];
85997                   var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
85998
85999                   if (turn.only || turns.length === 1) {
86000                     if (turn.via.ways) {
86001                       ids = ids.concat(turn.via.ways);
86002                     }
86003                   } else if (turn.to.way === wayID) {
86004                     continue;
86005                   }
86006
86007                   surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
86008                 }
86009               }
86010             }
86011
86012             function updateHints(datum) {
86013               var help = _container.selectAll('.restriction-help').html('');
86014
86015               var placeholders = {};
86016               ['from', 'via', 'to'].forEach(function (k) {
86017                 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
86018               });
86019               var entity = datum && datum.properties && datum.properties.entity;
86020
86021               if (entity) {
86022                 datum = entity;
86023               }
86024
86025               if (_fromWayID) {
86026                 way = vgraph.entity(_fromWayID);
86027                 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86028               } // Hovering a way
86029
86030
86031               if (datum instanceof osmWay && datum.__from) {
86032                 way = datum;
86033                 highlightPathsFrom(_fromWayID ? null : way.id);
86034                 surface.selectAll('.' + way.id).classed('related', true);
86035                 var clickSelect = !_fromWayID || _fromWayID !== way.id;
86036                 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
86037                 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
86038                   from: placeholders.from,
86039                   fromName: displayName(way.id, vgraph)
86040                 })); // Hovering a turn arrow
86041               } else if (datum instanceof osmTurn) {
86042                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86043                 var turnType = restrictionType.replace(/^(only|no)\_/, '');
86044                 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
86045                 var klass, turnText, nextText;
86046
86047                 if (datum.no) {
86048                   klass = 'restrict';
86049                   turnText = _t.html('restriction.help.turn.no_' + turnType, {
86050                     indirect: indirect
86051                   });
86052                   nextText = _t.html('restriction.help.turn.only_' + turnType, {
86053                     indirect: ''
86054                   });
86055                 } else if (datum.only) {
86056                   klass = 'only';
86057                   turnText = _t.html('restriction.help.turn.only_' + turnType, {
86058                     indirect: indirect
86059                   });
86060                   nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
86061                     indirect: ''
86062                   });
86063                 } else {
86064                   klass = 'allow';
86065                   turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
86066                     indirect: indirect
86067                   });
86068                   nextText = _t.html('restriction.help.turn.no_' + turnType, {
86069                     indirect: ''
86070                   });
86071                 }
86072
86073                 help.append('div') // "NO Right Turn (indirect)"
86074                 .attr('class', 'qualifier ' + klass).html(turnText);
86075                 help.append('div') // "FROM {fromName} TO {toName}"
86076                 .html(_t.html('restriction.help.from_name_to_name', {
86077                   from: placeholders.from,
86078                   fromName: displayName(datum.from.way, vgraph),
86079                   to: placeholders.to,
86080                   toName: displayName(datum.to.way, vgraph)
86081                 }));
86082
86083                 if (datum.via.ways && datum.via.ways.length) {
86084                   var names = [];
86085
86086                   for (var i = 0; i < datum.via.ways.length; i++) {
86087                     var prev = names[names.length - 1];
86088                     var curr = displayName(datum.via.ways[i], vgraph);
86089                     if (!prev || curr !== prev) // collapse identical names
86090                       names.push(curr);
86091                   }
86092
86093                   help.append('div') // "VIA {viaNames}"
86094                   .html(_t.html('restriction.help.via_names', {
86095                     via: placeholders.via,
86096                     viaNames: names.join(', ')
86097                   }));
86098                 }
86099
86100                 if (!indirect) {
86101                   help.append('div') // Click for "No Right Turn"
86102                   .html(_t.html('restriction.help.toggle', {
86103                     turn: nextText.trim()
86104                   }));
86105                 }
86106
86107                 highlightPathsFrom(null);
86108                 var alongIDs = datum.path.slice();
86109                 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
86110               } else {
86111                 highlightPathsFrom(null);
86112
86113                 if (_fromWayID) {
86114                   help.append('div') // "FROM {fromName}"
86115                   .html(_t.html('restriction.help.from_name', {
86116                     from: placeholders.from,
86117                     fromName: displayName(_fromWayID, vgraph)
86118                   }));
86119                 } else {
86120                   help.append('div') // "Click to select a FROM segment."
86121                   .html(_t.html('restriction.help.select_from', {
86122                     from: placeholders.from
86123                   }));
86124                 }
86125               }
86126             }
86127           }
86128
86129           function displayMaxDistance(maxDist) {
86130             var isImperial = !_mainLocalizer.usesMetric();
86131             var opts;
86132
86133             if (isImperial) {
86134               var distToFeet = {
86135                 // imprecise conversion for prettier display
86136                 20: 70,
86137                 25: 85,
86138                 30: 100,
86139                 35: 115,
86140                 40: 130,
86141                 45: 145,
86142                 50: 160
86143               }[maxDist];
86144               opts = {
86145                 distance: _t('units.feet', {
86146                   quantity: distToFeet
86147                 })
86148               };
86149             } else {
86150               opts = {
86151                 distance: _t('units.meters', {
86152                   quantity: maxDist
86153                 })
86154               };
86155             }
86156
86157             return _t.html('restriction.controls.distance_up_to', opts);
86158           }
86159
86160           function displayMaxVia(maxVia) {
86161             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');
86162           }
86163
86164           function displayName(entityID, graph) {
86165             var entity = graph.entity(entityID);
86166             var name = utilDisplayName(entity) || '';
86167             var matched = _mainPresetIndex.match(entity, graph);
86168             var type = matched && matched.name() || utilDisplayType(entity.id);
86169             return name || type;
86170           }
86171
86172           restrictions.entityIDs = function (val) {
86173             _intersection = null;
86174             _fromWayID = null;
86175             _oldTurns = null;
86176             _vertexID = val[0];
86177           };
86178
86179           restrictions.tags = function () {};
86180
86181           restrictions.focus = function () {};
86182
86183           restrictions.off = function (selection) {
86184             if (!_initialized) return;
86185             selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
86186             select(window).on('resize.restrictions', null);
86187           };
86188
86189           return utilRebind(restrictions, dispatch$1, 'on');
86190         }
86191         uiFieldRestrictions.supportsMultiselection = false;
86192
86193         function uiFieldTextarea(field, context) {
86194           var dispatch$1 = dispatch('change');
86195           var input = select(null);
86196
86197           var _tags;
86198
86199           function textarea(selection) {
86200             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86201             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86202             input = wrap.selectAll('textarea').data([0]);
86203             input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
86204           }
86205
86206           function change(onInput) {
86207             return function () {
86208               var val = utilGetSetValue(input);
86209               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
86210
86211               if (!val && Array.isArray(_tags[field.key])) return;
86212               var t = {};
86213               t[field.key] = val || undefined;
86214               dispatch$1.call('change', this, t, onInput);
86215             };
86216           }
86217
86218           textarea.tags = function (tags) {
86219             _tags = tags;
86220             var isMixed = Array.isArray(tags[field.key]);
86221             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);
86222           };
86223
86224           textarea.focus = function () {
86225             input.node().focus();
86226           };
86227
86228           return utilRebind(textarea, dispatch$1, 'on');
86229         }
86230
86231         var getOwnPropertyDescriptor$5 = objectGetOwnPropertyDescriptor.f;
86232
86233
86234
86235
86236
86237
86238         var nativeEndsWith = ''.endsWith;
86239         var min$a = Math.min;
86240
86241         var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegexpLogic('endsWith');
86242         // https://github.com/zloirock/core-js/pull/702
86243         var MDN_POLYFILL_BUG$1 =  !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
86244           var descriptor = getOwnPropertyDescriptor$5(String.prototype, 'endsWith');
86245           return descriptor && !descriptor.writable;
86246         }();
86247
86248         // `String.prototype.endsWith` method
86249         // https://tc39.es/ecma262/#sec-string.prototype.endswith
86250         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
86251           endsWith: function endsWith(searchString /* , endPosition = @length */) {
86252             var that = String(requireObjectCoercible(this));
86253             notARegexp(searchString);
86254             var endPosition = arguments.length > 1 ? arguments[1] : undefined;
86255             var len = toLength(that.length);
86256             var end = endPosition === undefined ? len : min$a(toLength(endPosition), len);
86257             var search = String(searchString);
86258             return nativeEndsWith
86259               ? nativeEndsWith.call(that, search, end)
86260               : that.slice(end - search.length, end) === search;
86261           }
86262         });
86263
86264         function uiFieldWikidata(field, context) {
86265           var wikidata = services.wikidata;
86266           var dispatch$1 = dispatch('change');
86267
86268           var _selection = select(null);
86269
86270           var _searchInput = select(null);
86271
86272           var _qid = null;
86273           var _wikidataEntity = null;
86274           var _wikiURL = '';
86275           var _entityIDs = [];
86276
86277           var _wikipediaKey = field.keys && field.keys.find(function (key) {
86278             return key.includes('wikipedia');
86279           }),
86280               _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
86281
86282           var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
86283
86284           function wiki(selection) {
86285             _selection = selection;
86286             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86287             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86288             var list = wrap.selectAll('ul').data([0]);
86289             list = list.enter().append('ul').attr('class', 'rows').merge(list);
86290             var searchRow = list.selectAll('li.wikidata-search').data([0]);
86291             var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
86292             searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
86293               var node = select(this).node();
86294               node.setSelectionRange(0, node.value.length);
86295             }).on('blur', function () {
86296               setLabelForEntity();
86297             }).call(combobox.fetcher(fetchWikidataItems));
86298             combobox.on('accept', function (d) {
86299               if (d) {
86300                 _qid = d.id;
86301                 change();
86302               }
86303             }).on('cancel', function () {
86304               setLabelForEntity();
86305             });
86306             searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
86307               domain: 'wikidata.org'
86308             })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
86309               d3_event.preventDefault();
86310               if (_wikiURL) window.open(_wikiURL, '_blank');
86311             });
86312             searchRow = searchRow.merge(searchRowEnter);
86313             _searchInput = searchRow.select('input');
86314             var wikidataProperties = ['description', 'identifier'];
86315             var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
86316
86317             var enter = items.enter().append('li').attr('class', function (d) {
86318               return 'labeled-input preset-wikidata-' + d;
86319             });
86320             enter.append('span').attr('class', 'label').html(function (d) {
86321               return _t.html('wikidata.' + d);
86322             });
86323             enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
86324             enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
86325               d3_event.preventDefault();
86326               select(this.parentNode).select('input').node().select();
86327               document.execCommand('copy');
86328             });
86329           }
86330
86331           function fetchWikidataItems(q, callback) {
86332             if (!q && _hintKey) {
86333               // other tags may be good search terms
86334               for (var i in _entityIDs) {
86335                 var entity = context.hasEntity(_entityIDs[i]);
86336
86337                 if (entity.tags[_hintKey]) {
86338                   q = entity.tags[_hintKey];
86339                   break;
86340                 }
86341               }
86342             }
86343
86344             wikidata.itemsForSearchQuery(q, function (err, data) {
86345               if (err) return;
86346
86347               for (var i in data) {
86348                 data[i].value = data[i].label + ' (' + data[i].id + ')';
86349                 data[i].title = data[i].description;
86350               }
86351
86352               if (callback) callback(data);
86353             });
86354           }
86355
86356           function change() {
86357             var syncTags = {};
86358             syncTags[field.key] = _qid;
86359             dispatch$1.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
86360
86361             var initGraph = context.graph();
86362             var initEntityIDs = _entityIDs;
86363             wikidata.entityByQID(_qid, function (err, entity) {
86364               if (err) return; // If graph has changed, we can't apply this update.
86365
86366               if (context.graph() !== initGraph) return;
86367               if (!entity.sitelinks) return;
86368               var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
86369
86370               ['labels', 'descriptions'].forEach(function (key) {
86371                 if (!entity[key]) return;
86372                 var valueLangs = Object.keys(entity[key]);
86373                 if (valueLangs.length === 0) return;
86374                 var valueLang = valueLangs[0];
86375
86376                 if (langs.indexOf(valueLang) === -1) {
86377                   langs.push(valueLang);
86378                 }
86379               });
86380               var newWikipediaValue;
86381
86382               if (_wikipediaKey) {
86383                 var foundPreferred;
86384
86385                 for (var i in langs) {
86386                   var lang = langs[i];
86387                   var siteID = lang.replace('-', '_') + 'wiki';
86388
86389                   if (entity.sitelinks[siteID]) {
86390                     foundPreferred = true;
86391                     newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
86392
86393                     break;
86394                   }
86395                 }
86396
86397                 if (!foundPreferred) {
86398                   // No wikipedia sites available in the user's language or the fallback languages,
86399                   // default to any wikipedia sitelink
86400                   var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
86401                     return site.endsWith('wiki');
86402                   });
86403
86404                   if (wikiSiteKeys.length === 0) {
86405                     // if no wikipedia pages are linked to this wikidata entity, delete that tag
86406                     newWikipediaValue = null;
86407                   } else {
86408                     var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
86409                     var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
86410                     newWikipediaValue = wikiLang + ':' + wikiTitle;
86411                   }
86412                 }
86413               }
86414
86415               if (newWikipediaValue) {
86416                 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
86417               }
86418
86419               if (typeof newWikipediaValue === 'undefined') return;
86420               var actions = initEntityIDs.map(function (entityID) {
86421                 var entity = context.hasEntity(entityID);
86422                 if (!entity) return null;
86423                 var currTags = Object.assign({}, entity.tags); // shallow copy
86424
86425                 if (newWikipediaValue === null) {
86426                   if (!currTags[_wikipediaKey]) return null;
86427                   delete currTags[_wikipediaKey];
86428                 } else {
86429                   currTags[_wikipediaKey] = newWikipediaValue;
86430                 }
86431
86432                 return actionChangeTags(entityID, currTags);
86433               }).filter(Boolean);
86434               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
86435
86436               context.overwrite(function actionUpdateWikipediaTags(graph) {
86437                 actions.forEach(function (action) {
86438                   graph = action(graph);
86439                 });
86440                 return graph;
86441               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
86442               // changeTags() is not intended to be called asynchronously
86443             });
86444           }
86445
86446           function setLabelForEntity() {
86447             var label = '';
86448
86449             if (_wikidataEntity) {
86450               label = entityPropertyForDisplay(_wikidataEntity, 'labels');
86451
86452               if (label.length === 0) {
86453                 label = _wikidataEntity.id.toString();
86454               }
86455             }
86456
86457             utilGetSetValue(_searchInput, label);
86458           }
86459
86460           wiki.tags = function (tags) {
86461             var isMixed = Array.isArray(tags[field.key]);
86462
86463             _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
86464
86465             _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
86466
86467             if (!/^Q[0-9]*$/.test(_qid)) {
86468               // not a proper QID
86469               unrecognized();
86470               return;
86471             } // QID value in correct format
86472
86473
86474             _wikiURL = 'https://wikidata.org/wiki/' + _qid;
86475             wikidata.entityByQID(_qid, function (err, entity) {
86476               if (err) {
86477                 unrecognized();
86478                 return;
86479               }
86480
86481               _wikidataEntity = entity;
86482               setLabelForEntity();
86483               var description = entityPropertyForDisplay(entity, 'descriptions');
86484
86485               _selection.select('button.wiki-link').classed('disabled', false);
86486
86487               _selection.select('.preset-wikidata-description').style('display', function () {
86488                 return description.length > 0 ? 'flex' : 'none';
86489               }).select('input').attr('value', description);
86490
86491               _selection.select('.preset-wikidata-identifier').style('display', function () {
86492                 return entity.id ? 'flex' : 'none';
86493               }).select('input').attr('value', entity.id);
86494             }); // not a proper QID
86495
86496             function unrecognized() {
86497               _wikidataEntity = null;
86498               setLabelForEntity();
86499
86500               _selection.select('.preset-wikidata-description').style('display', 'none');
86501
86502               _selection.select('.preset-wikidata-identifier').style('display', 'none');
86503
86504               _selection.select('button.wiki-link').classed('disabled', true);
86505
86506               if (_qid && _qid !== '') {
86507                 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
86508               } else {
86509                 _wikiURL = '';
86510               }
86511             }
86512           };
86513
86514           function entityPropertyForDisplay(wikidataEntity, propKey) {
86515             if (!wikidataEntity[propKey]) return '';
86516             var propObj = wikidataEntity[propKey];
86517             var langKeys = Object.keys(propObj);
86518             if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
86519
86520             var langs = wikidata.languagesToQuery();
86521
86522             for (var i in langs) {
86523               var lang = langs[i];
86524               var valueObj = propObj[lang];
86525               if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
86526             } // default to any available value
86527
86528
86529             return propObj[langKeys[0]].value;
86530           }
86531
86532           wiki.entityIDs = function (val) {
86533             if (!arguments.length) return _entityIDs;
86534             _entityIDs = val;
86535             return wiki;
86536           };
86537
86538           wiki.focus = function () {
86539             _searchInput.node().focus();
86540           };
86541
86542           return utilRebind(wiki, dispatch$1, 'on');
86543         }
86544
86545         function uiFieldWikipedia(field, context) {
86546           var _arguments = arguments;
86547           var dispatch$1 = dispatch('change');
86548           var wikipedia = services.wikipedia;
86549           var wikidata = services.wikidata;
86550
86551           var _langInput = select(null);
86552
86553           var _titleInput = select(null);
86554
86555           var _wikiURL = '';
86556
86557           var _entityIDs;
86558
86559           var _tags;
86560
86561           var _dataWikipedia = [];
86562           _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
86563             _dataWikipedia = d;
86564             if (_tags) updateForTags(_tags);
86565           })["catch"](function () {
86566             /* ignore */
86567           });
86568           var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
86569             var v = value.toLowerCase();
86570             callback(_dataWikipedia.filter(function (d) {
86571               return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
86572             }).map(function (d) {
86573               return {
86574                 value: d[1]
86575               };
86576             }));
86577           });
86578           var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
86579             if (!value) {
86580               value = '';
86581
86582               for (var i in _entityIDs) {
86583                 var entity = context.hasEntity(_entityIDs[i]);
86584
86585                 if (entity.tags.name) {
86586                   value = entity.tags.name;
86587                   break;
86588                 }
86589               }
86590             }
86591
86592             var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
86593             searchfn(language()[2], value, function (query, data) {
86594               callback(data.map(function (d) {
86595                 return {
86596                   value: d
86597                 };
86598               }));
86599             });
86600           });
86601
86602           function wiki(selection) {
86603             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86604             wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
86605             var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
86606             langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
86607             _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
86608             _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);
86609
86610             _langInput.on('blur', changeLang).on('change', changeLang);
86611
86612             var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
86613             titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
86614             _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
86615             _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
86616
86617             _titleInput.on('blur', function () {
86618               change(true);
86619             }).on('change', function () {
86620               change(false);
86621             });
86622
86623             var link = titleContainer.selectAll('.wiki-link').data([0]);
86624             link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
86625               domain: 'wikipedia.org'
86626             })).call(svgIcon('#iD-icon-out-link')).merge(link);
86627             link.on('click', function (d3_event) {
86628               d3_event.preventDefault();
86629               if (_wikiURL) window.open(_wikiURL, '_blank');
86630             });
86631           }
86632
86633           function defaultLanguageInfo(skipEnglishFallback) {
86634             var langCode = _mainLocalizer.languageCode().toLowerCase();
86635
86636             for (var i in _dataWikipedia) {
86637               var d = _dataWikipedia[i]; // default to the language of iD's current locale
86638
86639               if (d[2] === langCode) return d;
86640             } // fallback to English
86641
86642
86643             return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
86644           }
86645
86646           function language(skipEnglishFallback) {
86647             var value = utilGetSetValue(_langInput).toLowerCase();
86648
86649             for (var i in _dataWikipedia) {
86650               var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
86651
86652               if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
86653             } // fallback to English
86654
86655
86656             return defaultLanguageInfo(skipEnglishFallback);
86657           }
86658
86659           function changeLang() {
86660             utilGetSetValue(_langInput, language()[1]);
86661             change(true);
86662           }
86663
86664           function change(skipWikidata) {
86665             var value = utilGetSetValue(_titleInput);
86666             var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
86667
86668             var langInfo = m && _dataWikipedia.find(function (d) {
86669               return m[1] === d[2];
86670             });
86671
86672             var syncTags = {};
86673
86674             if (langInfo) {
86675               var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
86676
86677               value = decodeURIComponent(m[2]).replace(/_/g, ' ');
86678
86679               if (m[3]) {
86680                 var anchor; // try {
86681                 // leave this out for now - #6232
86682                 // Best-effort `anchordecode:` implementation
86683                 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
86684                 // } catch (e) {
86685
86686                 anchor = decodeURIComponent(m[3]); // }
86687
86688                 value += '#' + anchor.replace(/_/g, ' ');
86689               }
86690
86691               value = value.slice(0, 1).toUpperCase() + value.slice(1);
86692               utilGetSetValue(_langInput, nativeLangName);
86693               utilGetSetValue(_titleInput, value);
86694             }
86695
86696             if (value) {
86697               syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
86698             } else {
86699               syncTags.wikipedia = undefined;
86700             }
86701
86702             dispatch$1.call('change', this, syncTags);
86703             if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
86704
86705             var initGraph = context.graph();
86706             var initEntityIDs = _entityIDs;
86707             wikidata.itemsByTitle(language()[2], value, function (err, data) {
86708               if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
86709
86710               if (context.graph() !== initGraph) return;
86711               var qids = Object.keys(data);
86712               var value = qids && qids.find(function (id) {
86713                 return id.match(/^Q\d+$/);
86714               });
86715               var actions = initEntityIDs.map(function (entityID) {
86716                 var entity = context.entity(entityID).tags;
86717                 var currTags = Object.assign({}, entity); // shallow copy
86718
86719                 if (currTags.wikidata !== value) {
86720                   currTags.wikidata = value;
86721                   return actionChangeTags(entityID, currTags);
86722                 }
86723
86724                 return null;
86725               }).filter(Boolean);
86726               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
86727
86728               context.overwrite(function actionUpdateWikidataTags(graph) {
86729                 actions.forEach(function (action) {
86730                   graph = action(graph);
86731                 });
86732                 return graph;
86733               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
86734               // changeTags() is not intended to be called asynchronously
86735             });
86736           }
86737
86738           wiki.tags = function (tags) {
86739             _tags = tags;
86740             updateForTags(tags);
86741           };
86742
86743           function updateForTags(tags) {
86744             var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
86745             // optional suffix of `#anchor`
86746
86747             var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
86748             var tagLang = m && m[1];
86749             var tagArticleTitle = m && m[2];
86750             var anchor = m && m[3];
86751
86752             var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
86753               return tagLang === d[2];
86754             }); // value in correct format
86755
86756
86757             if (tagLangInfo) {
86758               var nativeLangName = tagLangInfo[1];
86759               utilGetSetValue(_langInput, nativeLangName);
86760               utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
86761
86762               if (anchor) {
86763                 try {
86764                   // Best-effort `anchorencode:` implementation
86765                   anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
86766                 } catch (e) {
86767                   anchor = anchor.replace(/ /g, '_');
86768                 }
86769               }
86770
86771               _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
86772             } else {
86773               utilGetSetValue(_titleInput, value);
86774
86775               if (value && value !== '') {
86776                 utilGetSetValue(_langInput, '');
86777                 var defaultLangInfo = defaultLanguageInfo();
86778                 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
86779               } else {
86780                 var shownOrDefaultLangInfo = language(true
86781                 /* skipEnglishFallback */
86782                 );
86783                 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
86784                 _wikiURL = '';
86785               }
86786             }
86787           }
86788
86789           wiki.entityIDs = function (val) {
86790             if (!_arguments.length) return _entityIDs;
86791             _entityIDs = val;
86792             return wiki;
86793           };
86794
86795           wiki.focus = function () {
86796             _titleInput.node().focus();
86797           };
86798
86799           return utilRebind(wiki, dispatch$1, 'on');
86800         }
86801         uiFieldWikipedia.supportsMultiselection = false;
86802
86803         var uiFields = {
86804           access: uiFieldAccess,
86805           address: uiFieldAddress,
86806           check: uiFieldCheck,
86807           combo: uiFieldCombo,
86808           cycleway: uiFieldCycleway,
86809           defaultCheck: uiFieldCheck,
86810           email: uiFieldText,
86811           identifier: uiFieldText,
86812           lanes: uiFieldLanes,
86813           localized: uiFieldLocalized,
86814           maxspeed: uiFieldMaxspeed,
86815           manyCombo: uiFieldCombo,
86816           multiCombo: uiFieldCombo,
86817           networkCombo: uiFieldCombo,
86818           number: uiFieldText,
86819           onewayCheck: uiFieldCheck,
86820           radio: uiFieldRadio,
86821           restrictions: uiFieldRestrictions,
86822           semiCombo: uiFieldCombo,
86823           structureRadio: uiFieldRadio,
86824           tel: uiFieldText,
86825           text: uiFieldText,
86826           textarea: uiFieldTextarea,
86827           typeCombo: uiFieldCombo,
86828           url: uiFieldText,
86829           wikidata: uiFieldWikidata,
86830           wikipedia: uiFieldWikipedia
86831         };
86832
86833         function uiField(context, presetField, entityIDs, options) {
86834           options = Object.assign({
86835             show: true,
86836             wrap: true,
86837             remove: true,
86838             revert: true,
86839             info: true
86840           }, options);
86841           var dispatch$1 = dispatch('change', 'revert');
86842           var field = Object.assign({}, presetField); // shallow copy
86843
86844           field.domId = utilUniqueDomId('form-field-' + field.safeid);
86845           var _show = options.show;
86846           var _state = '';
86847           var _tags = {};
86848           var _locked = false;
86849
86850           var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
86851             label: field.label
86852           })).placement('bottom');
86853
86854           field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
86855
86856           if (_show && !field.impl) {
86857             createField();
86858           } // Creates the field.. This is done lazily,
86859           // once we know that the field will be shown.
86860
86861
86862           function createField() {
86863             field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
86864               dispatch$1.call('change', field, t, onInput);
86865             });
86866
86867             if (entityIDs) {
86868               field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
86869
86870               if (field.impl.entityIDs) {
86871                 field.impl.entityIDs(entityIDs);
86872               }
86873             }
86874           }
86875
86876           function isModified() {
86877             if (!entityIDs || !entityIDs.length) return false;
86878             return entityIDs.some(function (entityID) {
86879               var original = context.graph().base().entities[entityID];
86880               var latest = context.graph().entity(entityID);
86881               return field.keys.some(function (key) {
86882                 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
86883               });
86884             });
86885           }
86886
86887           function tagsContainFieldKey() {
86888             return field.keys.some(function (key) {
86889               if (field.type === 'multiCombo') {
86890                 for (var tagKey in _tags) {
86891                   if (tagKey.indexOf(key) === 0) {
86892                     return true;
86893                   }
86894                 }
86895
86896                 return false;
86897               }
86898
86899               return _tags[key] !== undefined;
86900             });
86901           }
86902
86903           function revert(d3_event, d) {
86904             d3_event.stopPropagation();
86905             d3_event.preventDefault();
86906             if (!entityIDs || _locked) return;
86907             dispatch$1.call('revert', d, d.keys);
86908           }
86909
86910           function remove(d3_event, d) {
86911             d3_event.stopPropagation();
86912             d3_event.preventDefault();
86913             if (_locked) return;
86914             var t = {};
86915             d.keys.forEach(function (key) {
86916               t[key] = undefined;
86917             });
86918             dispatch$1.call('change', d, t);
86919           }
86920
86921           field.render = function (selection) {
86922             var container = selection.selectAll('.form-field').data([field]); // Enter
86923
86924             var enter = container.enter().append('div').attr('class', function (d) {
86925               return 'form-field form-field-' + d.safeid;
86926             }).classed('nowrap', !options.wrap);
86927
86928             if (options.wrap) {
86929               var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
86930                 return d.domId;
86931               });
86932               var textEnter = labelEnter.append('span').attr('class', 'label-text');
86933               textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
86934                 return d.label();
86935               });
86936               textEnter.append('span').attr('class', 'label-textannotation');
86937
86938               if (options.remove) {
86939                 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
86940               }
86941
86942               if (options.revert) {
86943                 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
86944               }
86945             } // Update
86946
86947
86948             container = container.merge(enter);
86949             container.select('.field-label > .remove-icon') // propagate bound data
86950             .on('click', remove);
86951             container.select('.field-label > .modified-icon') // propagate bound data
86952             .on('click', revert);
86953             container.each(function (d) {
86954               var selection = select(this);
86955
86956               if (!d.impl) {
86957                 createField();
86958               }
86959
86960               var reference, help; // instantiate field help
86961
86962               if (options.wrap && field.type === 'restrictions') {
86963                 help = uiFieldHelp(context, 'restrictions');
86964               } // instantiate tag reference
86965
86966
86967               if (options.wrap && options.info) {
86968                 var referenceKey = d.key || '';
86969
86970                 if (d.type === 'multiCombo') {
86971                   // lookup key without the trailing ':'
86972                   referenceKey = referenceKey.replace(/:$/, '');
86973                 }
86974
86975                 reference = uiTagReference(d.reference || {
86976                   key: referenceKey
86977                 });
86978
86979                 if (_state === 'hover') {
86980                   reference.showing(false);
86981                 }
86982               }
86983
86984               selection.call(d.impl); // add field help components
86985
86986               if (help) {
86987                 selection.call(help.body).select('.field-label').call(help.button);
86988               } // add tag reference components
86989
86990
86991               if (reference) {
86992                 selection.call(reference.body).select('.field-label').call(reference.button);
86993               }
86994
86995               d.impl.tags(_tags);
86996             });
86997             container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
86998
86999             var annotation = container.selectAll('.field-label .label-textannotation');
87000             var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
87001             icon.exit().remove();
87002             icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
87003             container.call(_locked ? _lockedTip : _lockedTip.destroy);
87004           };
87005
87006           field.state = function (val) {
87007             if (!arguments.length) return _state;
87008             _state = val;
87009             return field;
87010           };
87011
87012           field.tags = function (val) {
87013             if (!arguments.length) return _tags;
87014             _tags = val;
87015
87016             if (tagsContainFieldKey() && !_show) {
87017               // always show a field if it has a value to display
87018               _show = true;
87019
87020               if (!field.impl) {
87021                 createField();
87022               }
87023             }
87024
87025             return field;
87026           };
87027
87028           field.locked = function (val) {
87029             if (!arguments.length) return _locked;
87030             _locked = val;
87031             return field;
87032           };
87033
87034           field.show = function () {
87035             _show = true;
87036
87037             if (!field.impl) {
87038               createField();
87039             }
87040
87041             if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
87042               var t = {};
87043               t[field.key] = field["default"];
87044               dispatch$1.call('change', this, t);
87045             }
87046           }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
87047
87048
87049           field.isShown = function () {
87050             return _show;
87051           }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
87052           // A non-allowed field is hidden from the user altogether
87053
87054
87055           field.isAllowed = function () {
87056             if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
87057             if (field.geometry && !entityIDs.every(function (entityID) {
87058               return field.matchGeometry(context.graph().geometry(entityID));
87059             })) return false;
87060
87061             if (field.countryCodes || field.notCountryCodes) {
87062               var extent = combinedEntityExtent();
87063               if (!extent) return true;
87064               var center = extent.center();
87065               var countryCode = iso1A2Code(center);
87066               if (!countryCode) return false;
87067               countryCode = countryCode.toLowerCase();
87068
87069               if (field.countryCodes && field.countryCodes.indexOf(countryCode) === -1) {
87070                 return false;
87071               }
87072
87073               if (field.notCountryCodes && field.notCountryCodes.indexOf(countryCode) !== -1) {
87074                 return false;
87075               }
87076             }
87077
87078             var prerequisiteTag = field.prerequisiteTag;
87079
87080             if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
87081             prerequisiteTag) {
87082               if (!entityIDs.every(function (entityID) {
87083                 var entity = context.graph().entity(entityID);
87084
87085                 if (prerequisiteTag.key) {
87086                   var value = entity.tags[prerequisiteTag.key];
87087                   if (!value) return false;
87088
87089                   if (prerequisiteTag.valueNot) {
87090                     return prerequisiteTag.valueNot !== value;
87091                   }
87092
87093                   if (prerequisiteTag.value) {
87094                     return prerequisiteTag.value === value;
87095                   }
87096                 } else if (prerequisiteTag.keyNot) {
87097                   if (entity.tags[prerequisiteTag.keyNot]) return false;
87098                 }
87099
87100                 return true;
87101               })) return false;
87102             }
87103
87104             return true;
87105           };
87106
87107           field.focus = function () {
87108             if (field.impl) {
87109               field.impl.focus();
87110             }
87111           };
87112
87113           function combinedEntityExtent() {
87114             return entityIDs && entityIDs.length && entityIDs.reduce(function (extent, entityID) {
87115               var entity = context.graph().entity(entityID);
87116               return extent.extend(entity.extent(context.graph()));
87117             }, geoExtent());
87118           }
87119
87120           return utilRebind(field, dispatch$1, 'on');
87121         }
87122
87123         function uiFormFields(context) {
87124           var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
87125           var _fieldsArr = [];
87126           var _lastPlaceholder = '';
87127           var _state = '';
87128           var _klass = '';
87129
87130           function formFields(selection) {
87131             var allowedFields = _fieldsArr.filter(function (field) {
87132               return field.isAllowed();
87133             });
87134
87135             var shown = allowedFields.filter(function (field) {
87136               return field.isShown();
87137             });
87138             var notShown = allowedFields.filter(function (field) {
87139               return !field.isShown();
87140             });
87141             var container = selection.selectAll('.form-fields-container').data([0]);
87142             container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
87143             var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
87144               return d.id + (d.entityIDs ? d.entityIDs.join() : '');
87145             });
87146             fields.exit().remove(); // Enter
87147
87148             var enter = fields.enter().append('div').attr('class', function (d) {
87149               return 'wrap-form-field wrap-form-field-' + d.safeid;
87150             }); // Update
87151
87152             fields = fields.merge(enter);
87153             fields.order().each(function (d) {
87154               select(this).call(d.render);
87155             });
87156             var titles = [];
87157             var moreFields = notShown.map(function (field) {
87158               var title = field.title();
87159               titles.push(title);
87160               var terms = field.terms();
87161               if (field.key) terms.push(field.key);
87162               if (field.keys) terms = terms.concat(field.keys);
87163               return {
87164                 display: field.label(),
87165                 value: title,
87166                 title: title,
87167                 field: field,
87168                 terms: terms
87169               };
87170             });
87171             var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
87172             var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
87173             more.exit().remove();
87174             var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
87175             moreEnter.append('span').html(_t.html('inspector.add_fields'));
87176             more = moreEnter.merge(more);
87177             var input = more.selectAll('.value').data([0]);
87178             input.exit().remove();
87179             input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
87180             input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
87181               if (!d) return; // user entered something that was not matched
87182
87183               var field = d.field;
87184               field.show();
87185               selection.call(formFields); // rerender
87186
87187               field.focus();
87188             })); // avoid updating placeholder excessively (triggers style recalc)
87189
87190             if (_lastPlaceholder !== placeholder) {
87191               input.attr('placeholder', placeholder);
87192               _lastPlaceholder = placeholder;
87193             }
87194           }
87195
87196           formFields.fieldsArr = function (val) {
87197             if (!arguments.length) return _fieldsArr;
87198             _fieldsArr = val || [];
87199             return formFields;
87200           };
87201
87202           formFields.state = function (val) {
87203             if (!arguments.length) return _state;
87204             _state = val;
87205             return formFields;
87206           };
87207
87208           formFields.klass = function (val) {
87209             if (!arguments.length) return _klass;
87210             _klass = val;
87211             return formFields;
87212           };
87213
87214           return formFields;
87215         }
87216
87217         function uiSectionPresetFields(context) {
87218           var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
87219           var dispatch$1 = dispatch('change', 'revert');
87220           var formFields = uiFormFields(context);
87221
87222           var _state;
87223
87224           var _fieldsArr;
87225
87226           var _presets = [];
87227
87228           var _tags;
87229
87230           var _entityIDs;
87231
87232           function renderDisclosureContent(selection) {
87233             if (!_fieldsArr) {
87234               var graph = context.graph();
87235               var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
87236                 geoms[graph.entity(entityID).geometry(graph)] = true;
87237                 return geoms;
87238               }, {}));
87239               var presetsManager = _mainPresetIndex;
87240               var allFields = [];
87241               var allMoreFields = [];
87242               var sharedTotalFields;
87243
87244               _presets.forEach(function (preset) {
87245                 var fields = preset.fields();
87246                 var moreFields = preset.moreFields();
87247                 allFields = utilArrayUnion(allFields, fields);
87248                 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
87249
87250                 if (!sharedTotalFields) {
87251                   sharedTotalFields = utilArrayUnion(fields, moreFields);
87252                 } else {
87253                   sharedTotalFields = sharedTotalFields.filter(function (field) {
87254                     return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
87255                   });
87256                 }
87257               });
87258
87259               var sharedFields = allFields.filter(function (field) {
87260                 return sharedTotalFields.indexOf(field) !== -1;
87261               });
87262               var sharedMoreFields = allMoreFields.filter(function (field) {
87263                 return sharedTotalFields.indexOf(field) !== -1;
87264               });
87265               _fieldsArr = [];
87266               sharedFields.forEach(function (field) {
87267                 if (field.matchAllGeometry(geometries)) {
87268                   _fieldsArr.push(uiField(context, field, _entityIDs));
87269                 }
87270               });
87271               var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
87272
87273               if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
87274                 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
87275               }
87276
87277               var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
87278               additionalFields.sort(function (field1, field2) {
87279                 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
87280               });
87281               additionalFields.forEach(function (field) {
87282                 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
87283                   _fieldsArr.push(uiField(context, field, _entityIDs, {
87284                     show: false
87285                   }));
87286                 }
87287               });
87288
87289               _fieldsArr.forEach(function (field) {
87290                 field.on('change', function (t, onInput) {
87291                   dispatch$1.call('change', field, _entityIDs, t, onInput);
87292                 }).on('revert', function (keys) {
87293                   dispatch$1.call('revert', field, keys);
87294                 });
87295               });
87296             }
87297
87298             _fieldsArr.forEach(function (field) {
87299               field.state(_state).tags(_tags);
87300             });
87301
87302             selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
87303             selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
87304               // if user presses enter, and combobox is not active, accept edits..
87305               if (d3_event.keyCode === 13 && // ↩ Return
87306               context.container().select('.combobox').empty()) {
87307                 context.enter(modeBrowse(context));
87308               }
87309             });
87310           }
87311
87312           section.presets = function (val) {
87313             if (!arguments.length) return _presets;
87314
87315             if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
87316               _presets = val;
87317               _fieldsArr = null;
87318             }
87319
87320             return section;
87321           };
87322
87323           section.state = function (val) {
87324             if (!arguments.length) return _state;
87325             _state = val;
87326             return section;
87327           };
87328
87329           section.tags = function (val) {
87330             if (!arguments.length) return _tags;
87331             _tags = val; // Don't reset _fieldsArr here.
87332
87333             return section;
87334           };
87335
87336           section.entityIDs = function (val) {
87337             if (!arguments.length) return _entityIDs;
87338
87339             if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
87340               _entityIDs = val;
87341               _fieldsArr = null;
87342             }
87343
87344             return section;
87345           };
87346
87347           return utilRebind(section, dispatch$1, 'on');
87348         }
87349
87350         function uiSectionRawMemberEditor(context) {
87351           var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
87352             if (!_entityIDs || _entityIDs.length !== 1) return false;
87353             var entity = context.hasEntity(_entityIDs[0]);
87354             return entity && entity.type === 'relation';
87355           }).label(function () {
87356             var entity = context.hasEntity(_entityIDs[0]);
87357             if (!entity) return '';
87358             var gt = entity.members.length > _maxMembers ? '>' : '';
87359             var count = gt + entity.members.slice(0, _maxMembers).length;
87360             return _t('inspector.title_count', {
87361               title: _t.html('inspector.members'),
87362               count: count
87363             });
87364           }).disclosureContent(renderDisclosureContent);
87365           var taginfo = services.taginfo;
87366
87367           var _entityIDs;
87368
87369           var _maxMembers = 1000;
87370
87371           function downloadMember(d3_event, d) {
87372             d3_event.preventDefault(); // display the loading indicator
87373
87374             select(this.parentNode).classed('tag-reference-loading', true);
87375             context.loadEntity(d.id, function () {
87376               section.reRender();
87377             });
87378           }
87379
87380           function zoomToMember(d3_event, d) {
87381             d3_event.preventDefault();
87382             var entity = context.entity(d.id);
87383             context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
87384
87385             utilHighlightEntities([d.id], true, context);
87386           }
87387
87388           function selectMember(d3_event, d) {
87389             d3_event.preventDefault(); // remove the hover-highlight styling
87390
87391             utilHighlightEntities([d.id], false, context);
87392             var entity = context.entity(d.id);
87393             var mapExtent = context.map().extent();
87394
87395             if (!entity.intersects(mapExtent, context.graph())) {
87396               // zoom to the entity if its extent is not visible now
87397               context.map().zoomToEase(entity);
87398             }
87399
87400             context.enter(modeSelect(context, [d.id]));
87401           }
87402
87403           function changeRole(d3_event, d) {
87404             var oldRole = d.role;
87405             var newRole = context.cleanRelationRole(select(this).property('value'));
87406
87407             if (oldRole !== newRole) {
87408               var member = {
87409                 id: d.id,
87410                 type: d.type,
87411                 role: newRole
87412               };
87413               context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
87414                 n: 1
87415               }));
87416               context.validator().validate();
87417             }
87418           }
87419
87420           function deleteMember(d3_event, d) {
87421             // remove the hover-highlight styling
87422             utilHighlightEntities([d.id], false, context);
87423             context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
87424               n: 1
87425             }));
87426
87427             if (!context.hasEntity(d.relation.id)) {
87428               // Removing the last member will also delete the relation.
87429               // If this happens we need to exit the selection mode
87430               context.enter(modeBrowse(context));
87431             } else {
87432               // Changing the mode also runs `validate`, but otherwise we need to
87433               // rerun it manually
87434               context.validator().validate();
87435             }
87436           }
87437
87438           function renderDisclosureContent(selection) {
87439             var entityID = _entityIDs[0];
87440             var memberships = [];
87441             var entity = context.entity(entityID);
87442             entity.members.slice(0, _maxMembers).forEach(function (member, index) {
87443               memberships.push({
87444                 index: index,
87445                 id: member.id,
87446                 type: member.type,
87447                 role: member.role,
87448                 relation: entity,
87449                 member: context.hasEntity(member.id),
87450                 domId: utilUniqueDomId(entityID + '-member-' + index)
87451               });
87452             });
87453             var list = selection.selectAll('.member-list').data([0]);
87454             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
87455             var items = list.selectAll('li').data(memberships, function (d) {
87456               return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
87457             });
87458             items.exit().each(unbind).remove();
87459             var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
87460               return !d.member;
87461             });
87462             itemsEnter.each(function (d) {
87463               var item = select(this);
87464               var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
87465
87466               if (d.member) {
87467                 // highlight the member feature in the map while hovering on the list item
87468                 item.on('mouseover', function () {
87469                   utilHighlightEntities([d.id], true, context);
87470                 }).on('mouseout', function () {
87471                   utilHighlightEntities([d.id], false, context);
87472                 });
87473                 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
87474                 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
87475                   var matched = _mainPresetIndex.match(d.member, context.graph());
87476                   return matched && matched.name() || utilDisplayType(d.member.id);
87477                 });
87478                 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
87479                   return utilDisplayName(d.member);
87480                 });
87481                 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
87482                 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
87483               } else {
87484                 var labelText = label.append('span').attr('class', 'label-text');
87485                 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
87486                   id: d.id
87487                 }));
87488                 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
87489                   id: d.id
87490                 }));
87491                 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
87492               }
87493             });
87494             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
87495             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
87496               return d.domId;
87497             }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
87498
87499             if (taginfo) {
87500               wrapEnter.each(bindTypeahead);
87501             } // update
87502
87503
87504             items = items.merge(itemsEnter).order();
87505             items.select('input.member-role').property('value', function (d) {
87506               return d.role;
87507             }).on('blur', changeRole).on('change', changeRole);
87508             items.select('button.member-delete').on('click', deleteMember);
87509             var dragOrigin, targetIndex;
87510             items.call(d3_drag().on('start', function (d3_event) {
87511               dragOrigin = {
87512                 x: d3_event.x,
87513                 y: d3_event.y
87514               };
87515               targetIndex = null;
87516             }).on('drag', function (d3_event) {
87517               var x = d3_event.x - dragOrigin.x,
87518                   y = d3_event.y - dragOrigin.y;
87519               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
87520               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
87521               var index = items.nodes().indexOf(this);
87522               select(this).classed('dragging', true);
87523               targetIndex = null;
87524               selection.selectAll('li.member-row').style('transform', function (d2, index2) {
87525                 var node = select(this).node();
87526
87527                 if (index === index2) {
87528                   return 'translate(' + x + 'px, ' + y + 'px)';
87529                 } else if (index2 > index && d3_event.y > node.offsetTop) {
87530                   if (targetIndex === null || index2 > targetIndex) {
87531                     targetIndex = index2;
87532                   }
87533
87534                   return 'translateY(-100%)';
87535                 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
87536                   if (targetIndex === null || index2 < targetIndex) {
87537                     targetIndex = index2;
87538                   }
87539
87540                   return 'translateY(100%)';
87541                 }
87542
87543                 return null;
87544               });
87545             }).on('end', function (d3_event, d) {
87546               if (!select(this).classed('dragging')) return;
87547               var index = items.nodes().indexOf(this);
87548               select(this).classed('dragging', false);
87549               selection.selectAll('li.member-row').style('transform', null);
87550
87551               if (targetIndex !== null) {
87552                 // dragged to a new position, reorder
87553                 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
87554                 context.validator().validate();
87555               }
87556             }));
87557
87558             function bindTypeahead(d) {
87559               var row = select(this);
87560               var role = row.selectAll('input.member-role');
87561               var origValue = role.property('value');
87562
87563               function sort(value, data) {
87564                 var sameletter = [];
87565                 var other = [];
87566
87567                 for (var i = 0; i < data.length; i++) {
87568                   if (data[i].value.substring(0, value.length) === value) {
87569                     sameletter.push(data[i]);
87570                   } else {
87571                     other.push(data[i]);
87572                   }
87573                 }
87574
87575                 return sameletter.concat(other);
87576               }
87577
87578               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
87579                 // The `geometry` param is used in the `taginfo.js` interface for
87580                 // filtering results, as a key into the `tag_members_fractions`
87581                 // object.  If we don't know the geometry because the member is
87582                 // not yet downloaded, it's ok to guess based on type.
87583                 var geometry;
87584
87585                 if (d.member) {
87586                   geometry = context.graph().geometry(d.member.id);
87587                 } else if (d.type === 'relation') {
87588                   geometry = 'relation';
87589                 } else if (d.type === 'way') {
87590                   geometry = 'line';
87591                 } else {
87592                   geometry = 'point';
87593                 }
87594
87595                 var rtype = entity.tags.type;
87596                 taginfo.roles({
87597                   debounce: true,
87598                   rtype: rtype || '',
87599                   geometry: geometry,
87600                   query: role
87601                 }, function (err, data) {
87602                   if (!err) callback(sort(role, data));
87603                 });
87604               }).on('cancel', function () {
87605                 role.property('value', origValue);
87606               }));
87607             }
87608
87609             function unbind() {
87610               var row = select(this);
87611               row.selectAll('input.member-role').call(uiCombobox.off, context);
87612             }
87613           }
87614
87615           section.entityIDs = function (val) {
87616             if (!arguments.length) return _entityIDs;
87617             _entityIDs = val;
87618             return section;
87619           };
87620
87621           return section;
87622         }
87623
87624         function actionDeleteMembers(relationId, memberIndexes) {
87625           return function (graph) {
87626             // Remove the members in descending order so removals won't shift what members
87627             // are at the remaining indexes
87628             memberIndexes.sort(function (a, b) {
87629               return b - a;
87630             });
87631
87632             for (var i in memberIndexes) {
87633               graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
87634             }
87635
87636             return graph;
87637           };
87638         }
87639
87640         function uiSectionRawMembershipEditor(context) {
87641           var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
87642             return _entityIDs && _entityIDs.length;
87643           }).label(function () {
87644             var parents = getSharedParentRelations();
87645             var gt = parents.length > _maxMemberships ? '>' : '';
87646             var count = gt + parents.slice(0, _maxMemberships).length;
87647             return _t('inspector.title_count', {
87648               title: _t.html('inspector.relations'),
87649               count: count
87650             });
87651           }).disclosureContent(renderDisclosureContent);
87652           var taginfo = services.taginfo;
87653           var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
87654             if (d.relation) utilHighlightEntities([d.relation.id], true, context);
87655           }).itemsMouseLeave(function (d3_event, d) {
87656             if (d.relation) utilHighlightEntities([d.relation.id], false, context);
87657           });
87658           var _inChange = false;
87659           var _entityIDs = [];
87660
87661           var _showBlank;
87662
87663           var _maxMemberships = 1000;
87664
87665           function getSharedParentRelations() {
87666             var parents = [];
87667
87668             for (var i = 0; i < _entityIDs.length; i++) {
87669               var entity = context.graph().hasEntity(_entityIDs[i]);
87670               if (!entity) continue;
87671
87672               if (i === 0) {
87673                 parents = context.graph().parentRelations(entity);
87674               } else {
87675                 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
87676               }
87677
87678               if (!parents.length) break;
87679             }
87680
87681             return parents;
87682           }
87683
87684           function getMemberships() {
87685             var memberships = [];
87686             var relations = getSharedParentRelations().slice(0, _maxMemberships);
87687             var isMultiselect = _entityIDs.length > 1;
87688             var i, relation, membership, index, member, indexedMember;
87689
87690             for (i = 0; i < relations.length; i++) {
87691               relation = relations[i];
87692               membership = {
87693                 relation: relation,
87694                 members: [],
87695                 hash: osmEntity.key(relation)
87696               };
87697
87698               for (index = 0; index < relation.members.length; index++) {
87699                 member = relation.members[index];
87700
87701                 if (_entityIDs.indexOf(member.id) !== -1) {
87702                   indexedMember = Object.assign({}, member, {
87703                     index: index
87704                   });
87705                   membership.members.push(indexedMember);
87706                   membership.hash += ',' + index.toString();
87707
87708                   if (!isMultiselect) {
87709                     // For single selections, list one entry per membership per relation.
87710                     // For multiselections, list one entry per relation.
87711                     memberships.push(membership);
87712                     membership = {
87713                       relation: relation,
87714                       members: [],
87715                       hash: osmEntity.key(relation)
87716                     };
87717                   }
87718                 }
87719               }
87720
87721               if (membership.members.length) memberships.push(membership);
87722             }
87723
87724             memberships.forEach(function (membership) {
87725               membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
87726               var roles = [];
87727               membership.members.forEach(function (member) {
87728                 if (roles.indexOf(member.role) === -1) roles.push(member.role);
87729               });
87730               membership.role = roles.length === 1 ? roles[0] : roles;
87731             });
87732             return memberships;
87733           }
87734
87735           function selectRelation(d3_event, d) {
87736             d3_event.preventDefault(); // remove the hover-highlight styling
87737
87738             utilHighlightEntities([d.relation.id], false, context);
87739             context.enter(modeSelect(context, [d.relation.id]));
87740           }
87741
87742           function zoomToRelation(d3_event, d) {
87743             d3_event.preventDefault();
87744             var entity = context.entity(d.relation.id);
87745             context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
87746
87747             utilHighlightEntities([d.relation.id], true, context);
87748           }
87749
87750           function changeRole(d3_event, d) {
87751             if (d === 0) return; // called on newrow (shouldn't happen)
87752
87753             if (_inChange) return; // avoid accidental recursive call #5731
87754
87755             var newRole = context.cleanRelationRole(select(this).property('value'));
87756             if (!newRole.trim() && typeof d.role !== 'string') return;
87757             var membersToUpdate = d.members.filter(function (member) {
87758               return member.role !== newRole;
87759             });
87760
87761             if (membersToUpdate.length) {
87762               _inChange = true;
87763               context.perform(function actionChangeMemberRoles(graph) {
87764                 membersToUpdate.forEach(function (member) {
87765                   var newMember = Object.assign({}, member, {
87766                     role: newRole
87767                   });
87768                   delete newMember.index;
87769                   graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
87770                 });
87771                 return graph;
87772               }, _t('operations.change_role.annotation', {
87773                 n: membersToUpdate.length
87774               }));
87775               context.validator().validate();
87776             }
87777
87778             _inChange = false;
87779           }
87780
87781           function addMembership(d, role) {
87782             this.blur(); // avoid keeping focus on the button
87783
87784             _showBlank = false;
87785
87786             function actionAddMembers(relationId, ids, role) {
87787               return function (graph) {
87788                 for (var i in ids) {
87789                   var member = {
87790                     id: ids[i],
87791                     type: graph.entity(ids[i]).type,
87792                     role: role
87793                   };
87794                   graph = actionAddMember(relationId, member)(graph);
87795                 }
87796
87797                 return graph;
87798               };
87799             }
87800
87801             if (d.relation) {
87802               context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
87803                 n: _entityIDs.length
87804               }));
87805               context.validator().validate();
87806             } else {
87807               var relation = osmRelation();
87808               context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
87809
87810               context.enter(modeSelect(context, [relation.id]).newFeature(true));
87811             }
87812           }
87813
87814           function deleteMembership(d3_event, d) {
87815             this.blur(); // avoid keeping focus on the button
87816
87817             if (d === 0) return; // called on newrow (shouldn't happen)
87818             // remove the hover-highlight styling
87819
87820             utilHighlightEntities([d.relation.id], false, context);
87821             var indexes = d.members.map(function (member) {
87822               return member.index;
87823             });
87824             context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
87825               n: _entityIDs.length
87826             }));
87827             context.validator().validate();
87828           }
87829
87830           function fetchNearbyRelations(q, callback) {
87831             var newRelation = {
87832               relation: null,
87833               value: _t('inspector.new_relation'),
87834               display: _t.html('inspector.new_relation')
87835             };
87836             var entityID = _entityIDs[0];
87837             var result = [];
87838             var graph = context.graph();
87839
87840             function baseDisplayLabel(entity) {
87841               var matched = _mainPresetIndex.match(entity, graph);
87842               var presetName = matched && matched.name() || _t('inspector.relation');
87843               var entityName = utilDisplayName(entity) || '';
87844               return presetName + ' ' + entityName;
87845             }
87846
87847             var explicitRelation = q && context.hasEntity(q.toLowerCase());
87848
87849             if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
87850               // loaded relation is specified explicitly, only show that
87851               result.push({
87852                 relation: explicitRelation,
87853                 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
87854               });
87855             } else {
87856               context.history().intersects(context.map().extent()).forEach(function (entity) {
87857                 if (entity.type !== 'relation' || entity.id === entityID) return;
87858                 var value = baseDisplayLabel(entity);
87859                 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
87860                 result.push({
87861                   relation: entity,
87862                   value: value
87863                 });
87864               });
87865               result.sort(function (a, b) {
87866                 return osmRelation.creationOrder(a.relation, b.relation);
87867               }); // Dedupe identical names by appending relation id - see #2891
87868
87869               var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
87870                 return v.length > 1;
87871               });
87872               dupeGroups.forEach(function (group) {
87873                 group.forEach(function (obj) {
87874                   obj.value += ' ' + obj.relation.id;
87875                 });
87876               });
87877             }
87878
87879             result.forEach(function (obj) {
87880               obj.title = obj.value;
87881             });
87882             result.unshift(newRelation);
87883             callback(result);
87884           }
87885
87886           function renderDisclosureContent(selection) {
87887             var memberships = getMemberships();
87888             var list = selection.selectAll('.member-list').data([0]);
87889             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
87890             var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
87891               return d.hash;
87892             });
87893             items.exit().each(unbind).remove(); // Enter
87894
87895             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
87896
87897             itemsEnter.on('mouseover', function (d3_event, d) {
87898               utilHighlightEntities([d.relation.id], true, context);
87899             }).on('mouseout', function (d3_event, d) {
87900               utilHighlightEntities([d.relation.id], false, context);
87901             });
87902             var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
87903               return d.domId;
87904             });
87905             var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
87906             labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
87907               var matched = _mainPresetIndex.match(d.relation, context.graph());
87908               return matched && matched.name() || _t('inspector.relation');
87909             });
87910             labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
87911               return utilDisplayName(d.relation);
87912             });
87913             labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
87914             labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
87915             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
87916             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
87917               return d.domId;
87918             }).property('type', 'text').property('value', function (d) {
87919               return typeof d.role === 'string' ? d.role : '';
87920             }).attr('title', function (d) {
87921               return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
87922             }).attr('placeholder', function (d) {
87923               return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
87924             }).classed('mixed', function (d) {
87925               return Array.isArray(d.role);
87926             }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
87927
87928             if (taginfo) {
87929               wrapEnter.each(bindTypeahead);
87930             }
87931
87932             var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
87933
87934             newMembership.exit().remove(); // Enter
87935
87936             var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
87937             var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
87938             newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
87939             newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
87940               list.selectAll('.member-row-new').remove();
87941             });
87942             var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
87943             newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
87944
87945             newMembership = newMembership.merge(newMembershipEnter);
87946             newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
87947             .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
87948
87949             var addRow = selection.selectAll('.add-row').data([0]); // enter
87950
87951             var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
87952             var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
87953             addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
87954             addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
87955             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
87956
87957             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
87958             // update
87959
87960             addRow = addRow.merge(addRowEnter);
87961             addRow.select('.add-relation').on('click', function () {
87962               _showBlank = true;
87963               section.reRender();
87964               list.selectAll('.member-entity-input').node().focus();
87965             });
87966
87967             function acceptEntity(d) {
87968               if (!d) {
87969                 cancelEntity();
87970                 return;
87971               } // remove hover-higlighting
87972
87973
87974               if (d.relation) utilHighlightEntities([d.relation.id], false, context);
87975               var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
87976               addMembership(d, role);
87977             }
87978
87979             function cancelEntity() {
87980               var input = newMembership.selectAll('.member-entity-input');
87981               input.property('value', ''); // remove hover-higlighting
87982
87983               context.surface().selectAll('.highlighted').classed('highlighted', false);
87984             }
87985
87986             function bindTypeahead(d) {
87987               var row = select(this);
87988               var role = row.selectAll('input.member-role');
87989               var origValue = role.property('value');
87990
87991               function sort(value, data) {
87992                 var sameletter = [];
87993                 var other = [];
87994
87995                 for (var i = 0; i < data.length; i++) {
87996                   if (data[i].value.substring(0, value.length) === value) {
87997                     sameletter.push(data[i]);
87998                   } else {
87999                     other.push(data[i]);
88000                   }
88001                 }
88002
88003                 return sameletter.concat(other);
88004               }
88005
88006               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88007                 var rtype = d.relation.tags.type;
88008                 taginfo.roles({
88009                   debounce: true,
88010                   rtype: rtype || '',
88011                   geometry: context.graph().geometry(_entityIDs[0]),
88012                   query: role
88013                 }, function (err, data) {
88014                   if (!err) callback(sort(role, data));
88015                 });
88016               }).on('cancel', function () {
88017                 role.property('value', origValue);
88018               }));
88019             }
88020
88021             function unbind() {
88022               var row = select(this);
88023               row.selectAll('input.member-role').call(uiCombobox.off, context);
88024             }
88025           }
88026
88027           section.entityIDs = function (val) {
88028             if (!arguments.length) return _entityIDs;
88029             _entityIDs = val;
88030             _showBlank = false;
88031             return section;
88032           };
88033
88034           return section;
88035         }
88036
88037         function uiSectionSelectionList(context) {
88038           var _selectedIDs = [];
88039           var section = uiSection('selected-features', context).shouldDisplay(function () {
88040             return _selectedIDs.length > 1;
88041           }).label(function () {
88042             return _t('inspector.title_count', {
88043               title: _t.html('inspector.features'),
88044               count: _selectedIDs.length
88045             });
88046           }).disclosureContent(renderDisclosureContent);
88047           context.history().on('change.selectionList', function (difference) {
88048             if (difference) {
88049               section.reRender();
88050             }
88051           });
88052
88053           section.entityIDs = function (val) {
88054             if (!arguments.length) return _selectedIDs;
88055             _selectedIDs = val;
88056             return section;
88057           };
88058
88059           function selectEntity(d3_event, entity) {
88060             context.enter(modeSelect(context, [entity.id]));
88061           }
88062
88063           function deselectEntity(d3_event, entity) {
88064             var selectedIDs = _selectedIDs.slice();
88065
88066             var index = selectedIDs.indexOf(entity.id);
88067
88068             if (index > -1) {
88069               selectedIDs.splice(index, 1);
88070               context.enter(modeSelect(context, selectedIDs));
88071             }
88072           }
88073
88074           function renderDisclosureContent(selection) {
88075             var list = selection.selectAll('.feature-list').data([0]);
88076             list = list.enter().append('ul').attr('class', 'feature-list').merge(list);
88077
88078             var entities = _selectedIDs.map(function (id) {
88079               return context.hasEntity(id);
88080             }).filter(Boolean);
88081
88082             var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
88083             items.exit().remove(); // Enter
88084
88085             var enter = items.enter().append('li').attr('class', 'feature-list-item').each(function (d) {
88086               select(this).on('mouseover', function () {
88087                 utilHighlightEntities([d.id], true, context);
88088               }).on('mouseout', function () {
88089                 utilHighlightEntities([d.id], false, context);
88090               });
88091             });
88092             var label = enter.append('button').attr('class', 'label').on('click', selectEntity);
88093             label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
88094             label.append('span').attr('class', 'entity-type');
88095             label.append('span').attr('class', 'entity-name');
88096             enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close')); // Update
88097
88098             items = items.merge(enter);
88099             items.selectAll('.entity-geom-icon use').attr('href', function () {
88100               var entity = this.parentNode.parentNode.__data__;
88101               return '#iD-icon-' + entity.geometry(context.graph());
88102             });
88103             items.selectAll('.entity-type').html(function (entity) {
88104               return _mainPresetIndex.match(entity, context.graph()).name();
88105             });
88106             items.selectAll('.entity-name').html(function (d) {
88107               // fetch latest entity
88108               var entity = context.entity(d.id);
88109               return utilDisplayName(entity);
88110             });
88111           }
88112
88113           return section;
88114         }
88115
88116         function uiEntityEditor(context) {
88117           var dispatch$1 = dispatch('choose');
88118           var _state = 'select';
88119           var _coalesceChanges = false;
88120           var _modified = false;
88121
88122           var _base;
88123
88124           var _entityIDs;
88125
88126           var _activePresets = [];
88127
88128           var _newFeature;
88129
88130           var _sections;
88131
88132           function entityEditor(selection) {
88133             var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
88134
88135             var header = selection.selectAll('.header').data([0]); // Enter
88136
88137             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
88138             headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
88139             headerEnter.append('button').attr('class', 'close').on('click', function () {
88140               context.enter(modeBrowse(context));
88141             }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
88142             headerEnter.append('h3'); // Update
88143
88144             header = header.merge(headerEnter);
88145             header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
88146             header.selectAll('.preset-reset').on('click', function () {
88147               dispatch$1.call('choose', this, _activePresets);
88148             }); // Body
88149
88150             var body = selection.selectAll('.inspector-body').data([0]); // Enter
88151
88152             var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
88153
88154             body = body.merge(bodyEnter);
88155
88156             if (!_sections) {
88157               _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
88158                 dispatch$1.call('choose', this, presets);
88159               }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
88160             }
88161
88162             _sections.forEach(function (section) {
88163               if (section.entityIDs) {
88164                 section.entityIDs(_entityIDs);
88165               }
88166
88167               if (section.presets) {
88168                 section.presets(_activePresets);
88169               }
88170
88171               if (section.tags) {
88172                 section.tags(combinedTags);
88173               }
88174
88175               if (section.state) {
88176                 section.state(_state);
88177               }
88178
88179               body.call(section.render);
88180             });
88181
88182             context.history().on('change.entity-editor', historyChanged);
88183
88184             function historyChanged(difference) {
88185               if (selection.selectAll('.entity-editor').empty()) return;
88186               if (_state === 'hide') return;
88187               var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
88188               if (!significant) return;
88189               _entityIDs = _entityIDs.filter(context.hasEntity);
88190               if (!_entityIDs.length) return;
88191               var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
88192               loadActivePresets();
88193               var graph = context.graph();
88194               entityEditor.modified(_base !== graph);
88195               entityEditor(selection);
88196
88197               if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
88198                 // flash the button to indicate the preset changed
88199                 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
88200               }
88201             }
88202           } // Tag changes that fire on input can all get coalesced into a single
88203           // history operation when the user leaves the field.  #2342
88204           // Use explicit entityIDs in case the selection changes before the event is fired.
88205
88206
88207           function changeTags(entityIDs, changed, onInput) {
88208             var actions = [];
88209
88210             for (var i in entityIDs) {
88211               var entityID = entityIDs[i];
88212               var entity = context.entity(entityID);
88213               var tags = Object.assign({}, entity.tags); // shallow copy
88214
88215               for (var k in changed) {
88216                 if (!k) continue;
88217                 var v = changed[k];
88218
88219                 if (v !== undefined || tags.hasOwnProperty(k)) {
88220                   tags[k] = v;
88221                 }
88222               }
88223
88224               if (!onInput) {
88225                 tags = utilCleanTags(tags);
88226               }
88227
88228               if (!fastDeepEqual(entity.tags, tags)) {
88229                 actions.push(actionChangeTags(entityID, tags));
88230               }
88231             }
88232
88233             if (actions.length) {
88234               var combinedAction = function combinedAction(graph) {
88235                 actions.forEach(function (action) {
88236                   graph = action(graph);
88237                 });
88238                 return graph;
88239               };
88240
88241               var annotation = _t('operations.change_tags.annotation');
88242
88243               if (_coalesceChanges) {
88244                 context.overwrite(combinedAction, annotation);
88245               } else {
88246                 context.perform(combinedAction, annotation);
88247                 _coalesceChanges = !!onInput;
88248               }
88249             } // if leaving field (blur event), rerun validation
88250
88251
88252             if (!onInput) {
88253               context.validator().validate();
88254             }
88255           }
88256
88257           function revertTags(keys) {
88258             var actions = [];
88259
88260             for (var i in _entityIDs) {
88261               var entityID = _entityIDs[i];
88262               var original = context.graph().base().entities[entityID];
88263               var changed = {};
88264
88265               for (var j in keys) {
88266                 var key = keys[j];
88267                 changed[key] = original ? original.tags[key] : undefined;
88268               }
88269
88270               var entity = context.entity(entityID);
88271               var tags = Object.assign({}, entity.tags); // shallow copy
88272
88273               for (var k in changed) {
88274                 if (!k) continue;
88275                 var v = changed[k];
88276
88277                 if (v !== undefined || tags.hasOwnProperty(k)) {
88278                   tags[k] = v;
88279                 }
88280               }
88281
88282               tags = utilCleanTags(tags);
88283
88284               if (!fastDeepEqual(entity.tags, tags)) {
88285                 actions.push(actionChangeTags(entityID, tags));
88286               }
88287             }
88288
88289             if (actions.length) {
88290               var combinedAction = function combinedAction(graph) {
88291                 actions.forEach(function (action) {
88292                   graph = action(graph);
88293                 });
88294                 return graph;
88295               };
88296
88297               var annotation = _t('operations.change_tags.annotation');
88298
88299               if (_coalesceChanges) {
88300                 context.overwrite(combinedAction, annotation);
88301               } else {
88302                 context.perform(combinedAction, annotation);
88303                 _coalesceChanges = false;
88304               }
88305             }
88306
88307             context.validator().validate();
88308           }
88309
88310           entityEditor.modified = function (val) {
88311             if (!arguments.length) return _modified;
88312             _modified = val;
88313             return entityEditor;
88314           };
88315
88316           entityEditor.state = function (val) {
88317             if (!arguments.length) return _state;
88318             _state = val;
88319             return entityEditor;
88320           };
88321
88322           entityEditor.entityIDs = function (val) {
88323             if (!arguments.length) return _entityIDs; // always reload these even if the entityIDs are unchanged, since we
88324             // could be reselecting after something like dragging a node
88325
88326             _base = context.graph();
88327             _coalesceChanges = false;
88328             if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
88329
88330             _entityIDs = val;
88331             loadActivePresets(true);
88332             return entityEditor.modified(false);
88333           };
88334
88335           entityEditor.newFeature = function (val) {
88336             if (!arguments.length) return _newFeature;
88337             _newFeature = val;
88338             return entityEditor;
88339           };
88340
88341           function loadActivePresets(isForNewSelection) {
88342             var graph = context.graph();
88343             var counts = {};
88344
88345             for (var i in _entityIDs) {
88346               var entity = graph.hasEntity(_entityIDs[i]);
88347               if (!entity) return;
88348               var match = _mainPresetIndex.match(entity, graph);
88349               if (!counts[match.id]) counts[match.id] = 0;
88350               counts[match.id] += 1;
88351             }
88352
88353             var matches = Object.keys(counts).sort(function (p1, p2) {
88354               return counts[p2] - counts[p1];
88355             }).map(function (pID) {
88356               return _mainPresetIndex.item(pID);
88357             });
88358
88359             if (!isForNewSelection) {
88360               // A "weak" preset doesn't set any tags. (e.g. "Address")
88361               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")
88362
88363               if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
88364             }
88365
88366             entityEditor.presets(matches);
88367           }
88368
88369           entityEditor.presets = function (val) {
88370             if (!arguments.length) return _activePresets; // don't reload the same preset
88371
88372             if (!utilArrayIdentical(val, _activePresets)) {
88373               _activePresets = val;
88374             }
88375
88376             return entityEditor;
88377           };
88378
88379           return utilRebind(entityEditor, dispatch$1, 'on');
88380         }
88381
88382         function uiPresetList(context) {
88383           var dispatch$1 = dispatch('cancel', 'choose');
88384
88385           var _entityIDs;
88386
88387           var _currentPresets;
88388
88389           var _autofocus = false;
88390
88391           function presetList(selection) {
88392             if (!_entityIDs) return;
88393             var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
88394             selection.html('');
88395             var messagewrap = selection.append('div').attr('class', 'header fillL');
88396             var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
88397             messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
88398               dispatch$1.call('cancel', this);
88399             }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
88400
88401             function initialKeydown(d3_event) {
88402               // hack to let delete shortcut work when search is autofocused
88403               if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
88404                 d3_event.preventDefault();
88405                 d3_event.stopPropagation();
88406                 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
88407               } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
88408                 d3_event.preventDefault();
88409                 d3_event.stopPropagation();
88410                 context.undo();
88411               } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
88412                 // don't check for delete/undo hack on future keydown events
88413                 select(this).on('keydown', keydown);
88414                 keydown.call(this, d3_event);
88415               }
88416             }
88417
88418             function keydown(d3_event) {
88419               // down arrow
88420               if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
88421               search.node().selectionStart === search.property('value').length) {
88422                 d3_event.preventDefault();
88423                 d3_event.stopPropagation(); // move focus to the first item in the preset list
88424
88425                 var buttons = list.selectAll('.preset-list-button');
88426                 if (!buttons.empty()) buttons.nodes()[0].focus();
88427               }
88428             }
88429
88430             function keypress(d3_event) {
88431               // enter
88432               var value = search.property('value');
88433
88434               if (d3_event.keyCode === 13 && // ↩ Return
88435               value.length) {
88436                 list.selectAll('.preset-list-item:first-child').each(function (d) {
88437                   d.choose.call(this);
88438                 });
88439               }
88440             }
88441
88442             function inputevent() {
88443               var value = search.property('value');
88444               list.classed('filtered', value.length);
88445               var extent = combinedEntityExtent();
88446               var results, messageText;
88447
88448               if (value.length && extent) {
88449                 var center = extent.center();
88450                 var countryCode = iso1A2Code(center);
88451                 results = presets.search(value, entityGeometries()[0], countryCode && countryCode.toLowerCase());
88452                 messageText = _t('inspector.results', {
88453                   n: results.collection.length,
88454                   search: value
88455                 });
88456               } else {
88457                 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro());
88458                 messageText = _t('inspector.choose');
88459               }
88460
88461               list.call(drawList, results);
88462               message.html(messageText);
88463             }
88464
88465             var searchWrap = selection.append('div').attr('class', 'search-header');
88466             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
88467             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);
88468
88469             if (_autofocus) {
88470               search.node().focus(); // Safari 14 doesn't always like to focus immediately,
88471               // so try again on the next pass
88472
88473               setTimeout(function () {
88474                 search.node().focus();
88475               }, 0);
88476             }
88477
88478             var listWrap = selection.append('div').attr('class', 'inspector-body');
88479             var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro()));
88480             context.features().on('change.preset-list', updateForFeatureHiddenState);
88481           }
88482
88483           function drawList(list, presets) {
88484             presets = presets.matchAllGeometry(entityGeometries());
88485             var collection = presets.collection.reduce(function (collection, preset) {
88486               if (!preset) return collection;
88487
88488               if (preset.members) {
88489                 if (preset.members.collection.filter(function (preset) {
88490                   return preset.addable();
88491                 }).length > 1) {
88492                   collection.push(CategoryItem(preset));
88493                 }
88494               } else if (preset.addable()) {
88495                 collection.push(PresetItem(preset));
88496               }
88497
88498               return collection;
88499             }, []);
88500             var items = list.selectAll('.preset-list-item').data(collection, function (d) {
88501               return d.preset.id;
88502             });
88503             items.order();
88504             items.exit().remove();
88505             items.enter().append('div').attr('class', function (item) {
88506               return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
88507             }).classed('current', function (item) {
88508               return _currentPresets.indexOf(item.preset) !== -1;
88509             }).each(function (item) {
88510               select(this).call(item);
88511             }).style('opacity', 0).transition().style('opacity', 1);
88512             updateForFeatureHiddenState();
88513           }
88514
88515           function itemKeydown(d3_event) {
88516             // the actively focused item
88517             var item = select(this.closest('.preset-list-item'));
88518             var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
88519
88520             if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
88521               d3_event.preventDefault();
88522               d3_event.stopPropagation(); // the next item in the list at the same level
88523
88524               var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
88525
88526               if (nextItem.empty()) {
88527                 // if there is a parent item
88528                 if (!parentItem.empty()) {
88529                   // the item is the last item of a sublist,
88530                   // select the next item at the parent level
88531                   nextItem = select(parentItem.node().nextElementSibling);
88532                 } // if the focused item is expanded
88533
88534               } else if (select(this).classed('expanded')) {
88535                 // select the first subitem instead
88536                 nextItem = item.select('.subgrid .preset-list-item:first-child');
88537               }
88538
88539               if (!nextItem.empty()) {
88540                 // focus on the next item
88541                 nextItem.select('.preset-list-button').node().focus();
88542               } // arrow up, move focus to the previous, higher item
88543
88544             } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
88545               d3_event.preventDefault();
88546               d3_event.stopPropagation(); // the previous item in the list at the same level
88547
88548               var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
88549
88550               if (previousItem.empty()) {
88551                 // if there is a parent item
88552                 if (!parentItem.empty()) {
88553                   // the item is the first subitem of a sublist select the parent item
88554                   previousItem = parentItem;
88555                 } // if the previous item is expanded
88556
88557               } else if (previousItem.select('.preset-list-button').classed('expanded')) {
88558                 // select the last subitem of the sublist of the previous item
88559                 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
88560               }
88561
88562               if (!previousItem.empty()) {
88563                 // focus on the previous item
88564                 previousItem.select('.preset-list-button').node().focus();
88565               } else {
88566                 // the focus is at the top of the list, move focus back to the search field
88567                 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
88568                 search.node().focus();
88569               } // arrow left, move focus to the parent item if there is one
88570
88571             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
88572               d3_event.preventDefault();
88573               d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
88574
88575               if (!parentItem.empty()) {
88576                 parentItem.select('.preset-list-button').node().focus();
88577               } // arrow right, choose this item
88578
88579             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
88580               d3_event.preventDefault();
88581               d3_event.stopPropagation();
88582               item.datum().choose.call(select(this).node());
88583             }
88584           }
88585
88586           function CategoryItem(preset) {
88587             var box,
88588                 sublist,
88589                 shown = false;
88590
88591             function item(selection) {
88592               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
88593
88594               function click() {
88595                 var isExpanded = select(this).classed('expanded');
88596                 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
88597                 select(this).classed('expanded', !isExpanded);
88598                 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
88599                 item.choose();
88600               }
88601
88602               var geometries = entityGeometries();
88603               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) {
88604                 // right arrow, expand the focused item
88605                 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
88606                   d3_event.preventDefault();
88607                   d3_event.stopPropagation(); // if the item isn't expanded
88608
88609                   if (!select(this).classed('expanded')) {
88610                     // toggle expansion (expand the item)
88611                     click.call(this, d3_event);
88612                   } // left arrow, collapse the focused item
88613
88614                 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
88615                   d3_event.preventDefault();
88616                   d3_event.stopPropagation(); // if the item is expanded
88617
88618                   if (select(this).classed('expanded')) {
88619                     // toggle expansion (collapse the item)
88620                     click.call(this, d3_event);
88621                   }
88622                 } else {
88623                   itemKeydown.call(this, d3_event);
88624                 }
88625               });
88626               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
88627               label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
88628                 return preset.nameLabel() + '&hellip;';
88629               });
88630               box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
88631               box.append('div').attr('class', 'arrow');
88632               sublist = box.append('div').attr('class', 'preset-list fillL3');
88633             }
88634
88635             item.choose = function () {
88636               if (!box || !sublist) return;
88637
88638               if (shown) {
88639                 shown = false;
88640                 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
88641               } else {
88642                 shown = true;
88643                 var members = preset.members.matchAllGeometry(entityGeometries());
88644                 sublist.call(drawList, members);
88645                 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
88646               }
88647             };
88648
88649             item.preset = preset;
88650             return item;
88651           }
88652
88653           function PresetItem(preset) {
88654             function item(selection) {
88655               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
88656               var geometries = entityGeometries();
88657               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);
88658               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
88659               var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
88660               label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
88661                 return d;
88662               });
88663               wrap.call(item.reference.button);
88664               selection.call(item.reference.body);
88665             }
88666
88667             item.choose = function () {
88668               if (select(this).classed('disabled')) return;
88669
88670               if (!context.inIntro()) {
88671                 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
88672               }
88673
88674               context.perform(function (graph) {
88675                 for (var i in _entityIDs) {
88676                   var entityID = _entityIDs[i];
88677                   var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
88678                   graph = actionChangePreset(entityID, oldPreset, preset)(graph);
88679                 }
88680
88681                 return graph;
88682               }, _t('operations.change_tags.annotation'));
88683               context.validator().validate(); // rerun validation
88684
88685               dispatch$1.call('choose', this, preset);
88686             };
88687
88688             item.help = function (d3_event) {
88689               d3_event.stopPropagation();
88690               item.reference.toggle();
88691             };
88692
88693             item.preset = preset;
88694             item.reference = uiTagReference(preset.reference());
88695             return item;
88696           }
88697
88698           function updateForFeatureHiddenState() {
88699             if (!_entityIDs.every(context.hasEntity)) return;
88700             var geometries = entityGeometries();
88701             var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
88702
88703             button.call(uiTooltip().destroyAny);
88704             button.each(function (item, index) {
88705               var hiddenPresetFeaturesId;
88706
88707               for (var i in geometries) {
88708                 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
88709                 if (hiddenPresetFeaturesId) break;
88710               }
88711
88712               var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
88713               select(this).classed('disabled', isHiddenPreset);
88714
88715               if (isHiddenPreset) {
88716                 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
88717                 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
88718                   features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
88719                 })).placement(index < 2 ? 'bottom' : 'top'));
88720               }
88721             });
88722           }
88723
88724           presetList.autofocus = function (val) {
88725             if (!arguments.length) return _autofocus;
88726             _autofocus = val;
88727             return presetList;
88728           };
88729
88730           presetList.entityIDs = function (val) {
88731             if (!arguments.length) return _entityIDs;
88732             _entityIDs = val;
88733
88734             if (_entityIDs && _entityIDs.length) {
88735               var presets = _entityIDs.map(function (entityID) {
88736                 return _mainPresetIndex.match(context.entity(entityID), context.graph());
88737               });
88738
88739               presetList.presets(presets);
88740             }
88741
88742             return presetList;
88743           };
88744
88745           presetList.presets = function (val) {
88746             if (!arguments.length) return _currentPresets;
88747             _currentPresets = val;
88748             return presetList;
88749           };
88750
88751           function entityGeometries() {
88752             var counts = {};
88753
88754             for (var i in _entityIDs) {
88755               var entityID = _entityIDs[i];
88756               var entity = context.entity(entityID);
88757               var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
88758
88759               if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
88760                 geometry = 'point';
88761               }
88762
88763               if (!counts[geometry]) counts[geometry] = 0;
88764               counts[geometry] += 1;
88765             }
88766
88767             return Object.keys(counts).sort(function (geom1, geom2) {
88768               return counts[geom2] - counts[geom1];
88769             });
88770           }
88771
88772           function combinedEntityExtent() {
88773             return _entityIDs.reduce(function (extent, entityID) {
88774               var entity = context.graph().entity(entityID);
88775               return extent.extend(entity.extent(context.graph()));
88776             }, geoExtent());
88777           }
88778
88779           return utilRebind(presetList, dispatch$1, 'on');
88780         }
88781
88782         function uiInspector(context) {
88783           var presetList = uiPresetList(context);
88784           var entityEditor = uiEntityEditor(context);
88785           var wrap = select(null),
88786               presetPane = select(null),
88787               editorPane = select(null);
88788           var _state = 'select';
88789
88790           var _entityIDs;
88791
88792           var _newFeature = false;
88793
88794           function inspector(selection) {
88795             presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
88796               inspector.setPreset();
88797             });
88798             entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
88799             wrap = selection.selectAll('.panewrap').data([0]);
88800             var enter = wrap.enter().append('div').attr('class', 'panewrap');
88801             enter.append('div').attr('class', 'preset-list-pane pane');
88802             enter.append('div').attr('class', 'entity-editor-pane pane');
88803             wrap = wrap.merge(enter);
88804             presetPane = wrap.selectAll('.preset-list-pane');
88805             editorPane = wrap.selectAll('.entity-editor-pane');
88806
88807             function shouldDefaultToPresetList() {
88808               // always show the inspector on hover
88809               if (_state !== 'select') return false; // can only change preset on single selection
88810
88811               if (_entityIDs.length !== 1) return false;
88812               var entityID = _entityIDs[0];
88813               var entity = context.hasEntity(entityID);
88814               if (!entity) return false; // default to inspector if there are already tags
88815
88816               if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
88817
88818               if (_newFeature) return true; // all existing features except vertices should default to inspector
88819
88820               if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
88821
88822               if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
88823
88824               if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
88825
88826               if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
88827
88828               return true;
88829             }
88830
88831             if (shouldDefaultToPresetList()) {
88832               wrap.style('right', '-100%');
88833               editorPane.classed('hide', true);
88834               presetPane.classed('hide', false).call(presetList);
88835             } else {
88836               wrap.style('right', '0%');
88837               presetPane.classed('hide', true);
88838               editorPane.classed('hide', false).call(entityEditor);
88839             }
88840
88841             var footer = selection.selectAll('.footer').data([0]);
88842             footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
88843             footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
88844           }
88845
88846           inspector.showList = function (presets) {
88847             presetPane.classed('hide', false);
88848             wrap.transition().styleTween('right', function () {
88849               return interpolate('0%', '-100%');
88850             }).on('end', function () {
88851               editorPane.classed('hide', true);
88852             });
88853
88854             if (presets) {
88855               presetList.presets(presets);
88856             }
88857
88858             presetPane.call(presetList.autofocus(true));
88859           };
88860
88861           inspector.setPreset = function (preset) {
88862             // upon setting multipolygon, go to the area preset list instead of the editor
88863             if (preset && preset.id === 'type/multipolygon') {
88864               presetPane.call(presetList.autofocus(true));
88865             } else {
88866               editorPane.classed('hide', false);
88867               wrap.transition().styleTween('right', function () {
88868                 return interpolate('-100%', '0%');
88869               }).on('end', function () {
88870                 presetPane.classed('hide', true);
88871               });
88872
88873               if (preset) {
88874                 entityEditor.presets([preset]);
88875               }
88876
88877               editorPane.call(entityEditor);
88878             }
88879           };
88880
88881           inspector.state = function (val) {
88882             if (!arguments.length) return _state;
88883             _state = val;
88884             entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
88885
88886             context.container().selectAll('.field-help-body').remove();
88887             return inspector;
88888           };
88889
88890           inspector.entityIDs = function (val) {
88891             if (!arguments.length) return _entityIDs;
88892             _entityIDs = val;
88893             return inspector;
88894           };
88895
88896           inspector.newFeature = function (val) {
88897             if (!arguments.length) return _newFeature;
88898             _newFeature = val;
88899             return inspector;
88900           };
88901
88902           return inspector;
88903         }
88904
88905         function uiSidebar(context) {
88906           var inspector = uiInspector(context);
88907           var dataEditor = uiDataEditor(context);
88908           var noteEditor = uiNoteEditor(context);
88909           var improveOsmEditor = uiImproveOsmEditor(context);
88910           var keepRightEditor = uiKeepRightEditor(context);
88911           var osmoseEditor = uiOsmoseEditor(context);
88912
88913           var _current;
88914
88915           var _wasData = false;
88916           var _wasNote = false;
88917           var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
88918
88919           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
88920
88921           function sidebar(selection) {
88922             var container = context.container();
88923             var minWidth = 240;
88924             var sidebarWidth;
88925             var containerWidth;
88926             var dragOffset; // Set the initial width constraints
88927
88928             selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
88929             var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
88930             var downPointerId, lastClientX, containerLocGetter;
88931
88932             function pointerdown(d3_event) {
88933               if (downPointerId) return;
88934               if ('button' in d3_event && d3_event.button !== 0) return;
88935               downPointerId = d3_event.pointerId || 'mouse';
88936               lastClientX = d3_event.clientX;
88937               containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
88938
88939               dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
88940               sidebarWidth = selection.node().getBoundingClientRect().width;
88941               containerWidth = container.node().getBoundingClientRect().width;
88942               var widthPct = sidebarWidth / containerWidth * 100;
88943               selection.style('width', widthPct + '%') // lock in current width
88944               .style('max-width', '85%'); // but allow larger widths
88945
88946               resizer.classed('dragging', true);
88947               select(window).on('touchmove.sidebar-resizer', function (d3_event) {
88948                 // disable page scrolling while resizing on touch input
88949                 d3_event.preventDefault();
88950               }, {
88951                 passive: false
88952               }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
88953             }
88954
88955             function pointermove(d3_event) {
88956               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
88957               d3_event.preventDefault();
88958               var dx = d3_event.clientX - lastClientX;
88959               lastClientX = d3_event.clientX;
88960               var isRTL = _mainLocalizer.textDirection() === 'rtl';
88961               var scaleX = isRTL ? 0 : 1;
88962               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
88963               var x = containerLocGetter(d3_event)[0] - dragOffset;
88964               sidebarWidth = isRTL ? containerWidth - x : x;
88965               var isCollapsed = selection.classed('collapsed');
88966               var shouldCollapse = sidebarWidth < minWidth;
88967               selection.classed('collapsed', shouldCollapse);
88968
88969               if (shouldCollapse) {
88970                 if (!isCollapsed) {
88971                   selection.style(xMarginProperty, '-400px').style('width', '400px');
88972                   context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
88973                 }
88974               } else {
88975                 var widthPct = sidebarWidth / containerWidth * 100;
88976                 selection.style(xMarginProperty, null).style('width', widthPct + '%');
88977
88978                 if (isCollapsed) {
88979                   context.ui().onResize([-sidebarWidth * scaleX, 0]);
88980                 } else {
88981                   context.ui().onResize([-dx * scaleX, 0]);
88982                 }
88983               }
88984             }
88985
88986             function pointerup(d3_event) {
88987               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
88988               downPointerId = null;
88989               resizer.classed('dragging', false);
88990               select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
88991             }
88992
88993             var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
88994             var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
88995
88996             var hoverModeSelect = function hoverModeSelect(targets) {
88997               context.container().selectAll('.feature-list-item button').classed('hover', false);
88998
88999               if (context.selectedIDs().length > 1 && targets && targets.length) {
89000                 var elements = context.container().selectAll('.feature-list-item button').filter(function (node) {
89001                   return targets.indexOf(node) !== -1;
89002                 });
89003
89004                 if (!elements.empty()) {
89005                   elements.classed('hover', true);
89006                 }
89007               }
89008             };
89009
89010             sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
89011
89012             function hover(targets) {
89013               var datum = targets && targets.length && targets[0];
89014
89015               if (datum && datum.__featurehash__) {
89016                 // hovering on data
89017                 _wasData = true;
89018                 sidebar.show(dataEditor.datum(datum));
89019                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89020               } else if (datum instanceof osmNote) {
89021                 if (context.mode().id === 'drag-note') return;
89022                 _wasNote = true;
89023                 var osm = services.osm;
89024
89025                 if (osm) {
89026                   datum = osm.getNote(datum.id); // marker may contain stale data - get latest
89027                 }
89028
89029                 sidebar.show(noteEditor.note(datum));
89030                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89031               } else if (datum instanceof QAItem) {
89032                 _wasQaItem = true;
89033                 var errService = services[datum.service];
89034
89035                 if (errService) {
89036                   // marker may contain stale data - get latest
89037                   datum = errService.getError(datum.id);
89038                 } // Currently only three possible services
89039
89040
89041                 var errEditor;
89042
89043                 if (datum.service === 'keepRight') {
89044                   errEditor = keepRightEditor;
89045                 } else if (datum.service === 'osmose') {
89046                   errEditor = osmoseEditor;
89047                 } else {
89048                   errEditor = improveOsmEditor;
89049                 }
89050
89051                 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
89052                   return d.id === datum.id;
89053                 });
89054                 sidebar.show(errEditor.error(datum));
89055                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89056               } else if (!_current && datum instanceof osmEntity) {
89057                 featureListWrap.classed('inspector-hidden', true);
89058                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
89059
89060                 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
89061                   inspector.state('hover').entityIDs([datum.id]).newFeature(false);
89062                   inspectorWrap.call(inspector);
89063                 }
89064               } else if (!_current) {
89065                 featureListWrap.classed('inspector-hidden', false);
89066                 inspectorWrap.classed('inspector-hidden', true);
89067                 inspector.state('hide');
89068               } else if (_wasData || _wasNote || _wasQaItem) {
89069                 _wasNote = false;
89070                 _wasData = false;
89071                 _wasQaItem = false;
89072                 context.container().selectAll('.note').classed('hover', false);
89073                 context.container().selectAll('.qaItem').classed('hover', false);
89074                 sidebar.hide();
89075               }
89076             }
89077
89078             sidebar.hover = throttle(hover, 200);
89079
89080             sidebar.intersects = function (extent) {
89081               var rect = selection.node().getBoundingClientRect();
89082               return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
89083             };
89084
89085             sidebar.select = function (ids, newFeature) {
89086               sidebar.hide();
89087
89088               if (ids && ids.length) {
89089                 var entity = ids.length === 1 && context.entity(ids[0]);
89090
89091                 if (entity && newFeature && selection.classed('collapsed')) {
89092                   // uncollapse the sidebar
89093                   var extent = entity.extent(context.graph());
89094                   sidebar.expand(sidebar.intersects(extent));
89095                 }
89096
89097                 featureListWrap.classed('inspector-hidden', true);
89098                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
89099                 // themselves may have changed
89100
89101                 inspector.state('select').entityIDs(ids).newFeature(newFeature);
89102                 inspectorWrap.call(inspector);
89103               } else {
89104                 inspector.state('hide');
89105               }
89106             };
89107
89108             sidebar.showPresetList = function () {
89109               inspector.showList();
89110             };
89111
89112             sidebar.show = function (component, element) {
89113               featureListWrap.classed('inspector-hidden', true);
89114               inspectorWrap.classed('inspector-hidden', true);
89115               if (_current) _current.remove();
89116               _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
89117             };
89118
89119             sidebar.hide = function () {
89120               featureListWrap.classed('inspector-hidden', false);
89121               inspectorWrap.classed('inspector-hidden', true);
89122               if (_current) _current.remove();
89123               _current = null;
89124             };
89125
89126             sidebar.expand = function (moveMap) {
89127               if (selection.classed('collapsed')) {
89128                 sidebar.toggle(moveMap);
89129               }
89130             };
89131
89132             sidebar.collapse = function (moveMap) {
89133               if (!selection.classed('collapsed')) {
89134                 sidebar.toggle(moveMap);
89135               }
89136             };
89137
89138             sidebar.toggle = function (moveMap) {
89139               // Don't allow sidebar to toggle when the user is in the walkthrough.
89140               if (context.inIntro()) return;
89141               var isCollapsed = selection.classed('collapsed');
89142               var isCollapsing = !isCollapsed;
89143               var isRTL = _mainLocalizer.textDirection() === 'rtl';
89144               var scaleX = isRTL ? 0 : 1;
89145               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
89146               sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
89147
89148               selection.style('width', sidebarWidth + 'px');
89149               var startMargin, endMargin, lastMargin;
89150
89151               if (isCollapsing) {
89152                 startMargin = lastMargin = 0;
89153                 endMargin = -sidebarWidth;
89154               } else {
89155                 startMargin = lastMargin = -sidebarWidth;
89156                 endMargin = 0;
89157               }
89158
89159               if (!isCollapsing) {
89160                 // unhide the sidebar's content before it transitions onscreen
89161                 selection.classed('collapsed', isCollapsing);
89162               }
89163
89164               selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
89165                 var i = d3_interpolateNumber(startMargin, endMargin);
89166                 return function (t) {
89167                   var dx = lastMargin - Math.round(i(t));
89168                   lastMargin = lastMargin - dx;
89169                   context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
89170                 };
89171               }).on('end', function () {
89172                 if (isCollapsing) {
89173                   // hide the sidebar's content after it transitions offscreen
89174                   selection.classed('collapsed', isCollapsing);
89175                 } // switch back from px to %
89176
89177
89178                 if (!isCollapsing) {
89179                   var containerWidth = container.node().getBoundingClientRect().width;
89180                   var widthPct = sidebarWidth / containerWidth * 100;
89181                   selection.style(xMarginProperty, null).style('width', widthPct + '%');
89182                 }
89183               });
89184             }; // toggle the sidebar collapse when double-clicking the resizer
89185
89186
89187             resizer.on('dblclick', function (d3_event) {
89188               d3_event.preventDefault();
89189
89190               if (d3_event.sourceEvent) {
89191                 d3_event.sourceEvent.preventDefault();
89192               }
89193
89194               sidebar.toggle();
89195             }); // ensure hover sidebar is closed when zooming out beyond editable zoom
89196
89197             context.map().on('crossEditableZoom.sidebar', function (within) {
89198               if (!within && !selection.select('.inspector-hover').empty()) {
89199                 hover([]);
89200               }
89201             });
89202           }
89203
89204           sidebar.showPresetList = function () {};
89205
89206           sidebar.hover = function () {};
89207
89208           sidebar.hover.cancel = function () {};
89209
89210           sidebar.intersects = function () {};
89211
89212           sidebar.select = function () {};
89213
89214           sidebar.show = function () {};
89215
89216           sidebar.hide = function () {};
89217
89218           sidebar.expand = function () {};
89219
89220           sidebar.collapse = function () {};
89221
89222           sidebar.toggle = function () {};
89223
89224           return sidebar;
89225         }
89226
89227         function uiSourceSwitch(context) {
89228           var keys;
89229
89230           function click(d3_event) {
89231             d3_event.preventDefault();
89232             var osm = context.connection();
89233             if (!osm) return;
89234             if (context.inIntro()) return;
89235             if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
89236             var isLive = select(this).classed('live');
89237             isLive = !isLive;
89238             context.enter(modeBrowse(context));
89239             context.history().clearSaved(); // remove saved history
89240
89241             context.flush(); // remove stored data
89242
89243             select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
89244             osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
89245           }
89246
89247           var sourceSwitch = function sourceSwitch(selection) {
89248             selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
89249           };
89250
89251           sourceSwitch.keys = function (_) {
89252             if (!arguments.length) return keys;
89253             keys = _;
89254             return sourceSwitch;
89255           };
89256
89257           return sourceSwitch;
89258         }
89259
89260         function uiSpinner(context) {
89261           var osm = context.connection();
89262           return function (selection) {
89263             var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
89264
89265             if (osm) {
89266               osm.on('loading.spinner', function () {
89267                 img.transition().style('opacity', 1);
89268               }).on('loaded.spinner', function () {
89269                 img.transition().style('opacity', 0);
89270               });
89271             }
89272           };
89273         }
89274
89275         function uiSplash(context) {
89276           return function (selection) {
89277             // Exception - if there are restorable changes, skip this splash screen.
89278             // This is because we currently only support one `uiModal` at a time
89279             //  and we need to show them `uiRestore`` instead of this one.
89280             if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
89281
89282             var updateMessage = '';
89283             var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
89284             var showSplash = !corePreferences('sawSplash');
89285
89286             if (sawPrivacyVersion !== context.privacyVersion) {
89287               updateMessage = _t('splash.privacy_update');
89288               showSplash = true;
89289             }
89290
89291             if (!showSplash) return;
89292             corePreferences('sawSplash', true);
89293             corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
89294
89295             _mainFileFetcher.get('intro_graph');
89296             var modalSelection = uiModal(selection);
89297             modalSelection.select('.modal').attr('class', 'modal-splash modal');
89298             var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
89299             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
89300             var modalSection = introModal.append('div').attr('class', 'modal-section');
89301             modalSection.append('p').html(_t.html('splash.text', {
89302               version: context.version,
89303               website: '<a target="_blank" href="http://ideditor.blog/">ideditor.blog</a>',
89304               github: '<a target="_blank" href="https://github.com/openstreetmap/iD">github.com</a>'
89305             }));
89306             modalSection.append('p').html(_t.html('splash.privacy', {
89307               updateMessage: updateMessage,
89308               privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
89309             }));
89310             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
89311             var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
89312               context.container().call(uiIntro(context));
89313               modalSelection.close();
89314             });
89315             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
89316             walkthrough.append('div').html(_t.html('splash.walkthrough'));
89317             var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
89318             startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
89319             startEditing.append('div').html(_t.html('splash.start'));
89320             modalSelection.select('button.close').attr('class', 'hide');
89321           };
89322         }
89323
89324         function uiStatus(context) {
89325           var osm = context.connection();
89326           return function (selection) {
89327             if (!osm) return;
89328
89329             function update(err, apiStatus) {
89330               selection.html('');
89331
89332               if (err) {
89333                 if (apiStatus === 'connectionSwitched') {
89334                   // if the connection was just switched, we can't rely on
89335                   // the status (we're getting the status of the previous api)
89336                   return;
89337                 } else if (apiStatus === 'rateLimited') {
89338                   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) {
89339                     d3_event.preventDefault();
89340                     osm.authenticate();
89341                   });
89342                 } else {
89343                   // don't allow retrying too rapidly
89344                   var throttledRetry = throttle(function () {
89345                     // try loading the visible tiles
89346                     context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
89347
89348                     osm.reloadApiStatus();
89349                   }, 2000); // eslint-disable-next-line no-warning-comments
89350                   // TODO: nice messages for different error types
89351
89352
89353                   selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
89354                   .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
89355                     d3_event.preventDefault();
89356                     throttledRetry();
89357                   });
89358                 }
89359               } else if (apiStatus === 'readonly') {
89360                 selection.html(_t.html('osm_api_status.message.readonly'));
89361               } else if (apiStatus === 'offline') {
89362                 selection.html(_t.html('osm_api_status.message.offline'));
89363               }
89364
89365               selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
89366             }
89367
89368             osm.on('apiStatusChange.uiStatus', update); // reload the status periodically regardless of other factors
89369
89370             window.setInterval(function () {
89371               osm.reloadApiStatus();
89372             }, 90000); // load the initial status in case no OSM data was loaded yet
89373
89374             osm.reloadApiStatus();
89375           };
89376         }
89377
89378         function modeDrawArea(context, wayID, startGraph, button) {
89379           var mode = {
89380             button: button,
89381             id: 'draw-area'
89382           };
89383           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
89384             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
89385           });
89386           mode.wayID = wayID;
89387
89388           mode.enter = function () {
89389             context.install(behavior);
89390           };
89391
89392           mode.exit = function () {
89393             context.uninstall(behavior);
89394           };
89395
89396           mode.selectedIDs = function () {
89397             return [wayID];
89398           };
89399
89400           mode.activeID = function () {
89401             return behavior && behavior.activeID() || [];
89402           };
89403
89404           return mode;
89405         }
89406
89407         function modeAddArea(context, mode) {
89408           mode.id = 'add-area';
89409           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
89410           var defaultTags = {
89411             area: 'yes'
89412           };
89413           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
89414
89415           function actionClose(wayId) {
89416             return function (graph) {
89417               return graph.replace(graph.entity(wayId).close());
89418             };
89419           }
89420
89421           function start(loc) {
89422             var startGraph = context.graph();
89423             var node = osmNode({
89424               loc: loc
89425             });
89426             var way = osmWay({
89427               tags: defaultTags
89428             });
89429             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
89430             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
89431           }
89432
89433           function startFromWay(loc, edge) {
89434             var startGraph = context.graph();
89435             var node = osmNode({
89436               loc: loc
89437             });
89438             var way = osmWay({
89439               tags: defaultTags
89440             });
89441             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
89442               loc: loc,
89443               edge: edge
89444             }, node));
89445             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
89446           }
89447
89448           function startFromNode(node) {
89449             var startGraph = context.graph();
89450             var way = osmWay({
89451               tags: defaultTags
89452             });
89453             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
89454             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
89455           }
89456
89457           mode.enter = function () {
89458             context.install(behavior);
89459           };
89460
89461           mode.exit = function () {
89462             context.uninstall(behavior);
89463           };
89464
89465           return mode;
89466         }
89467
89468         function modeAddLine(context, mode) {
89469           mode.id = 'add-line';
89470           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
89471           var defaultTags = {};
89472           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
89473
89474           function start(loc) {
89475             var startGraph = context.graph();
89476             var node = osmNode({
89477               loc: loc
89478             });
89479             var way = osmWay({
89480               tags: defaultTags
89481             });
89482             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
89483             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
89484           }
89485
89486           function startFromWay(loc, edge) {
89487             var startGraph = context.graph();
89488             var node = osmNode({
89489               loc: loc
89490             });
89491             var way = osmWay({
89492               tags: defaultTags
89493             });
89494             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
89495               loc: loc,
89496               edge: edge
89497             }, node));
89498             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
89499           }
89500
89501           function startFromNode(node) {
89502             var startGraph = context.graph();
89503             var way = osmWay({
89504               tags: defaultTags
89505             });
89506             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
89507             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
89508           }
89509
89510           mode.enter = function () {
89511             context.install(behavior);
89512           };
89513
89514           mode.exit = function () {
89515             context.uninstall(behavior);
89516           };
89517
89518           return mode;
89519         }
89520
89521         function modeAddPoint(context, mode) {
89522           mode.id = 'add-point';
89523           var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
89524           var defaultTags = {};
89525           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
89526
89527           function add(loc) {
89528             var node = osmNode({
89529               loc: loc,
89530               tags: defaultTags
89531             });
89532             context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
89533             enterSelectMode(node);
89534           }
89535
89536           function addWay(loc, edge) {
89537             var node = osmNode({
89538               tags: defaultTags
89539             });
89540             context.perform(actionAddMidpoint({
89541               loc: loc,
89542               edge: edge
89543             }, node), _t('operations.add.annotation.vertex'));
89544             enterSelectMode(node);
89545           }
89546
89547           function enterSelectMode(node) {
89548             context.enter(modeSelect(context, [node.id]).newFeature(true));
89549           }
89550
89551           function addNode(node) {
89552             if (Object.keys(defaultTags).length === 0) {
89553               enterSelectMode(node);
89554               return;
89555             }
89556
89557             var tags = Object.assign({}, node.tags); // shallow copy
89558
89559             for (var key in defaultTags) {
89560               tags[key] = defaultTags[key];
89561             }
89562
89563             context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
89564             enterSelectMode(node);
89565           }
89566
89567           function cancel() {
89568             context.enter(modeBrowse(context));
89569           }
89570
89571           mode.enter = function () {
89572             context.install(behavior);
89573           };
89574
89575           mode.exit = function () {
89576             context.uninstall(behavior);
89577           };
89578
89579           return mode;
89580         }
89581
89582         function modeAddNote(context) {
89583           var mode = {
89584             id: 'add-note',
89585             button: 'note',
89586             description: _t.html('modes.add_note.description'),
89587             key: _t('modes.add_note.key')
89588           };
89589           var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
89590
89591           function add(loc) {
89592             var osm = services.osm;
89593             if (!osm) return;
89594             var note = osmNote({
89595               loc: loc,
89596               status: 'open',
89597               comments: []
89598             });
89599             osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
89600
89601             context.map().pan([0, 0]);
89602             context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
89603           }
89604
89605           function cancel() {
89606             context.enter(modeBrowse(context));
89607           }
89608
89609           mode.enter = function () {
89610             context.install(behavior);
89611           };
89612
89613           mode.exit = function () {
89614             context.uninstall(behavior);
89615           };
89616
89617           return mode;
89618         }
89619
89620         function uiConflicts(context) {
89621           var dispatch$1 = dispatch('cancel', 'save');
89622           var keybinding = utilKeybinding('conflicts');
89623
89624           var _origChanges;
89625
89626           var _conflictList;
89627
89628           var _shownConflictIndex;
89629
89630           function keybindingOn() {
89631             select(document).call(keybinding.on('⎋', cancel, true));
89632           }
89633
89634           function keybindingOff() {
89635             select(document).call(keybinding.unbind);
89636           }
89637
89638           function tryAgain() {
89639             keybindingOff();
89640             dispatch$1.call('save');
89641           }
89642
89643           function cancel() {
89644             keybindingOff();
89645             dispatch$1.call('cancel');
89646           }
89647
89648           function conflicts(selection) {
89649             keybindingOn();
89650             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
89651             headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
89652             headerEnter.append('h3').html(_t.html('save.conflict.header'));
89653             var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
89654             var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
89655
89656             var detected = utilDetect();
89657             var changeset = new osmChangeset();
89658             delete changeset.id; // Export without changeset_id
89659
89660             var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
89661             var blob = new Blob([data], {
89662               type: 'text/xml;charset=utf-8;'
89663             });
89664             var fileName = 'changes.osc';
89665             var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
89666
89667             if (detected.download) {
89668               // All except IE11 and Edge
89669               linkEnter // download the data as a file
89670               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
89671             } else {
89672               // IE11 and Edge
89673               linkEnter // open data uri in a new tab
89674               .attr('target', '_blank').on('click.download', function () {
89675                 navigator.msSaveBlob(blob, fileName);
89676               });
89677             }
89678
89679             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
89680             bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
89681             bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
89682             var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
89683             buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
89684             buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
89685           }
89686
89687           function showConflict(selection, index) {
89688             index = utilWrap(index, _conflictList.length);
89689             _shownConflictIndex = index;
89690             var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
89691
89692             if (index === _conflictList.length - 1) {
89693               window.setTimeout(function () {
89694                 parent.select('.conflicts-button').attr('disabled', null);
89695                 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
89696               }, 250);
89697             }
89698
89699             var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
89700             conflict.exit().remove();
89701             var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
89702             conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
89703               num: index + 1,
89704               total: _conflictList.length
89705             }));
89706             conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
89707               return d.name;
89708             }).on('click', function (d3_event, d) {
89709               d3_event.preventDefault();
89710               zoomToEntity(d.id);
89711             });
89712             var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
89713             details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
89714               return d.details || [];
89715             }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
89716               return d;
89717             });
89718             details.append('div').attr('class', 'conflict-choices').call(addChoices);
89719             details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
89720               return _t.html('save.conflict.' + d);
89721             }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
89722               return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
89723             }).on('click', function (d3_event, d) {
89724               d3_event.preventDefault();
89725               var container = parent.selectAll('.conflict-container');
89726               var sign = d === 'previous' ? -1 : 1;
89727               container.selectAll('.conflict').remove();
89728               container.call(showConflict, index + sign);
89729             });
89730           }
89731
89732           function addChoices(selection) {
89733             var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
89734               return d.choices || [];
89735             }); // enter
89736
89737             var choicesEnter = choices.enter().append('li').attr('class', 'layer');
89738             var labelEnter = choicesEnter.append('label');
89739             labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
89740               return d.id;
89741             }).on('change', function (d3_event, d) {
89742               var ul = this.parentNode.parentNode.parentNode;
89743               ul.__data__.chosen = d.id;
89744               choose(d3_event, ul, d);
89745             });
89746             labelEnter.append('span').html(function (d) {
89747               return d.text;
89748             }); // update
89749
89750             choicesEnter.merge(choices).each(function (d) {
89751               var ul = this.parentNode;
89752
89753               if (ul.__data__.chosen === d.id) {
89754                 choose(null, ul, d);
89755               }
89756             });
89757           }
89758
89759           function choose(d3_event, ul, datum) {
89760             if (d3_event) d3_event.preventDefault();
89761             select(ul).selectAll('li').classed('active', function (d) {
89762               return d === datum;
89763             }).selectAll('input').property('checked', function (d) {
89764               return d === datum;
89765             });
89766             var extent = geoExtent();
89767             var entity;
89768             entity = context.graph().hasEntity(datum.id);
89769             if (entity) extent._extend(entity.extent(context.graph()));
89770             datum.action();
89771             entity = context.graph().hasEntity(datum.id);
89772             if (entity) extent._extend(entity.extent(context.graph()));
89773             zoomToEntity(datum.id, extent);
89774           }
89775
89776           function zoomToEntity(id, extent) {
89777             context.surface().selectAll('.hover').classed('hover', false);
89778             var entity = context.graph().hasEntity(id);
89779
89780             if (entity) {
89781               if (extent) {
89782                 context.map().trimmedExtent(extent);
89783               } else {
89784                 context.map().zoomToEase(entity);
89785               }
89786
89787               context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
89788             }
89789           } // The conflict list should be an array of objects like:
89790           // {
89791           //     id: id,
89792           //     name: entityName(local),
89793           //     details: merge.conflicts(),
89794           //     chosen: 1,
89795           //     choices: [
89796           //         choice(id, keepMine, forceLocal),
89797           //         choice(id, keepTheirs, forceRemote)
89798           //     ]
89799           // }
89800
89801
89802           conflicts.conflictList = function (_) {
89803             if (!arguments.length) return _conflictList;
89804             _conflictList = _;
89805             return conflicts;
89806           };
89807
89808           conflicts.origChanges = function (_) {
89809             if (!arguments.length) return _origChanges;
89810             _origChanges = _;
89811             return conflicts;
89812           };
89813
89814           conflicts.shownEntityIds = function () {
89815             if (_conflictList && typeof _shownConflictIndex === 'number') {
89816               return [_conflictList[_shownConflictIndex].id];
89817             }
89818
89819             return [];
89820           };
89821
89822           return utilRebind(conflicts, dispatch$1, 'on');
89823         }
89824
89825         function uiConfirm(selection) {
89826           var modalSelection = uiModal(selection);
89827           modalSelection.select('.modal').classed('modal-alert', true);
89828           var section = modalSelection.select('.content');
89829           section.append('div').attr('class', 'modal-section header');
89830           section.append('div').attr('class', 'modal-section message-text');
89831           var buttons = section.append('div').attr('class', 'modal-section buttons cf');
89832
89833           modalSelection.okButton = function () {
89834             buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
89835               modalSelection.remove();
89836             }).html(_t.html('confirm.okay')).node().focus();
89837             return modalSelection;
89838           };
89839
89840           return modalSelection;
89841         }
89842
89843         function uiChangesetEditor(context) {
89844           var dispatch$1 = dispatch('change');
89845           var formFields = uiFormFields(context);
89846           var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
89847
89848           var _fieldsArr;
89849
89850           var _tags;
89851
89852           var _changesetID;
89853
89854           function changesetEditor(selection) {
89855             render(selection);
89856           }
89857
89858           function render(selection) {
89859             var initial = false;
89860
89861             if (!_fieldsArr) {
89862               initial = true;
89863               var presets = _mainPresetIndex;
89864               _fieldsArr = [uiField(context, presets.field('comment'), null, {
89865                 show: true,
89866                 revert: false
89867               }), uiField(context, presets.field('source'), null, {
89868                 show: false,
89869                 revert: false
89870               }), uiField(context, presets.field('hashtags'), null, {
89871                 show: false,
89872                 revert: false
89873               })];
89874
89875               _fieldsArr.forEach(function (field) {
89876                 field.on('change', function (t, onInput) {
89877                   dispatch$1.call('change', field, undefined, t, onInput);
89878                 });
89879               });
89880             }
89881
89882             _fieldsArr.forEach(function (field) {
89883               field.tags(_tags);
89884             });
89885
89886             selection.call(formFields.fieldsArr(_fieldsArr));
89887
89888             if (initial) {
89889               var commentField = selection.select('.form-field-comment textarea');
89890               var commentNode = commentField.node();
89891
89892               if (commentNode) {
89893                 commentNode.focus();
89894                 commentNode.select();
89895               } // trigger a 'blur' event so that comment field can be cleaned
89896               // and checked for hashtags, even if retrieved from localstorage
89897
89898
89899               utilTriggerEvent(commentField, 'blur');
89900               var osm = context.connection();
89901
89902               if (osm) {
89903                 osm.userChangesets(function (err, changesets) {
89904                   if (err) return;
89905                   var comments = changesets.map(function (changeset) {
89906                     var comment = changeset.tags.comment;
89907                     return comment ? {
89908                       title: comment,
89909                       value: comment
89910                     } : null;
89911                   }).filter(Boolean);
89912                   commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
89913                 });
89914               }
89915             } // Add warning if comment mentions Google
89916
89917
89918             var hasGoogle = _tags.comment.match(/google/i);
89919
89920             var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
89921             commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
89922             var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
89923             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'));
89924             commentEnter.transition().duration(200).style('opacity', 1);
89925           }
89926
89927           changesetEditor.tags = function (_) {
89928             if (!arguments.length) return _tags;
89929             _tags = _; // Don't reset _fieldsArr here.
89930
89931             return changesetEditor;
89932           };
89933
89934           changesetEditor.changesetID = function (_) {
89935             if (!arguments.length) return _changesetID;
89936             if (_changesetID === _) return changesetEditor;
89937             _changesetID = _;
89938             _fieldsArr = null;
89939             return changesetEditor;
89940           };
89941
89942           return utilRebind(changesetEditor, dispatch$1, 'on');
89943         }
89944
89945         function uiSectionChanges(context) {
89946           var detected = utilDetect();
89947           var _discardTags = {};
89948           _mainFileFetcher.get('discarded').then(function (d) {
89949             _discardTags = d;
89950           })["catch"](function () {
89951             /* ignore */
89952           });
89953           var section = uiSection('changes-list', context).label(function () {
89954             var history = context.history();
89955             var summary = history.difference().summary();
89956             return _t('inspector.title_count', {
89957               title: _t.html('commit.changes'),
89958               count: summary.length
89959             });
89960           }).disclosureContent(renderDisclosureContent);
89961
89962           function renderDisclosureContent(selection) {
89963             var history = context.history();
89964             var summary = history.difference().summary();
89965             var container = selection.selectAll('.commit-section').data([0]);
89966             var containerEnter = container.enter().append('div').attr('class', 'commit-section');
89967             containerEnter.append('ul').attr('class', 'changeset-list');
89968             container = containerEnter.merge(container);
89969             var items = container.select('ul').selectAll('li').data(summary);
89970             var itemsEnter = items.enter().append('li').attr('class', 'change-item');
89971             var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
89972             buttons.each(function (d) {
89973               select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
89974             });
89975             buttons.append('span').attr('class', 'change-type').html(function (d) {
89976               return _t.html('commit.' + d.changeType) + ' ';
89977             });
89978             buttons.append('strong').attr('class', 'entity-type').html(function (d) {
89979               var matched = _mainPresetIndex.match(d.entity, d.graph);
89980               return matched && matched.name() || utilDisplayType(d.entity.id);
89981             });
89982             buttons.append('span').attr('class', 'entity-name').html(function (d) {
89983               var name = utilDisplayName(d.entity) || '',
89984                   string = '';
89985
89986               if (name !== '') {
89987                 string += ':';
89988               }
89989
89990               return string += ' ' + name;
89991             });
89992             items = itemsEnter.merge(items); // Download changeset link
89993
89994             var changeset = new osmChangeset().update({
89995               id: undefined
89996             });
89997             var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
89998             delete changeset.id; // Export without chnageset_id
89999
90000             var data = JXON.stringify(changeset.osmChangeJXON(changes));
90001             var blob = new Blob([data], {
90002               type: 'text/xml;charset=utf-8;'
90003             });
90004             var fileName = 'changes.osc';
90005             var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
90006
90007             if (detected.download) {
90008               // All except IE11 and Edge
90009               linkEnter // download the data as a file
90010               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90011             } else {
90012               // IE11 and Edge
90013               linkEnter // open data uri in a new tab
90014               .attr('target', '_blank').on('click.download', function () {
90015                 navigator.msSaveBlob(blob, fileName);
90016               });
90017             }
90018
90019             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
90020
90021             function mouseover(d) {
90022               if (d.entity) {
90023                 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
90024               }
90025             }
90026
90027             function mouseout() {
90028               context.surface().selectAll('.hover').classed('hover', false);
90029             }
90030
90031             function click(d3_event, change) {
90032               if (change.changeType !== 'deleted') {
90033                 var entity = change.entity;
90034                 context.map().zoomToEase(entity);
90035                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90036               }
90037             }
90038           }
90039
90040           return section;
90041         }
90042
90043         function uiCommitWarnings(context) {
90044           function commitWarnings(selection) {
90045             var issuesBySeverity = context.validator().getIssuesBySeverity({
90046               what: 'edited',
90047               where: 'all',
90048               includeDisabledRules: true
90049             });
90050
90051             for (var severity in issuesBySeverity) {
90052               var issues = issuesBySeverity[severity];
90053               var section = severity + '-section';
90054               var issueItem = severity + '-item';
90055               var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
90056               container.exit().remove();
90057               var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
90058               containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
90059               containerEnter.append('ul').attr('class', 'changeset-list');
90060               container = containerEnter.merge(container);
90061               var items = container.select('ul').selectAll('li').data(issues, function (d) {
90062                 return d.id;
90063               });
90064               items.exit().remove();
90065               var itemsEnter = items.enter().append('li').attr('class', issueItem);
90066               var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
90067                 if (d.entityIds) {
90068                   context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
90069                 }
90070               }).on('mouseout', function () {
90071                 context.surface().selectAll('.hover').classed('hover', false);
90072               }).on('click', function (d3_event, d) {
90073                 context.validator().focusIssue(d);
90074               });
90075               buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
90076               buttons.append('strong').attr('class', 'issue-message');
90077               buttons.filter(function (d) {
90078                 return d.tooltip;
90079               }).call(uiTooltip().title(function (d) {
90080                 return d.tooltip;
90081               }).placement('top'));
90082               items = itemsEnter.merge(items);
90083               items.selectAll('.issue-message').html(function (d) {
90084                 return d.message(context);
90085               });
90086             }
90087           }
90088
90089           return commitWarnings;
90090         }
90091
90092         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
90093         // from https://stackoverflow.com/a/25575009
90094
90095         var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
90096         function uiCommit(context) {
90097           var dispatch$1 = dispatch('cancel');
90098
90099           var _userDetails;
90100
90101           var _selection;
90102
90103           var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
90104           var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
90105           var commitChanges = uiSectionChanges(context);
90106           var commitWarnings = uiCommitWarnings(context);
90107
90108           function commit(selection) {
90109             _selection = selection; // Initialize changeset if one does not exist yet.
90110
90111             if (!context.changeset) initChangeset();
90112             loadDerivedChangesetTags();
90113             selection.call(render);
90114           }
90115
90116           function initChangeset() {
90117             // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
90118             var commentDate = +corePreferences('commentDate') || 0;
90119             var currDate = Date.now();
90120             var cutoff = 2 * 86400 * 1000; // 2 days
90121
90122             if (commentDate > currDate || currDate - commentDate > cutoff) {
90123               corePreferences('comment', null);
90124               corePreferences('hashtags', null);
90125               corePreferences('source', null);
90126             } // load in explicitly-set values, if any
90127
90128
90129             if (context.defaultChangesetComment()) {
90130               corePreferences('comment', context.defaultChangesetComment());
90131               corePreferences('commentDate', Date.now());
90132             }
90133
90134             if (context.defaultChangesetSource()) {
90135               corePreferences('source', context.defaultChangesetSource());
90136               corePreferences('commentDate', Date.now());
90137             }
90138
90139             if (context.defaultChangesetHashtags()) {
90140               corePreferences('hashtags', context.defaultChangesetHashtags());
90141               corePreferences('commentDate', Date.now());
90142             }
90143
90144             var detected = utilDetect();
90145             var tags = {
90146               comment: corePreferences('comment') || '',
90147               created_by: context.cleanTagValue('iD ' + context.version),
90148               host: context.cleanTagValue(detected.host),
90149               locale: context.cleanTagValue(_mainLocalizer.localeCode())
90150             }; // call findHashtags initially - this will remove stored
90151             // hashtags if any hashtags are found in the comment - #4304
90152
90153             findHashtags(tags, true);
90154             var hashtags = corePreferences('hashtags');
90155
90156             if (hashtags) {
90157               tags.hashtags = hashtags;
90158             }
90159
90160             var source = corePreferences('source');
90161
90162             if (source) {
90163               tags.source = source;
90164             }
90165
90166             var photoOverlaysUsed = context.history().photoOverlaysUsed();
90167
90168             if (photoOverlaysUsed.length) {
90169               var sources = (tags.source || '').split(';'); // include this tag for any photo layer
90170
90171               if (sources.indexOf('streetlevel imagery') === -1) {
90172                 sources.push('streetlevel imagery');
90173               } // add the photo overlays used during editing as sources
90174
90175
90176               photoOverlaysUsed.forEach(function (photoOverlay) {
90177                 if (sources.indexOf(photoOverlay) === -1) {
90178                   sources.push(photoOverlay);
90179                 }
90180               });
90181               tags.source = context.cleanTagValue(sources.join(';'));
90182             }
90183
90184             context.changeset = new osmChangeset({
90185               tags: tags
90186             });
90187           } // Calculates read-only metadata tags based on the user's editing session and applies
90188           // them to the changeset.
90189
90190
90191           function loadDerivedChangesetTags() {
90192             var osm = context.connection();
90193             if (!osm) return;
90194             var tags = Object.assign({}, context.changeset.tags); // shallow copy
90195             // assign tags for imagery used
90196
90197             var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
90198             tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
90199
90200             var osmClosed = osm.getClosedIDs();
90201             var itemType;
90202
90203             if (osmClosed.length) {
90204               tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
90205             }
90206
90207             if (services.keepRight) {
90208               var krClosed = services.keepRight.getClosedIDs();
90209
90210               if (krClosed.length) {
90211                 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
90212               }
90213             }
90214
90215             if (services.improveOSM) {
90216               var iOsmClosed = services.improveOSM.getClosedCounts();
90217
90218               for (itemType in iOsmClosed) {
90219                 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
90220               }
90221             }
90222
90223             if (services.osmose) {
90224               var osmoseClosed = services.osmose.getClosedCounts();
90225
90226               for (itemType in osmoseClosed) {
90227                 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
90228               }
90229             } // remove existing issue counts
90230
90231
90232             for (var key in tags) {
90233               if (key.match(/(^warnings:)|(^resolved:)/)) {
90234                 delete tags[key];
90235               }
90236             }
90237
90238             function addIssueCounts(issues, prefix) {
90239               var issuesByType = utilArrayGroupBy(issues, 'type');
90240
90241               for (var issueType in issuesByType) {
90242                 var issuesOfType = issuesByType[issueType];
90243
90244                 if (issuesOfType[0].subtype) {
90245                   var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
90246
90247                   for (var issueSubtype in issuesBySubtype) {
90248                     var issuesOfSubtype = issuesBySubtype[issueSubtype];
90249                     tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
90250                   }
90251                 } else {
90252                   tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
90253                 }
90254               }
90255             } // add counts of warnings generated by the user's edits
90256
90257
90258             var warnings = context.validator().getIssuesBySeverity({
90259               what: 'edited',
90260               where: 'all',
90261               includeIgnored: true,
90262               includeDisabledRules: true
90263             }).warning;
90264             addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
90265
90266             var resolvedIssues = context.validator().getResolvedIssues();
90267             addIssueCounts(resolvedIssues, 'resolved');
90268             context.changeset = context.changeset.update({
90269               tags: tags
90270             });
90271           }
90272
90273           function render(selection) {
90274             var osm = context.connection();
90275             if (!osm) return;
90276             var header = selection.selectAll('.header').data([0]);
90277             var headerTitle = header.enter().append('div').attr('class', 'header fillL');
90278             headerTitle.append('div').append('h3').html(_t.html('commit.title'));
90279             headerTitle.append('button').attr('class', 'close').on('click', function () {
90280               dispatch$1.call('cancel', this);
90281             }).call(svgIcon('#iD-icon-close'));
90282             var body = selection.selectAll('.body').data([0]);
90283             body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
90284
90285             var changesetSection = body.selectAll('.changeset-editor').data([0]);
90286             changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
90287             changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
90288
90289             body.call(commitWarnings); // Upload Explanation
90290
90291             var saveSection = body.selectAll('.save-section').data([0]);
90292             saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
90293             var prose = saveSection.selectAll('.commit-info').data([0]);
90294
90295             if (prose.enter().size()) {
90296               // first time, make sure to update user details in prose
90297               _userDetails = null;
90298             }
90299
90300             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()
90301             // if needed, because it can trigger a style recalculation
90302
90303             osm.userDetails(function (err, user) {
90304               if (err) return;
90305               if (_userDetails === user) return; // no change
90306
90307               _userDetails = user;
90308               var userLink = select(document.createElement('div'));
90309
90310               if (user.image_url) {
90311                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
90312               }
90313
90314               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
90315               prose.html(_t.html('commit.upload_explanation_with_user', {
90316                 user: userLink.html()
90317               }));
90318             }); // Request Review
90319
90320             var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
90321
90322             var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
90323             var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
90324             var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
90325             labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
90326             labelEnter.append('span').html(_t.html('commit.request_review')); // Update
90327
90328             requestReview = requestReview.merge(requestReviewEnter);
90329             var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
90330
90331             var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
90332
90333             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
90334             buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
90335             var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
90336             uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
90337             var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
90338
90339             buttonSection = buttonSection.merge(buttonEnter);
90340             buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
90341               dispatch$1.call('cancel', this);
90342             });
90343             buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
90344               if (!select(this).classed('disabled')) {
90345                 this.blur(); // avoid keeping focus on the button - #4641
90346
90347                 for (var key in context.changeset.tags) {
90348                   // remove any empty keys before upload
90349                   if (!key) delete context.changeset.tags[key];
90350                 }
90351
90352                 context.uploader().save(context.changeset);
90353               }
90354             }); // remove any existing tooltip
90355
90356             uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
90357
90358             if (uploadBlockerTooltipText) {
90359               buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
90360             } // Raw Tag Editor
90361
90362
90363             var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
90364             tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
90365             tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
90366             .render);
90367             var changesSection = body.selectAll('.commit-changes-section').data([0]);
90368             changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
90369
90370             changesSection.call(commitChanges.render);
90371
90372             function toggleRequestReview() {
90373               var rr = requestReviewInput.property('checked');
90374               updateChangeset({
90375                 review_requested: rr ? 'yes' : undefined
90376               });
90377               tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
90378               .render);
90379             }
90380           }
90381
90382           function getUploadBlockerMessage() {
90383             var errors = context.validator().getIssuesBySeverity({
90384               what: 'edited',
90385               where: 'all'
90386             }).error;
90387
90388             if (errors.length) {
90389               return _t('commit.outstanding_errors_message', {
90390                 count: errors.length
90391               });
90392             } else {
90393               var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
90394
90395               if (!hasChangesetComment) {
90396                 return _t('commit.comment_needed_message');
90397               }
90398             }
90399
90400             return null;
90401           }
90402
90403           function changeTags(_, changed, onInput) {
90404             if (changed.hasOwnProperty('comment')) {
90405               if (changed.comment === undefined) {
90406                 changed.comment = '';
90407               }
90408
90409               if (!onInput) {
90410                 corePreferences('comment', changed.comment);
90411                 corePreferences('commentDate', Date.now());
90412               }
90413             }
90414
90415             if (changed.hasOwnProperty('source')) {
90416               if (changed.source === undefined) {
90417                 corePreferences('source', null);
90418               } else if (!onInput) {
90419                 corePreferences('source', changed.source);
90420                 corePreferences('commentDate', Date.now());
90421               }
90422             } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
90423
90424
90425             updateChangeset(changed, onInput);
90426
90427             if (_selection) {
90428               _selection.call(render);
90429             }
90430           }
90431
90432           function findHashtags(tags, commentOnly) {
90433             var detectedHashtags = commentHashtags();
90434
90435             if (detectedHashtags.length) {
90436               // always remove stored hashtags if there are hashtags in the comment - #4304
90437               corePreferences('hashtags', null);
90438             }
90439
90440             if (!detectedHashtags.length || !commentOnly) {
90441               detectedHashtags = detectedHashtags.concat(hashtagHashtags());
90442             }
90443
90444             var allLowerCase = new Set();
90445             return detectedHashtags.filter(function (hashtag) {
90446               // Compare tags as lowercase strings, but keep original case tags
90447               var lowerCase = hashtag.toLowerCase();
90448
90449               if (!allLowerCase.has(lowerCase)) {
90450                 allLowerCase.add(lowerCase);
90451                 return true;
90452               }
90453
90454               return false;
90455             }); // Extract hashtags from `comment`
90456
90457             function commentHashtags() {
90458               var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
90459               .match(hashtagRegex);
90460               return matches || [];
90461             } // Extract and clean hashtags from `hashtags`
90462
90463
90464             function hashtagHashtags() {
90465               var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
90466                 if (s[0] !== '#') {
90467                   s = '#' + s;
90468                 } // prepend '#'
90469
90470
90471                 var matched = s.match(hashtagRegex);
90472                 return matched && matched[0];
90473               }).filter(Boolean); // exclude falsy
90474
90475               return matches || [];
90476             }
90477           }
90478
90479           function isReviewRequested(tags) {
90480             var rr = tags.review_requested;
90481             if (rr === undefined) return false;
90482             rr = rr.trim().toLowerCase();
90483             return !(rr === '' || rr === 'no');
90484           }
90485
90486           function updateChangeset(changed, onInput) {
90487             var tags = Object.assign({}, context.changeset.tags); // shallow copy
90488
90489             Object.keys(changed).forEach(function (k) {
90490               var v = changed[k];
90491               k = context.cleanTagKey(k);
90492               if (readOnlyTags.indexOf(k) !== -1) return;
90493
90494               if (v === undefined) {
90495                 delete tags[k];
90496               } else if (onInput) {
90497                 tags[k] = v;
90498               } else {
90499                 tags[k] = context.cleanTagValue(v);
90500               }
90501             });
90502
90503             if (!onInput) {
90504               // when changing the comment, override hashtags with any found in comment.
90505               var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
90506               var arr = findHashtags(tags, commentOnly);
90507
90508               if (arr.length) {
90509                 tags.hashtags = context.cleanTagValue(arr.join(';'));
90510                 corePreferences('hashtags', tags.hashtags);
90511               } else {
90512                 delete tags.hashtags;
90513                 corePreferences('hashtags', null);
90514               }
90515             } // always update userdetails, just in case user reauthenticates as someone else
90516
90517
90518             if (_userDetails && _userDetails.changesets_count !== undefined) {
90519               var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
90520
90521               tags.changesets_count = String(changesetsCount); // first 100 edits - new user
90522
90523               if (changesetsCount <= 100) {
90524                 var s;
90525                 s = corePreferences('walkthrough_completed');
90526
90527                 if (s) {
90528                   tags['ideditor:walkthrough_completed'] = s;
90529                 }
90530
90531                 s = corePreferences('walkthrough_progress');
90532
90533                 if (s) {
90534                   tags['ideditor:walkthrough_progress'] = s;
90535                 }
90536
90537                 s = corePreferences('walkthrough_started');
90538
90539                 if (s) {
90540                   tags['ideditor:walkthrough_started'] = s;
90541                 }
90542               }
90543             } else {
90544               delete tags.changesets_count;
90545             }
90546
90547             if (!fastDeepEqual(context.changeset.tags, tags)) {
90548               context.changeset = context.changeset.update({
90549                 tags: tags
90550               });
90551             }
90552           }
90553
90554           commit.reset = function () {
90555             context.changeset = null;
90556           };
90557
90558           return utilRebind(commit, dispatch$1, 'on');
90559         }
90560
90561         var globalIsFinite = global_1.isFinite;
90562
90563         // `Number.isFinite` method
90564         // https://tc39.es/ecma262/#sec-number.isfinite
90565         var numberIsFinite = Number.isFinite || function isFinite(it) {
90566           return typeof it == 'number' && globalIsFinite(it);
90567         };
90568
90569         // `Number.isFinite` method
90570         // https://tc39.es/ecma262/#sec-number.isfinite
90571         _export({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
90572
90573         var RADIUS = 6378137;
90574         var FLATTENING = 1 / 298.257223563;
90575         var POLAR_RADIUS$1 = 6356752.3142;
90576         var wgs84 = {
90577           RADIUS: RADIUS,
90578           FLATTENING: FLATTENING,
90579           POLAR_RADIUS: POLAR_RADIUS$1
90580         };
90581
90582         var geometry_1 = geometry;
90583         var ring = ringArea;
90584
90585         function geometry(_) {
90586           var area = 0,
90587               i;
90588
90589           switch (_.type) {
90590             case 'Polygon':
90591               return polygonArea(_.coordinates);
90592
90593             case 'MultiPolygon':
90594               for (i = 0; i < _.coordinates.length; i++) {
90595                 area += polygonArea(_.coordinates[i]);
90596               }
90597
90598               return area;
90599
90600             case 'Point':
90601             case 'MultiPoint':
90602             case 'LineString':
90603             case 'MultiLineString':
90604               return 0;
90605
90606             case 'GeometryCollection':
90607               for (i = 0; i < _.geometries.length; i++) {
90608                 area += geometry(_.geometries[i]);
90609               }
90610
90611               return area;
90612           }
90613         }
90614
90615         function polygonArea(coords) {
90616           var area = 0;
90617
90618           if (coords && coords.length > 0) {
90619             area += Math.abs(ringArea(coords[0]));
90620
90621             for (var i = 1; i < coords.length; i++) {
90622               area -= Math.abs(ringArea(coords[i]));
90623             }
90624           }
90625
90626           return area;
90627         }
90628         /**
90629          * Calculate the approximate area of the polygon were it projected onto
90630          *     the earth.  Note that this area will be positive if ring is oriented
90631          *     clockwise, otherwise it will be negative.
90632          *
90633          * Reference:
90634          * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
90635          *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
90636          *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
90637          *
90638          * Returns:
90639          * {float} The approximate signed geodesic area of the polygon in square
90640          *     meters.
90641          */
90642
90643
90644         function ringArea(coords) {
90645           var p1,
90646               p2,
90647               p3,
90648               lowerIndex,
90649               middleIndex,
90650               upperIndex,
90651               i,
90652               area = 0,
90653               coordsLength = coords.length;
90654
90655           if (coordsLength > 2) {
90656             for (i = 0; i < coordsLength; i++) {
90657               if (i === coordsLength - 2) {
90658                 // i = N-2
90659                 lowerIndex = coordsLength - 2;
90660                 middleIndex = coordsLength - 1;
90661                 upperIndex = 0;
90662               } else if (i === coordsLength - 1) {
90663                 // i = N-1
90664                 lowerIndex = coordsLength - 1;
90665                 middleIndex = 0;
90666                 upperIndex = 1;
90667               } else {
90668                 // i = 0 to N-3
90669                 lowerIndex = i;
90670                 middleIndex = i + 1;
90671                 upperIndex = i + 2;
90672               }
90673
90674               p1 = coords[lowerIndex];
90675               p2 = coords[middleIndex];
90676               p3 = coords[upperIndex];
90677               area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
90678             }
90679
90680             area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
90681           }
90682
90683           return area;
90684         }
90685
90686         function rad(_) {
90687           return _ * Math.PI / 180;
90688         }
90689
90690         var geojsonArea = {
90691           geometry: geometry_1,
90692           ring: ring
90693         };
90694
90695         var validateCenter_1 = function validateCenter(center) {
90696           var validCenterLengths = [2, 3];
90697
90698           if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
90699             throw new Error("ERROR! Center has to be an array of length two or three");
90700           }
90701
90702           var _center = _slicedToArray(center, 2),
90703               lng = _center[0],
90704               lat = _center[1];
90705
90706           if (typeof lng !== "number" || typeof lat !== "number") {
90707             throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
90708           }
90709
90710           if (lng > 180 || lng < -180) {
90711             throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
90712           }
90713
90714           if (lat > 90 || lat < -90) {
90715             throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
90716           }
90717         };
90718
90719         var validateCenter = {
90720           validateCenter: validateCenter_1
90721         };
90722
90723         var validateRadius_1 = function validateRadius(radius) {
90724           if (typeof radius !== "number") {
90725             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
90726           }
90727
90728           if (radius <= 0) {
90729             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
90730           }
90731         };
90732
90733         var validateRadius = {
90734           validateRadius: validateRadius_1
90735         };
90736
90737         var validateNumberOfEdges_1 = function validateNumberOfEdges(numberOfEdges) {
90738           if (typeof numberOfEdges !== "number") {
90739             var ARGUMENT_TYPE = Array.isArray(numberOfEdges) ? "array" : _typeof(numberOfEdges);
90740             throw new Error("ERROR! Number of edges has to be a number but was: ".concat(ARGUMENT_TYPE));
90741           }
90742
90743           if (numberOfEdges < 3) {
90744             throw new Error("ERROR! Number of edges has to be at least 3 but was: ".concat(numberOfEdges));
90745           }
90746         };
90747
90748         var validateNumberOfEdges = {
90749           validateNumberOfEdges: validateNumberOfEdges_1
90750         };
90751
90752         var validateEarthRadius_1 = function validateEarthRadius(earthRadius) {
90753           if (typeof earthRadius !== "number") {
90754             var ARGUMENT_TYPE = Array.isArray(earthRadius) ? "array" : _typeof(earthRadius);
90755             throw new Error("ERROR! Earth radius has to be a number but was: ".concat(ARGUMENT_TYPE));
90756           }
90757
90758           if (earthRadius <= 0) {
90759             throw new Error("ERROR! Earth radius has to be a positive number but was: ".concat(earthRadius));
90760           }
90761         };
90762
90763         var validateEarthRadius = {
90764           validateEarthRadius: validateEarthRadius_1
90765         };
90766
90767         var validateBearing_1 = function validateBearing(bearing) {
90768           if (typeof bearing !== "number") {
90769             var ARGUMENT_TYPE = Array.isArray(bearing) ? "array" : _typeof(bearing);
90770             throw new Error("ERROR! Bearing has to be a number but was: ".concat(ARGUMENT_TYPE));
90771           }
90772         };
90773
90774         var validateBearing = {
90775           validateBearing: validateBearing_1
90776         };
90777
90778         var validateCenter$1 = validateCenter.validateCenter;
90779         var validateRadius$1 = validateRadius.validateRadius;
90780         var validateNumberOfEdges$1 = validateNumberOfEdges.validateNumberOfEdges;
90781         var validateEarthRadius$1 = validateEarthRadius.validateEarthRadius;
90782         var validateBearing$1 = validateBearing.validateBearing;
90783
90784         function validateInput(_ref) {
90785           var center = _ref.center,
90786               radius = _ref.radius,
90787               numberOfEdges = _ref.numberOfEdges,
90788               earthRadius = _ref.earthRadius,
90789               bearing = _ref.bearing;
90790           validateCenter$1(center);
90791           validateRadius$1(radius);
90792           validateNumberOfEdges$1(numberOfEdges);
90793           validateEarthRadius$1(earthRadius);
90794           validateBearing$1(bearing);
90795         }
90796
90797         var validateCenter_1$1 = validateCenter$1;
90798         var validateRadius_1$1 = validateRadius$1;
90799         var validateNumberOfEdges_1$1 = validateNumberOfEdges$1;
90800         var validateEarthRadius_1$1 = validateEarthRadius$1;
90801         var validateBearing_1$1 = validateBearing$1;
90802         var validateInput_1 = validateInput;
90803         var inputValidation = {
90804           validateCenter: validateCenter_1$1,
90805           validateRadius: validateRadius_1$1,
90806           validateNumberOfEdges: validateNumberOfEdges_1$1,
90807           validateEarthRadius: validateEarthRadius_1$1,
90808           validateBearing: validateBearing_1$1,
90809           validateInput: validateInput_1
90810         };
90811
90812         var validateInput$1 = inputValidation.validateInput;
90813         var defaultEarthRadius = 6378137; // equatorial Earth radius
90814
90815         function toRadians(angleInDegrees) {
90816           return angleInDegrees * Math.PI / 180;
90817         }
90818
90819         function toDegrees(angleInRadians) {
90820           return angleInRadians * 180 / Math.PI;
90821         }
90822
90823         function offset(c1, distance, earthRadius, bearing) {
90824           var lat1 = toRadians(c1[1]);
90825           var lon1 = toRadians(c1[0]);
90826           var dByR = distance / earthRadius;
90827           var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
90828           var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
90829           return [toDegrees(lon), toDegrees(lat)];
90830         }
90831
90832         var circleToPolygon = function circleToPolygon(center, radius, options) {
90833           var n = getNumberOfEdges(options);
90834           var earthRadius = getEarthRadius(options);
90835           var bearing = getBearing(options); // validateInput() throws error on invalid input and do nothing on valid input
90836
90837           validateInput$1({
90838             center: center,
90839             radius: radius,
90840             numberOfEdges: n,
90841             earthRadius: earthRadius,
90842             bearing: bearing
90843           });
90844           var start = toRadians(bearing);
90845           var coordinates = [];
90846
90847           for (var i = 0; i < n; ++i) {
90848             coordinates.push(offset(center, radius, earthRadius, start + 2 * Math.PI * -i / n));
90849           }
90850
90851           coordinates.push(coordinates[0]);
90852           return {
90853             type: "Polygon",
90854             coordinates: [coordinates]
90855           };
90856         };
90857
90858         function getNumberOfEdges(options) {
90859           if (options === undefined) {
90860             return 32;
90861           } else if (isObjectNotArray(options)) {
90862             var numberOfEdges = options.numberOfEdges;
90863             return numberOfEdges === undefined ? 32 : numberOfEdges;
90864           }
90865
90866           return options;
90867         }
90868
90869         function getEarthRadius(options) {
90870           if (options === undefined) {
90871             return defaultEarthRadius;
90872           } else if (isObjectNotArray(options)) {
90873             var earthRadius = options.earthRadius;
90874             return earthRadius === undefined ? defaultEarthRadius : earthRadius;
90875           }
90876
90877           return defaultEarthRadius;
90878         }
90879
90880         function getBearing(options) {
90881           if (options === undefined) {
90882             return 0;
90883           } else if (isObjectNotArray(options)) {
90884             var bearing = options.bearing;
90885             return bearing === undefined ? 0 : bearing;
90886           }
90887
90888           return 0;
90889         }
90890
90891         function isObjectNotArray(argument) {
90892           return _typeof(argument) === "object" && !Array.isArray(argument);
90893         }
90894
90895         // `Number.EPSILON` constant
90896         // https://tc39.es/ecma262/#sec-number.epsilon
90897         _export({ target: 'Number', stat: true }, {
90898           EPSILON: Math.pow(2, -52)
90899         });
90900
90901         /**
90902          * splaytree v3.1.0
90903          * Fast Splay tree for Node and browser
90904          *
90905          * @author Alexander Milevski <info@w8r.name>
90906          * @license MIT
90907          * @preserve
90908          */
90909         var Node$1 =
90910         /** @class */
90911         function () {
90912           function Node(key, data) {
90913             this.next = null;
90914             this.key = key;
90915             this.data = data;
90916             this.left = null;
90917             this.right = null;
90918           }
90919
90920           return Node;
90921         }();
90922         /* follows "An implementation of top-down splaying"
90923          * by D. Sleator <sleator@cs.cmu.edu> March 1992
90924          */
90925
90926
90927         function DEFAULT_COMPARE$1(a, b) {
90928           return a > b ? 1 : a < b ? -1 : 0;
90929         }
90930         /**
90931          * Simple top down splay, not requiring i to be in the tree t.
90932          */
90933
90934
90935         function splay(i, t, comparator) {
90936           var N = new Node$1(null, null);
90937           var l = N;
90938           var r = N;
90939
90940           while (true) {
90941             var cmp = comparator(i, t.key); //if (i < t.key) {
90942
90943             if (cmp < 0) {
90944               if (t.left === null) break; //if (i < t.left.key) {
90945
90946               if (comparator(i, t.left.key) < 0) {
90947                 var y = t.left;
90948                 /* rotate right */
90949
90950                 t.left = y.right;
90951                 y.right = t;
90952                 t = y;
90953                 if (t.left === null) break;
90954               }
90955
90956               r.left = t;
90957               /* link right */
90958
90959               r = t;
90960               t = t.left; //} else if (i > t.key) {
90961             } else if (cmp > 0) {
90962               if (t.right === null) break; //if (i > t.right.key) {
90963
90964               if (comparator(i, t.right.key) > 0) {
90965                 var y = t.right;
90966                 /* rotate left */
90967
90968                 t.right = y.left;
90969                 y.left = t;
90970                 t = y;
90971                 if (t.right === null) break;
90972               }
90973
90974               l.right = t;
90975               /* link left */
90976
90977               l = t;
90978               t = t.right;
90979             } else break;
90980           }
90981           /* assemble */
90982
90983
90984           l.right = t.left;
90985           r.left = t.right;
90986           t.left = N.right;
90987           t.right = N.left;
90988           return t;
90989         }
90990
90991         function insert(i, data, t, comparator) {
90992           var node = new Node$1(i, data);
90993
90994           if (t === null) {
90995             node.left = node.right = null;
90996             return node;
90997           }
90998
90999           t = splay(i, t, comparator);
91000           var cmp = comparator(i, t.key);
91001
91002           if (cmp < 0) {
91003             node.left = t.left;
91004             node.right = t;
91005             t.left = null;
91006           } else if (cmp >= 0) {
91007             node.right = t.right;
91008             node.left = t;
91009             t.right = null;
91010           }
91011
91012           return node;
91013         }
91014
91015         function split$2(key, v, comparator) {
91016           var left = null;
91017           var right = null;
91018
91019           if (v) {
91020             v = splay(key, v, comparator);
91021             var cmp = comparator(v.key, key);
91022
91023             if (cmp === 0) {
91024               left = v.left;
91025               right = v.right;
91026             } else if (cmp < 0) {
91027               right = v.right;
91028               v.right = null;
91029               left = v;
91030             } else {
91031               left = v.left;
91032               v.left = null;
91033               right = v;
91034             }
91035           }
91036
91037           return {
91038             left: left,
91039             right: right
91040           };
91041         }
91042
91043         function merge$4(left, right, comparator) {
91044           if (right === null) return left;
91045           if (left === null) return right;
91046           right = splay(left.key, right, comparator);
91047           right.left = left;
91048           return right;
91049         }
91050         /**
91051          * Prints level of the tree
91052          */
91053
91054
91055         function printRow(root, prefix, isTail, out, printNode) {
91056           if (root) {
91057             out("" + prefix + (isTail ? '└── ' : '├── ') + printNode(root) + "\n");
91058             var indent = prefix + (isTail ? '    ' : '│   ');
91059             if (root.left) printRow(root.left, indent, false, out, printNode);
91060             if (root.right) printRow(root.right, indent, true, out, printNode);
91061           }
91062         }
91063
91064         var Tree =
91065         /** @class */
91066         function () {
91067           function Tree(comparator) {
91068             if (comparator === void 0) {
91069               comparator = DEFAULT_COMPARE$1;
91070             }
91071
91072             this._root = null;
91073             this._size = 0;
91074             this._comparator = comparator;
91075           }
91076           /**
91077            * Inserts a key, allows duplicates
91078            */
91079
91080
91081           Tree.prototype.insert = function (key, data) {
91082             this._size++;
91083             return this._root = insert(key, data, this._root, this._comparator);
91084           };
91085           /**
91086            * Adds a key, if it is not present in the tree
91087            */
91088
91089
91090           Tree.prototype.add = function (key, data) {
91091             var node = new Node$1(key, data);
91092
91093             if (this._root === null) {
91094               node.left = node.right = null;
91095               this._size++;
91096               this._root = node;
91097             }
91098
91099             var comparator = this._comparator;
91100             var t = splay(key, this._root, comparator);
91101             var cmp = comparator(key, t.key);
91102             if (cmp === 0) this._root = t;else {
91103               if (cmp < 0) {
91104                 node.left = t.left;
91105                 node.right = t;
91106                 t.left = null;
91107               } else if (cmp > 0) {
91108                 node.right = t.right;
91109                 node.left = t;
91110                 t.right = null;
91111               }
91112
91113               this._size++;
91114               this._root = node;
91115             }
91116             return this._root;
91117           };
91118           /**
91119            * @param  {Key} key
91120            * @return {Node|null}
91121            */
91122
91123
91124           Tree.prototype.remove = function (key) {
91125             this._root = this._remove(key, this._root, this._comparator);
91126           };
91127           /**
91128            * Deletes i from the tree if it's there
91129            */
91130
91131
91132           Tree.prototype._remove = function (i, t, comparator) {
91133             var x;
91134             if (t === null) return null;
91135             t = splay(i, t, comparator);
91136             var cmp = comparator(i, t.key);
91137
91138             if (cmp === 0) {
91139               /* found it */
91140               if (t.left === null) {
91141                 x = t.right;
91142               } else {
91143                 x = splay(i, t.left, comparator);
91144                 x.right = t.right;
91145               }
91146
91147               this._size--;
91148               return x;
91149             }
91150
91151             return t;
91152             /* It wasn't there */
91153           };
91154           /**
91155            * Removes and returns the node with smallest key
91156            */
91157
91158
91159           Tree.prototype.pop = function () {
91160             var node = this._root;
91161
91162             if (node) {
91163               while (node.left) {
91164                 node = node.left;
91165               }
91166
91167               this._root = splay(node.key, this._root, this._comparator);
91168               this._root = this._remove(node.key, this._root, this._comparator);
91169               return {
91170                 key: node.key,
91171                 data: node.data
91172               };
91173             }
91174
91175             return null;
91176           };
91177           /**
91178            * Find without splaying
91179            */
91180
91181
91182           Tree.prototype.findStatic = function (key) {
91183             var current = this._root;
91184             var compare = this._comparator;
91185
91186             while (current) {
91187               var cmp = compare(key, current.key);
91188               if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
91189             }
91190
91191             return null;
91192           };
91193
91194           Tree.prototype.find = function (key) {
91195             if (this._root) {
91196               this._root = splay(key, this._root, this._comparator);
91197               if (this._comparator(key, this._root.key) !== 0) return null;
91198             }
91199
91200             return this._root;
91201           };
91202
91203           Tree.prototype.contains = function (key) {
91204             var current = this._root;
91205             var compare = this._comparator;
91206
91207             while (current) {
91208               var cmp = compare(key, current.key);
91209               if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
91210             }
91211
91212             return false;
91213           };
91214
91215           Tree.prototype.forEach = function (visitor, ctx) {
91216             var current = this._root;
91217             var Q = [];
91218             /* Initialize stack s */
91219
91220             var done = false;
91221
91222             while (!done) {
91223               if (current !== null) {
91224                 Q.push(current);
91225                 current = current.left;
91226               } else {
91227                 if (Q.length !== 0) {
91228                   current = Q.pop();
91229                   visitor.call(ctx, current);
91230                   current = current.right;
91231                 } else done = true;
91232               }
91233             }
91234
91235             return this;
91236           };
91237           /**
91238            * Walk key range from `low` to `high`. Stops if `fn` returns a value.
91239            */
91240
91241
91242           Tree.prototype.range = function (low, high, fn, ctx) {
91243             var Q = [];
91244             var compare = this._comparator;
91245             var node = this._root;
91246             var cmp;
91247
91248             while (Q.length !== 0 || node) {
91249               if (node) {
91250                 Q.push(node);
91251                 node = node.left;
91252               } else {
91253                 node = Q.pop();
91254                 cmp = compare(node.key, high);
91255
91256                 if (cmp > 0) {
91257                   break;
91258                 } else if (compare(node.key, low) >= 0) {
91259                   if (fn.call(ctx, node)) return this; // stop if smth is returned
91260                 }
91261
91262                 node = node.right;
91263               }
91264             }
91265
91266             return this;
91267           };
91268           /**
91269            * Returns array of keys
91270            */
91271
91272
91273           Tree.prototype.keys = function () {
91274             var keys = [];
91275             this.forEach(function (_a) {
91276               var key = _a.key;
91277               return keys.push(key);
91278             });
91279             return keys;
91280           };
91281           /**
91282            * Returns array of all the data in the nodes
91283            */
91284
91285
91286           Tree.prototype.values = function () {
91287             var values = [];
91288             this.forEach(function (_a) {
91289               var data = _a.data;
91290               return values.push(data);
91291             });
91292             return values;
91293           };
91294
91295           Tree.prototype.min = function () {
91296             if (this._root) return this.minNode(this._root).key;
91297             return null;
91298           };
91299
91300           Tree.prototype.max = function () {
91301             if (this._root) return this.maxNode(this._root).key;
91302             return null;
91303           };
91304
91305           Tree.prototype.minNode = function (t) {
91306             if (t === void 0) {
91307               t = this._root;
91308             }
91309
91310             if (t) while (t.left) {
91311               t = t.left;
91312             }
91313             return t;
91314           };
91315
91316           Tree.prototype.maxNode = function (t) {
91317             if (t === void 0) {
91318               t = this._root;
91319             }
91320
91321             if (t) while (t.right) {
91322               t = t.right;
91323             }
91324             return t;
91325           };
91326           /**
91327            * Returns node at given index
91328            */
91329
91330
91331           Tree.prototype.at = function (index) {
91332             var current = this._root;
91333             var done = false;
91334             var i = 0;
91335             var Q = [];
91336
91337             while (!done) {
91338               if (current) {
91339                 Q.push(current);
91340                 current = current.left;
91341               } else {
91342                 if (Q.length > 0) {
91343                   current = Q.pop();
91344                   if (i === index) return current;
91345                   i++;
91346                   current = current.right;
91347                 } else done = true;
91348               }
91349             }
91350
91351             return null;
91352           };
91353
91354           Tree.prototype.next = function (d) {
91355             var root = this._root;
91356             var successor = null;
91357
91358             if (d.right) {
91359               successor = d.right;
91360
91361               while (successor.left) {
91362                 successor = successor.left;
91363               }
91364
91365               return successor;
91366             }
91367
91368             var comparator = this._comparator;
91369
91370             while (root) {
91371               var cmp = comparator(d.key, root.key);
91372               if (cmp === 0) break;else if (cmp < 0) {
91373                 successor = root;
91374                 root = root.left;
91375               } else root = root.right;
91376             }
91377
91378             return successor;
91379           };
91380
91381           Tree.prototype.prev = function (d) {
91382             var root = this._root;
91383             var predecessor = null;
91384
91385             if (d.left !== null) {
91386               predecessor = d.left;
91387
91388               while (predecessor.right) {
91389                 predecessor = predecessor.right;
91390               }
91391
91392               return predecessor;
91393             }
91394
91395             var comparator = this._comparator;
91396
91397             while (root) {
91398               var cmp = comparator(d.key, root.key);
91399               if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
91400                 predecessor = root;
91401                 root = root.right;
91402               }
91403             }
91404
91405             return predecessor;
91406           };
91407
91408           Tree.prototype.clear = function () {
91409             this._root = null;
91410             this._size = 0;
91411             return this;
91412           };
91413
91414           Tree.prototype.toList = function () {
91415             return toList(this._root);
91416           };
91417           /**
91418            * Bulk-load items. Both array have to be same size
91419            */
91420
91421
91422           Tree.prototype.load = function (keys, values, presort) {
91423             if (values === void 0) {
91424               values = [];
91425             }
91426
91427             if (presort === void 0) {
91428               presort = false;
91429             }
91430
91431             var size = keys.length;
91432             var comparator = this._comparator; // sort if needed
91433
91434             if (presort) sort$1(keys, values, 0, size - 1, comparator);
91435
91436             if (this._root === null) {
91437               // empty tree
91438               this._root = loadRecursive$1(keys, values, 0, size);
91439               this._size = size;
91440             } else {
91441               // that re-builds the whole tree from two in-order traversals
91442               var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
91443               size = this._size + size;
91444               this._root = sortedListToBST({
91445                 head: mergedList
91446               }, 0, size);
91447             }
91448
91449             return this;
91450           };
91451
91452           Tree.prototype.isEmpty = function () {
91453             return this._root === null;
91454           };
91455
91456           Object.defineProperty(Tree.prototype, "size", {
91457             get: function get() {
91458               return this._size;
91459             },
91460             enumerable: true,
91461             configurable: true
91462           });
91463           Object.defineProperty(Tree.prototype, "root", {
91464             get: function get() {
91465               return this._root;
91466             },
91467             enumerable: true,
91468             configurable: true
91469           });
91470
91471           Tree.prototype.toString = function (printNode) {
91472             if (printNode === void 0) {
91473               printNode = function printNode(n) {
91474                 return String(n.key);
91475               };
91476             }
91477
91478             var out = [];
91479             printRow(this._root, '', true, function (v) {
91480               return out.push(v);
91481             }, printNode);
91482             return out.join('');
91483           };
91484
91485           Tree.prototype.update = function (key, newKey, newData) {
91486             var comparator = this._comparator;
91487
91488             var _a = split$2(key, this._root, comparator),
91489                 left = _a.left,
91490                 right = _a.right;
91491
91492             if (comparator(key, newKey) < 0) {
91493               right = insert(newKey, newData, right, comparator);
91494             } else {
91495               left = insert(newKey, newData, left, comparator);
91496             }
91497
91498             this._root = merge$4(left, right, comparator);
91499           };
91500
91501           Tree.prototype.split = function (key) {
91502             return split$2(key, this._root, this._comparator);
91503           };
91504
91505           return Tree;
91506         }();
91507
91508         function loadRecursive$1(keys, values, start, end) {
91509           var size = end - start;
91510
91511           if (size > 0) {
91512             var middle = start + Math.floor(size / 2);
91513             var key = keys[middle];
91514             var data = values[middle];
91515             var node = new Node$1(key, data);
91516             node.left = loadRecursive$1(keys, values, start, middle);
91517             node.right = loadRecursive$1(keys, values, middle + 1, end);
91518             return node;
91519           }
91520
91521           return null;
91522         }
91523
91524         function createList(keys, values) {
91525           var head = new Node$1(null, null);
91526           var p = head;
91527
91528           for (var i = 0; i < keys.length; i++) {
91529             p = p.next = new Node$1(keys[i], values[i]);
91530           }
91531
91532           p.next = null;
91533           return head.next;
91534         }
91535
91536         function toList(root) {
91537           var current = root;
91538           var Q = [];
91539           var done = false;
91540           var head = new Node$1(null, null);
91541           var p = head;
91542
91543           while (!done) {
91544             if (current) {
91545               Q.push(current);
91546               current = current.left;
91547             } else {
91548               if (Q.length > 0) {
91549                 current = p = p.next = Q.pop();
91550                 current = current.right;
91551               } else done = true;
91552             }
91553           }
91554
91555           p.next = null; // that'll work even if the tree was empty
91556
91557           return head.next;
91558         }
91559
91560         function sortedListToBST(list, start, end) {
91561           var size = end - start;
91562
91563           if (size > 0) {
91564             var middle = start + Math.floor(size / 2);
91565             var left = sortedListToBST(list, start, middle);
91566             var root = list.head;
91567             root.left = left;
91568             list.head = list.head.next;
91569             root.right = sortedListToBST(list, middle + 1, end);
91570             return root;
91571           }
91572
91573           return null;
91574         }
91575
91576         function mergeLists(l1, l2, compare) {
91577           var head = new Node$1(null, null); // dummy
91578
91579           var p = head;
91580           var p1 = l1;
91581           var p2 = l2;
91582
91583           while (p1 !== null && p2 !== null) {
91584             if (compare(p1.key, p2.key) < 0) {
91585               p.next = p1;
91586               p1 = p1.next;
91587             } else {
91588               p.next = p2;
91589               p2 = p2.next;
91590             }
91591
91592             p = p.next;
91593           }
91594
91595           if (p1 !== null) {
91596             p.next = p1;
91597           } else if (p2 !== null) {
91598             p.next = p2;
91599           }
91600
91601           return head.next;
91602         }
91603
91604         function sort$1(keys, values, left, right, compare) {
91605           if (left >= right) return;
91606           var pivot = keys[left + right >> 1];
91607           var i = left - 1;
91608           var j = right + 1;
91609
91610           while (true) {
91611             do {
91612               i++;
91613             } while (compare(keys[i], pivot) < 0);
91614
91615             do {
91616               j--;
91617             } while (compare(keys[j], pivot) > 0);
91618
91619             if (i >= j) break;
91620             var tmp = keys[i];
91621             keys[i] = keys[j];
91622             keys[j] = tmp;
91623             tmp = values[i];
91624             values[i] = values[j];
91625             values[j] = tmp;
91626           }
91627
91628           sort$1(keys, values, left, j, compare);
91629           sort$1(keys, values, j + 1, right, compare);
91630         }
91631
91632         function _classCallCheck$1(instance, Constructor) {
91633           if (!(instance instanceof Constructor)) {
91634             throw new TypeError("Cannot call a class as a function");
91635           }
91636         }
91637
91638         function _defineProperties$1(target, props) {
91639           for (var i = 0; i < props.length; i++) {
91640             var descriptor = props[i];
91641             descriptor.enumerable = descriptor.enumerable || false;
91642             descriptor.configurable = true;
91643             if ("value" in descriptor) descriptor.writable = true;
91644             Object.defineProperty(target, descriptor.key, descriptor);
91645           }
91646         }
91647
91648         function _createClass$1(Constructor, protoProps, staticProps) {
91649           if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
91650           if (staticProps) _defineProperties$1(Constructor, staticProps);
91651           return Constructor;
91652         }
91653         /**
91654          * A bounding box has the format:
91655          *
91656          *  { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
91657          *
91658          */
91659
91660
91661         var isInBbox = function isInBbox(bbox, point) {
91662           return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
91663         };
91664         /* Returns either null, or a bbox (aka an ordered pair of points)
91665          * If there is only one point of overlap, a bbox with identical points
91666          * will be returned */
91667
91668
91669         var getBboxOverlap = function getBboxOverlap(b1, b2) {
91670           // check if the bboxes overlap at all
91671           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
91672
91673           var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
91674           var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
91675
91676           var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
91677           var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
91678
91679           return {
91680             ll: {
91681               x: lowerX,
91682               y: lowerY
91683             },
91684             ur: {
91685               x: upperX,
91686               y: upperY
91687             }
91688           };
91689         };
91690         /* Javascript doesn't do integer math. Everything is
91691          * floating point with percision Number.EPSILON.
91692          *
91693          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
91694          */
91695
91696
91697         var epsilon$2 = Number.EPSILON; // IE Polyfill
91698
91699         if (epsilon$2 === undefined) epsilon$2 = Math.pow(2, -52);
91700         var EPSILON_SQ = epsilon$2 * epsilon$2;
91701         /* FLP comparator */
91702
91703         var cmp = function cmp(a, b) {
91704           // check if they're both 0
91705           if (-epsilon$2 < a && a < epsilon$2) {
91706             if (-epsilon$2 < b && b < epsilon$2) {
91707               return 0;
91708             }
91709           } // check if they're flp equal
91710
91711
91712           var ab = a - b;
91713
91714           if (ab * ab < EPSILON_SQ * a * b) {
91715             return 0;
91716           } // normal comparison
91717
91718
91719           return a < b ? -1 : 1;
91720         };
91721         /**
91722          * This class rounds incoming values sufficiently so that
91723          * floating points problems are, for the most part, avoided.
91724          *
91725          * Incoming points are have their x & y values tested against
91726          * all previously seen x & y values. If either is 'too close'
91727          * to a previously seen value, it's value is 'snapped' to the
91728          * previously seen value.
91729          *
91730          * All points should be rounded by this class before being
91731          * stored in any data structures in the rest of this algorithm.
91732          */
91733
91734
91735         var PtRounder = /*#__PURE__*/function () {
91736           function PtRounder() {
91737             _classCallCheck$1(this, PtRounder);
91738
91739             this.reset();
91740           }
91741
91742           _createClass$1(PtRounder, [{
91743             key: "reset",
91744             value: function reset() {
91745               this.xRounder = new CoordRounder();
91746               this.yRounder = new CoordRounder();
91747             }
91748           }, {
91749             key: "round",
91750             value: function round(x, y) {
91751               return {
91752                 x: this.xRounder.round(x),
91753                 y: this.yRounder.round(y)
91754               };
91755             }
91756           }]);
91757
91758           return PtRounder;
91759         }();
91760
91761         var CoordRounder = /*#__PURE__*/function () {
91762           function CoordRounder() {
91763             _classCallCheck$1(this, CoordRounder);
91764
91765             this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
91766
91767             this.round(0);
91768           } // Note: this can rounds input values backwards or forwards.
91769           //       You might ask, why not restrict this to just rounding
91770           //       forwards? Wouldn't that allow left endpoints to always
91771           //       remain left endpoints during splitting (never change to
91772           //       right). No - it wouldn't, because we snap intersections
91773           //       to endpoints (to establish independence from the segment
91774           //       angle for t-intersections).
91775
91776
91777           _createClass$1(CoordRounder, [{
91778             key: "round",
91779             value: function round(coord) {
91780               var node = this.tree.add(coord);
91781               var prevNode = this.tree.prev(node);
91782
91783               if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
91784                 this.tree.remove(coord);
91785                 return prevNode.key;
91786               }
91787
91788               var nextNode = this.tree.next(node);
91789
91790               if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
91791                 this.tree.remove(coord);
91792                 return nextNode.key;
91793               }
91794
91795               return coord;
91796             }
91797           }]);
91798
91799           return CoordRounder;
91800         }(); // singleton available by import
91801
91802
91803         var rounder = new PtRounder();
91804         /* Cross Product of two vectors with first point at origin */
91805
91806         var crossProduct$1 = function crossProduct(a, b) {
91807           return a.x * b.y - a.y * b.x;
91808         };
91809         /* Dot Product of two vectors with first point at origin */
91810
91811
91812         var dotProduct$1 = function dotProduct(a, b) {
91813           return a.x * b.x + a.y * b.y;
91814         };
91815         /* Comparator for two vectors with same starting point */
91816
91817
91818         var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
91819           var v1 = {
91820             x: endPt1.x - basePt.x,
91821             y: endPt1.y - basePt.y
91822           };
91823           var v2 = {
91824             x: endPt2.x - basePt.x,
91825             y: endPt2.y - basePt.y
91826           };
91827           var kross = crossProduct$1(v1, v2);
91828           return cmp(kross, 0);
91829         };
91830
91831         var length = function length(v) {
91832           return Math.sqrt(dotProduct$1(v, v));
91833         };
91834         /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
91835
91836
91837         var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
91838           var vBase = {
91839             x: pBase.x - pShared.x,
91840             y: pBase.y - pShared.y
91841           };
91842           var vAngle = {
91843             x: pAngle.x - pShared.x,
91844             y: pAngle.y - pShared.y
91845           };
91846           return crossProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
91847         };
91848         /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
91849
91850
91851         var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
91852           var vBase = {
91853             x: pBase.x - pShared.x,
91854             y: pBase.y - pShared.y
91855           };
91856           var vAngle = {
91857             x: pAngle.x - pShared.x,
91858             y: pAngle.y - pShared.y
91859           };
91860           return dotProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
91861         };
91862         /* Get the x coordinate where the given line (defined by a point and vector)
91863          * crosses the horizontal line with the given y coordiante.
91864          * In the case of parrallel lines (including overlapping ones) returns null. */
91865
91866
91867         var horizontalIntersection = function horizontalIntersection(pt, v, y) {
91868           if (v.y === 0) return null;
91869           return {
91870             x: pt.x + v.x / v.y * (y - pt.y),
91871             y: y
91872           };
91873         };
91874         /* Get the y coordinate where the given line (defined by a point and vector)
91875          * crosses the vertical line with the given x coordiante.
91876          * In the case of parrallel lines (including overlapping ones) returns null. */
91877
91878
91879         var verticalIntersection = function verticalIntersection(pt, v, x) {
91880           if (v.x === 0) return null;
91881           return {
91882             x: x,
91883             y: pt.y + v.y / v.x * (x - pt.x)
91884           };
91885         };
91886         /* Get the intersection of two lines, each defined by a base point and a vector.
91887          * In the case of parrallel lines (including overlapping ones) returns null. */
91888
91889
91890         var intersection$1 = function intersection(pt1, v1, pt2, v2) {
91891           // take some shortcuts for vertical and horizontal lines
91892           // this also ensures we don't calculate an intersection and then discover
91893           // it's actually outside the bounding box of the line
91894           if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
91895           if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
91896           if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
91897           if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
91898           // This algorithm is based on Schneider and Eberly.
91899           // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
91900
91901           var kross = crossProduct$1(v1, v2);
91902           if (kross == 0) return null;
91903           var ve = {
91904             x: pt2.x - pt1.x,
91905             y: pt2.y - pt1.y
91906           };
91907           var d1 = crossProduct$1(ve, v1) / kross;
91908           var d2 = crossProduct$1(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
91909
91910           var x1 = pt1.x + d2 * v1.x,
91911               x2 = pt2.x + d1 * v2.x;
91912           var y1 = pt1.y + d2 * v1.y,
91913               y2 = pt2.y + d1 * v2.y;
91914           var x = (x1 + x2) / 2;
91915           var y = (y1 + y2) / 2;
91916           return {
91917             x: x,
91918             y: y
91919           };
91920         };
91921
91922         var SweepEvent$1 = /*#__PURE__*/function () {
91923           _createClass$1(SweepEvent, null, [{
91924             key: "compare",
91925             // for ordering sweep events in the sweep event queue
91926             value: function compare(a, b) {
91927               // favor event with a point that the sweep line hits first
91928               var ptCmp = SweepEvent.comparePoints(a.point, b.point);
91929               if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
91930
91931               if (a.point !== b.point) a.link(b); // favor right events over left
91932
91933               if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
91934               // ordering of this case is the same as for their segments
91935
91936               return Segment.compare(a.segment, b.segment);
91937             } // for ordering points in sweep line order
91938
91939           }, {
91940             key: "comparePoints",
91941             value: function comparePoints(aPt, bPt) {
91942               if (aPt.x < bPt.x) return -1;
91943               if (aPt.x > bPt.x) return 1;
91944               if (aPt.y < bPt.y) return -1;
91945               if (aPt.y > bPt.y) return 1;
91946               return 0;
91947             } // Warning: 'point' input will be modified and re-used (for performance)
91948
91949           }]);
91950
91951           function SweepEvent(point, isLeft) {
91952             _classCallCheck$1(this, SweepEvent);
91953
91954             if (point.events === undefined) point.events = [this];else point.events.push(this);
91955             this.point = point;
91956             this.isLeft = isLeft; // this.segment, this.otherSE set by factory
91957           }
91958
91959           _createClass$1(SweepEvent, [{
91960             key: "link",
91961             value: function link(other) {
91962               if (other.point === this.point) {
91963                 throw new Error('Tried to link already linked events');
91964               }
91965
91966               var otherEvents = other.point.events;
91967
91968               for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
91969                 var evt = otherEvents[i];
91970                 this.point.events.push(evt);
91971                 evt.point = this.point;
91972               }
91973
91974               this.checkForConsuming();
91975             }
91976             /* Do a pass over our linked events and check to see if any pair
91977              * of segments match, and should be consumed. */
91978
91979           }, {
91980             key: "checkForConsuming",
91981             value: function checkForConsuming() {
91982               // FIXME: The loops in this method run O(n^2) => no good.
91983               //        Maintain little ordered sweep event trees?
91984               //        Can we maintaining an ordering that avoids the need
91985               //        for the re-sorting with getLeftmostComparator in geom-out?
91986               // Compare each pair of events to see if other events also match
91987               var numEvents = this.point.events.length;
91988
91989               for (var i = 0; i < numEvents; i++) {
91990                 var evt1 = this.point.events[i];
91991                 if (evt1.segment.consumedBy !== undefined) continue;
91992
91993                 for (var j = i + 1; j < numEvents; j++) {
91994                   var evt2 = this.point.events[j];
91995                   if (evt2.consumedBy !== undefined) continue;
91996                   if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
91997                   evt1.segment.consume(evt2.segment);
91998                 }
91999               }
92000             }
92001           }, {
92002             key: "getAvailableLinkedEvents",
92003             value: function getAvailableLinkedEvents() {
92004               // point.events is always of length 2 or greater
92005               var events = [];
92006
92007               for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
92008                 var evt = this.point.events[i];
92009
92010                 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
92011                   events.push(evt);
92012                 }
92013               }
92014
92015               return events;
92016             }
92017             /**
92018              * Returns a comparator function for sorting linked events that will
92019              * favor the event that will give us the smallest left-side angle.
92020              * All ring construction starts as low as possible heading to the right,
92021              * so by always turning left as sharp as possible we'll get polygons
92022              * without uncessary loops & holes.
92023              *
92024              * The comparator function has a compute cache such that it avoids
92025              * re-computing already-computed values.
92026              */
92027
92028           }, {
92029             key: "getLeftmostComparator",
92030             value: function getLeftmostComparator(baseEvent) {
92031               var _this = this;
92032
92033               var cache = new Map();
92034
92035               var fillCache = function fillCache(linkedEvent) {
92036                 var nextEvent = linkedEvent.otherSE;
92037                 cache.set(linkedEvent, {
92038                   sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
92039                   cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
92040                 });
92041               };
92042
92043               return function (a, b) {
92044                 if (!cache.has(a)) fillCache(a);
92045                 if (!cache.has(b)) fillCache(b);
92046
92047                 var _cache$get = cache.get(a),
92048                     asine = _cache$get.sine,
92049                     acosine = _cache$get.cosine;
92050
92051                 var _cache$get2 = cache.get(b),
92052                     bsine = _cache$get2.sine,
92053                     bcosine = _cache$get2.cosine; // both on or above x-axis
92054
92055
92056                 if (asine >= 0 && bsine >= 0) {
92057                   if (acosine < bcosine) return 1;
92058                   if (acosine > bcosine) return -1;
92059                   return 0;
92060                 } // both below x-axis
92061
92062
92063                 if (asine < 0 && bsine < 0) {
92064                   if (acosine < bcosine) return -1;
92065                   if (acosine > bcosine) return 1;
92066                   return 0;
92067                 } // one above x-axis, one below
92068
92069
92070                 if (bsine < asine) return -1;
92071                 if (bsine > asine) return 1;
92072                 return 0;
92073               };
92074             }
92075           }]);
92076
92077           return SweepEvent;
92078         }(); // segments and sweep events when all else is identical
92079
92080
92081         var segmentId = 0;
92082
92083         var Segment = /*#__PURE__*/function () {
92084           _createClass$1(Segment, null, [{
92085             key: "compare",
92086
92087             /* This compare() function is for ordering segments in the sweep
92088              * line tree, and does so according to the following criteria:
92089              *
92090              * Consider the vertical line that lies an infinestimal step to the
92091              * right of the right-more of the two left endpoints of the input
92092              * segments. Imagine slowly moving a point up from negative infinity
92093              * in the increasing y direction. Which of the two segments will that
92094              * point intersect first? That segment comes 'before' the other one.
92095              *
92096              * If neither segment would be intersected by such a line, (if one
92097              * or more of the segments are vertical) then the line to be considered
92098              * is directly on the right-more of the two left inputs.
92099              */
92100             value: function compare(a, b) {
92101               var alx = a.leftSE.point.x;
92102               var blx = b.leftSE.point.x;
92103               var arx = a.rightSE.point.x;
92104               var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
92105
92106               if (brx < alx) return 1;
92107               if (arx < blx) return -1;
92108               var aly = a.leftSE.point.y;
92109               var bly = b.leftSE.point.y;
92110               var ary = a.rightSE.point.y;
92111               var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
92112
92113               if (alx < blx) {
92114                 // are the two segments in the same horizontal plane?
92115                 if (bly < aly && bly < ary) return 1;
92116                 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
92117
92118                 var aCmpBLeft = a.comparePoint(b.leftSE.point);
92119                 if (aCmpBLeft < 0) return 1;
92120                 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
92121
92122                 var bCmpARight = b.comparePoint(a.rightSE.point);
92123                 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
92124                 // left endpoint to be first (arbitrary?)
92125
92126                 return -1;
92127               } // is left endpoint of segment A the right-more?
92128
92129
92130               if (alx > blx) {
92131                 if (aly < bly && aly < bry) return -1;
92132                 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
92133
92134                 var bCmpALeft = b.comparePoint(a.leftSE.point);
92135                 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
92136
92137                 var aCmpBRight = a.comparePoint(b.rightSE.point);
92138                 if (aCmpBRight < 0) return 1;
92139                 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
92140                 // left endpoint to be first (arbitrary?)
92141
92142                 return 1;
92143               } // if we get here, the two left endpoints are in the same
92144               // vertical plane, ie alx === blx
92145               // consider the lower left-endpoint to come first
92146
92147
92148               if (aly < bly) return -1;
92149               if (aly > bly) return 1; // left endpoints are identical
92150               // check for colinearity by using the left-more right endpoint
92151               // is the A right endpoint more left-more?
92152
92153               if (arx < brx) {
92154                 var _bCmpARight = b.comparePoint(a.rightSE.point);
92155
92156                 if (_bCmpARight !== 0) return _bCmpARight;
92157               } // is the B right endpoint more left-more?
92158
92159
92160               if (arx > brx) {
92161                 var _aCmpBRight = a.comparePoint(b.rightSE.point);
92162
92163                 if (_aCmpBRight < 0) return 1;
92164                 if (_aCmpBRight > 0) return -1;
92165               }
92166
92167               if (arx !== brx) {
92168                 // are these two [almost] vertical segments with opposite orientation?
92169                 // if so, the one with the lower right endpoint comes first
92170                 var ay = ary - aly;
92171                 var ax = arx - alx;
92172                 var by = bry - bly;
92173                 var bx = brx - blx;
92174                 if (ay > ax && by < bx) return 1;
92175                 if (ay < ax && by > bx) return -1;
92176               } // we have colinear segments with matching orientation
92177               // consider the one with more left-more right endpoint to be first
92178
92179
92180               if (arx > brx) return 1;
92181               if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
92182               // vertical plane, ie arx === brx
92183               // consider the lower right-endpoint to come first
92184
92185               if (ary < bry) return -1;
92186               if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
92187               // fall back on creation order as consistent tie-breaker
92188
92189               if (a.id < b.id) return -1;
92190               if (a.id > b.id) return 1; // identical segment, ie a === b
92191
92192               return 0;
92193             }
92194             /* Warning: a reference to ringWindings input will be stored,
92195              *  and possibly will be later modified */
92196
92197           }]);
92198
92199           function Segment(leftSE, rightSE, rings, windings) {
92200             _classCallCheck$1(this, Segment);
92201
92202             this.id = ++segmentId;
92203             this.leftSE = leftSE;
92204             leftSE.segment = this;
92205             leftSE.otherSE = rightSE;
92206             this.rightSE = rightSE;
92207             rightSE.segment = this;
92208             rightSE.otherSE = leftSE;
92209             this.rings = rings;
92210             this.windings = windings; // left unset for performance, set later in algorithm
92211             // this.ringOut, this.consumedBy, this.prev
92212           }
92213
92214           _createClass$1(Segment, [{
92215             key: "replaceRightSE",
92216
92217             /* When a segment is split, the rightSE is replaced with a new sweep event */
92218             value: function replaceRightSE(newRightSE) {
92219               this.rightSE = newRightSE;
92220               this.rightSE.segment = this;
92221               this.rightSE.otherSE = this.leftSE;
92222               this.leftSE.otherSE = this.rightSE;
92223             }
92224           }, {
92225             key: "bbox",
92226             value: function bbox() {
92227               var y1 = this.leftSE.point.y;
92228               var y2 = this.rightSE.point.y;
92229               return {
92230                 ll: {
92231                   x: this.leftSE.point.x,
92232                   y: y1 < y2 ? y1 : y2
92233                 },
92234                 ur: {
92235                   x: this.rightSE.point.x,
92236                   y: y1 > y2 ? y1 : y2
92237                 }
92238               };
92239             }
92240             /* A vector from the left point to the right */
92241
92242           }, {
92243             key: "vector",
92244             value: function vector() {
92245               return {
92246                 x: this.rightSE.point.x - this.leftSE.point.x,
92247                 y: this.rightSE.point.y - this.leftSE.point.y
92248               };
92249             }
92250           }, {
92251             key: "isAnEndpoint",
92252             value: function isAnEndpoint(pt) {
92253               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;
92254             }
92255             /* Compare this segment with a point.
92256              *
92257              * A point P is considered to be colinear to a segment if there
92258              * exists a distance D such that if we travel along the segment
92259              * from one * endpoint towards the other a distance D, we find
92260              * ourselves at point P.
92261              *
92262              * Return value indicates:
92263              *
92264              *   1: point lies above the segment (to the left of vertical)
92265              *   0: point is colinear to segment
92266              *  -1: point lies below the segment (to the right of vertical)
92267              */
92268
92269           }, {
92270             key: "comparePoint",
92271             value: function comparePoint(point) {
92272               if (this.isAnEndpoint(point)) return 0;
92273               var lPt = this.leftSE.point;
92274               var rPt = this.rightSE.point;
92275               var v = this.vector(); // Exactly vertical segments.
92276
92277               if (lPt.x === rPt.x) {
92278                 if (point.x === lPt.x) return 0;
92279                 return point.x < lPt.x ? 1 : -1;
92280               } // Nearly vertical segments with an intersection.
92281               // Check to see where a point on the line with matching Y coordinate is.
92282
92283
92284               var yDist = (point.y - lPt.y) / v.y;
92285               var xFromYDist = lPt.x + yDist * v.x;
92286               if (point.x === xFromYDist) return 0; // General case.
92287               // Check to see where a point on the line with matching X coordinate is.
92288
92289               var xDist = (point.x - lPt.x) / v.x;
92290               var yFromXDist = lPt.y + xDist * v.y;
92291               if (point.y === yFromXDist) return 0;
92292               return point.y < yFromXDist ? -1 : 1;
92293             }
92294             /**
92295              * Given another segment, returns the first non-trivial intersection
92296              * between the two segments (in terms of sweep line ordering), if it exists.
92297              *
92298              * A 'non-trivial' intersection is one that will cause one or both of the
92299              * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
92300              *
92301              *   * endpoint of segA with endpoint of segB --> trivial
92302              *   * endpoint of segA with point along segB --> non-trivial
92303              *   * endpoint of segB with point along segA --> non-trivial
92304              *   * point along segA with point along segB --> non-trivial
92305              *
92306              * If no non-trivial intersection exists, return null
92307              * Else, return null.
92308              */
92309
92310           }, {
92311             key: "getIntersection",
92312             value: function getIntersection(other) {
92313               // If bboxes don't overlap, there can't be any intersections
92314               var tBbox = this.bbox();
92315               var oBbox = other.bbox();
92316               var bboxOverlap = getBboxOverlap(tBbox, oBbox);
92317               if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
92318               // This will 'snap' intersections to endpoints if possible, and will
92319               // handle cases of colinearity.
92320
92321               var tlp = this.leftSE.point;
92322               var trp = this.rightSE.point;
92323               var olp = other.leftSE.point;
92324               var orp = other.rightSE.point; // does each endpoint touch the other segment?
92325               // note that we restrict the 'touching' definition to only allow segments
92326               // to touch endpoints that lie forward from where we are in the sweep line pass
92327
92328               var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
92329               var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
92330               var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
92331               var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
92332
92333               if (touchesThisLSE && touchesOtherLSE) {
92334                 // these two cases are for colinear segments with matching left
92335                 // endpoints, and one segment being longer than the other
92336                 if (touchesThisRSE && !touchesOtherRSE) return trp;
92337                 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
92338                 // or just on their left endpoint (one trivial intersection
92339
92340                 return null;
92341               } // does this left endpoint matches (other doesn't)
92342
92343
92344               if (touchesThisLSE) {
92345                 // check for segments that just intersect on opposing endpoints
92346                 if (touchesOtherRSE) {
92347                   if (tlp.x === orp.x && tlp.y === orp.y) return null;
92348                 } // t-intersection on left endpoint
92349
92350
92351                 return tlp;
92352               } // does other left endpoint matches (this doesn't)
92353
92354
92355               if (touchesOtherLSE) {
92356                 // check for segments that just intersect on opposing endpoints
92357                 if (touchesThisRSE) {
92358                   if (trp.x === olp.x && trp.y === olp.y) return null;
92359                 } // t-intersection on left endpoint
92360
92361
92362                 return olp;
92363               } // trivial intersection on right endpoints
92364
92365
92366               if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
92367
92368               if (touchesThisRSE) return trp;
92369               if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
92370               // infinite lines laid over the segments
92371
92372               var pt = intersection$1(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
92373               // they would have an endpoint intersection and that case was already handled above
92374
92375               if (pt === null) return null; // is the intersection found between the lines not on the segments?
92376
92377               if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
92378
92379               return rounder.round(pt.x, pt.y);
92380             }
92381             /**
92382              * Split the given segment into multiple segments on the given points.
92383              *  * Each existing segment will retain its leftSE and a new rightSE will be
92384              *    generated for it.
92385              *  * A new segment will be generated which will adopt the original segment's
92386              *    rightSE, and a new leftSE will be generated for it.
92387              *  * If there are more than two points given to split on, new segments
92388              *    in the middle will be generated with new leftSE and rightSE's.
92389              *  * An array of the newly generated SweepEvents will be returned.
92390              *
92391              * Warning: input array of points is modified
92392              */
92393
92394           }, {
92395             key: "split",
92396             value: function split(point) {
92397               var newEvents = [];
92398               var alreadyLinked = point.events !== undefined;
92399               var newLeftSE = new SweepEvent$1(point, true);
92400               var newRightSE = new SweepEvent$1(point, false);
92401               var oldRightSE = this.rightSE;
92402               this.replaceRightSE(newRightSE);
92403               newEvents.push(newRightSE);
92404               newEvents.push(newLeftSE);
92405               var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
92406               // sometimes one of the resulting new segments is vertical, in which
92407               // case its left and right events may need to be swapped
92408
92409               if (SweepEvent$1.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
92410                 newSeg.swapEvents();
92411               }
92412
92413               if (SweepEvent$1.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
92414                 this.swapEvents();
92415               } // in the point we just used to create new sweep events with was already
92416               // linked to other events, we need to check if either of the affected
92417               // segments should be consumed
92418
92419
92420               if (alreadyLinked) {
92421                 newLeftSE.checkForConsuming();
92422                 newRightSE.checkForConsuming();
92423               }
92424
92425               return newEvents;
92426             }
92427             /* Swap which event is left and right */
92428
92429           }, {
92430             key: "swapEvents",
92431             value: function swapEvents() {
92432               var tmpEvt = this.rightSE;
92433               this.rightSE = this.leftSE;
92434               this.leftSE = tmpEvt;
92435               this.leftSE.isLeft = true;
92436               this.rightSE.isLeft = false;
92437
92438               for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
92439                 this.windings[i] *= -1;
92440               }
92441             }
92442             /* Consume another segment. We take their rings under our wing
92443              * and mark them as consumed. Use for perfectly overlapping segments */
92444
92445           }, {
92446             key: "consume",
92447             value: function consume(other) {
92448               var consumer = this;
92449               var consumee = other;
92450
92451               while (consumer.consumedBy) {
92452                 consumer = consumer.consumedBy;
92453               }
92454
92455               while (consumee.consumedBy) {
92456                 consumee = consumee.consumedBy;
92457               }
92458
92459               var cmp = Segment.compare(consumer, consumee);
92460               if (cmp === 0) return; // already consumed
92461               // the winner of the consumption is the earlier segment
92462               // according to sweep line ordering
92463
92464               if (cmp > 0) {
92465                 var tmp = consumer;
92466                 consumer = consumee;
92467                 consumee = tmp;
92468               } // make sure a segment doesn't consume it's prev
92469
92470
92471               if (consumer.prev === consumee) {
92472                 var _tmp = consumer;
92473                 consumer = consumee;
92474                 consumee = _tmp;
92475               }
92476
92477               for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
92478                 var ring = consumee.rings[i];
92479                 var winding = consumee.windings[i];
92480                 var index = consumer.rings.indexOf(ring);
92481
92482                 if (index === -1) {
92483                   consumer.rings.push(ring);
92484                   consumer.windings.push(winding);
92485                 } else consumer.windings[index] += winding;
92486               }
92487
92488               consumee.rings = null;
92489               consumee.windings = null;
92490               consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
92491
92492               consumee.leftSE.consumedBy = consumer.leftSE;
92493               consumee.rightSE.consumedBy = consumer.rightSE;
92494             }
92495             /* The first segment previous segment chain that is in the result */
92496
92497           }, {
92498             key: "prevInResult",
92499             value: function prevInResult() {
92500               if (this._prevInResult !== undefined) return this._prevInResult;
92501               if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
92502               return this._prevInResult;
92503             }
92504           }, {
92505             key: "beforeState",
92506             value: function beforeState() {
92507               if (this._beforeState !== undefined) return this._beforeState;
92508               if (!this.prev) this._beforeState = {
92509                 rings: [],
92510                 windings: [],
92511                 multiPolys: []
92512               };else {
92513                 var seg = this.prev.consumedBy || this.prev;
92514                 this._beforeState = seg.afterState();
92515               }
92516               return this._beforeState;
92517             }
92518           }, {
92519             key: "afterState",
92520             value: function afterState() {
92521               if (this._afterState !== undefined) return this._afterState;
92522               var beforeState = this.beforeState();
92523               this._afterState = {
92524                 rings: beforeState.rings.slice(0),
92525                 windings: beforeState.windings.slice(0),
92526                 multiPolys: []
92527               };
92528               var ringsAfter = this._afterState.rings;
92529               var windingsAfter = this._afterState.windings;
92530               var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
92531
92532               for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
92533                 var ring = this.rings[i];
92534                 var winding = this.windings[i];
92535                 var index = ringsAfter.indexOf(ring);
92536
92537                 if (index === -1) {
92538                   ringsAfter.push(ring);
92539                   windingsAfter.push(winding);
92540                 } else windingsAfter[index] += winding;
92541               } // calcualte polysAfter
92542
92543
92544               var polysAfter = [];
92545               var polysExclude = [];
92546
92547               for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
92548                 if (windingsAfter[_i] === 0) continue; // non-zero rule
92549
92550                 var _ring = ringsAfter[_i];
92551                 var poly = _ring.poly;
92552                 if (polysExclude.indexOf(poly) !== -1) continue;
92553                 if (_ring.isExterior) polysAfter.push(poly);else {
92554                   if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
92555
92556                   var _index = polysAfter.indexOf(_ring.poly);
92557
92558                   if (_index !== -1) polysAfter.splice(_index, 1);
92559                 }
92560               } // calculate multiPolysAfter
92561
92562
92563               for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
92564                 var mp = polysAfter[_i2].multiPoly;
92565                 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
92566               }
92567
92568               return this._afterState;
92569             }
92570             /* Is this segment part of the final result? */
92571
92572           }, {
92573             key: "isInResult",
92574             value: function isInResult() {
92575               // if we've been consumed, we're not in the result
92576               if (this.consumedBy) return false;
92577               if (this._isInResult !== undefined) return this._isInResult;
92578               var mpsBefore = this.beforeState().multiPolys;
92579               var mpsAfter = this.afterState().multiPolys;
92580
92581               switch (operation.type) {
92582                 case 'union':
92583                   {
92584                     // UNION - included iff:
92585                     //  * On one side of us there is 0 poly interiors AND
92586                     //  * On the other side there is 1 or more.
92587                     var noBefores = mpsBefore.length === 0;
92588                     var noAfters = mpsAfter.length === 0;
92589                     this._isInResult = noBefores !== noAfters;
92590                     break;
92591                   }
92592
92593                 case 'intersection':
92594                   {
92595                     // INTERSECTION - included iff:
92596                     //  * on one side of us all multipolys are rep. with poly interiors AND
92597                     //  * on the other side of us, not all multipolys are repsented
92598                     //    with poly interiors
92599                     var least;
92600                     var most;
92601
92602                     if (mpsBefore.length < mpsAfter.length) {
92603                       least = mpsBefore.length;
92604                       most = mpsAfter.length;
92605                     } else {
92606                       least = mpsAfter.length;
92607                       most = mpsBefore.length;
92608                     }
92609
92610                     this._isInResult = most === operation.numMultiPolys && least < most;
92611                     break;
92612                   }
92613
92614                 case 'xor':
92615                   {
92616                     // XOR - included iff:
92617                     //  * the difference between the number of multipolys represented
92618                     //    with poly interiors on our two sides is an odd number
92619                     var diff = Math.abs(mpsBefore.length - mpsAfter.length);
92620                     this._isInResult = diff % 2 === 1;
92621                     break;
92622                   }
92623
92624                 case 'difference':
92625                   {
92626                     // DIFFERENCE included iff:
92627                     //  * on exactly one side, we have just the subject
92628                     var isJustSubject = function isJustSubject(mps) {
92629                       return mps.length === 1 && mps[0].isSubject;
92630                     };
92631
92632                     this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
92633                     break;
92634                   }
92635
92636                 default:
92637                   throw new Error("Unrecognized operation type found ".concat(operation.type));
92638               }
92639
92640               return this._isInResult;
92641             }
92642           }], [{
92643             key: "fromRing",
92644             value: function fromRing(pt1, pt2, ring) {
92645               var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
92646
92647               var cmpPts = SweepEvent$1.comparePoints(pt1, pt2);
92648
92649               if (cmpPts < 0) {
92650                 leftPt = pt1;
92651                 rightPt = pt2;
92652                 winding = 1;
92653               } else if (cmpPts > 0) {
92654                 leftPt = pt2;
92655                 rightPt = pt1;
92656                 winding = -1;
92657               } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
92658
92659               var leftSE = new SweepEvent$1(leftPt, true);
92660               var rightSE = new SweepEvent$1(rightPt, false);
92661               return new Segment(leftSE, rightSE, [ring], [winding]);
92662             }
92663           }]);
92664
92665           return Segment;
92666         }();
92667
92668         var RingIn = /*#__PURE__*/function () {
92669           function RingIn(geomRing, poly, isExterior) {
92670             _classCallCheck$1(this, RingIn);
92671
92672             if (!Array.isArray(geomRing) || geomRing.length === 0) {
92673               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
92674             }
92675
92676             this.poly = poly;
92677             this.isExterior = isExterior;
92678             this.segments = [];
92679
92680             if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
92681               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
92682             }
92683
92684             var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
92685             this.bbox = {
92686               ll: {
92687                 x: firstPoint.x,
92688                 y: firstPoint.y
92689               },
92690               ur: {
92691                 x: firstPoint.x,
92692                 y: firstPoint.y
92693               }
92694             };
92695             var prevPoint = firstPoint;
92696
92697             for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
92698               if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
92699                 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
92700               }
92701
92702               var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
92703
92704               if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
92705               this.segments.push(Segment.fromRing(prevPoint, point, this));
92706               if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
92707               if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
92708               if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
92709               if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
92710               prevPoint = point;
92711             } // add segment from last to first if last is not the same as first
92712
92713
92714             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
92715               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
92716             }
92717           }
92718
92719           _createClass$1(RingIn, [{
92720             key: "getSweepEvents",
92721             value: function getSweepEvents() {
92722               var sweepEvents = [];
92723
92724               for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
92725                 var segment = this.segments[i];
92726                 sweepEvents.push(segment.leftSE);
92727                 sweepEvents.push(segment.rightSE);
92728               }
92729
92730               return sweepEvents;
92731             }
92732           }]);
92733
92734           return RingIn;
92735         }();
92736
92737         var PolyIn = /*#__PURE__*/function () {
92738           function PolyIn(geomPoly, multiPoly) {
92739             _classCallCheck$1(this, PolyIn);
92740
92741             if (!Array.isArray(geomPoly)) {
92742               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
92743             }
92744
92745             this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
92746
92747             this.bbox = {
92748               ll: {
92749                 x: this.exteriorRing.bbox.ll.x,
92750                 y: this.exteriorRing.bbox.ll.y
92751               },
92752               ur: {
92753                 x: this.exteriorRing.bbox.ur.x,
92754                 y: this.exteriorRing.bbox.ur.y
92755               }
92756             };
92757             this.interiorRings = [];
92758
92759             for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
92760               var ring = new RingIn(geomPoly[i], this, false);
92761               if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
92762               if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
92763               if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
92764               if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
92765               this.interiorRings.push(ring);
92766             }
92767
92768             this.multiPoly = multiPoly;
92769           }
92770
92771           _createClass$1(PolyIn, [{
92772             key: "getSweepEvents",
92773             value: function getSweepEvents() {
92774               var sweepEvents = this.exteriorRing.getSweepEvents();
92775
92776               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
92777                 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
92778
92779                 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
92780                   sweepEvents.push(ringSweepEvents[j]);
92781                 }
92782               }
92783
92784               return sweepEvents;
92785             }
92786           }]);
92787
92788           return PolyIn;
92789         }();
92790
92791         var MultiPolyIn = /*#__PURE__*/function () {
92792           function MultiPolyIn(geom, isSubject) {
92793             _classCallCheck$1(this, MultiPolyIn);
92794
92795             if (!Array.isArray(geom)) {
92796               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
92797             }
92798
92799             try {
92800               // if the input looks like a polygon, convert it to a multipolygon
92801               if (typeof geom[0][0][0] === 'number') geom = [geom];
92802             } catch (ex) {// The input is either malformed or has empty arrays.
92803               // In either case, it will be handled later on.
92804             }
92805
92806             this.polys = [];
92807             this.bbox = {
92808               ll: {
92809                 x: Number.POSITIVE_INFINITY,
92810                 y: Number.POSITIVE_INFINITY
92811               },
92812               ur: {
92813                 x: Number.NEGATIVE_INFINITY,
92814                 y: Number.NEGATIVE_INFINITY
92815               }
92816             };
92817
92818             for (var i = 0, iMax = geom.length; i < iMax; i++) {
92819               var poly = new PolyIn(geom[i], this);
92820               if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
92821               if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
92822               if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
92823               if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
92824               this.polys.push(poly);
92825             }
92826
92827             this.isSubject = isSubject;
92828           }
92829
92830           _createClass$1(MultiPolyIn, [{
92831             key: "getSweepEvents",
92832             value: function getSweepEvents() {
92833               var sweepEvents = [];
92834
92835               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
92836                 var polySweepEvents = this.polys[i].getSweepEvents();
92837
92838                 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
92839                   sweepEvents.push(polySweepEvents[j]);
92840                 }
92841               }
92842
92843               return sweepEvents;
92844             }
92845           }]);
92846
92847           return MultiPolyIn;
92848         }();
92849
92850         var RingOut = /*#__PURE__*/function () {
92851           _createClass$1(RingOut, null, [{
92852             key: "factory",
92853
92854             /* Given the segments from the sweep line pass, compute & return a series
92855              * of closed rings from all the segments marked to be part of the result */
92856             value: function factory(allSegments) {
92857               var ringsOut = [];
92858
92859               for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
92860                 var segment = allSegments[i];
92861                 if (!segment.isInResult() || segment.ringOut) continue;
92862                 var prevEvent = null;
92863                 var event = segment.leftSE;
92864                 var nextEvent = segment.rightSE;
92865                 var events = [event];
92866                 var startingPoint = event.point;
92867                 var intersectionLEs = [];
92868                 /* Walk the chain of linked events to form a closed ring */
92869
92870                 while (true) {
92871                   prevEvent = event;
92872                   event = nextEvent;
92873                   events.push(event);
92874                   /* Is the ring complete? */
92875
92876                   if (event.point === startingPoint) break;
92877
92878                   while (true) {
92879                     var availableLEs = event.getAvailableLinkedEvents();
92880                     /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
92881                      * part of the algorithm malfunctioned... please file a bug report. */
92882
92883                     if (availableLEs.length === 0) {
92884                       var firstPt = events[0].point;
92885                       var lastPt = events[events.length - 1].point;
92886                       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, "]."));
92887                     }
92888                     /* Only one way to go, so cotinue on the path */
92889
92890
92891                     if (availableLEs.length === 1) {
92892                       nextEvent = availableLEs[0].otherSE;
92893                       break;
92894                     }
92895                     /* We must have an intersection. Check for a completed loop */
92896
92897
92898                     var indexLE = null;
92899
92900                     for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
92901                       if (intersectionLEs[j].point === event.point) {
92902                         indexLE = j;
92903                         break;
92904                       }
92905                     }
92906                     /* Found a completed loop. Cut that off and make a ring */
92907
92908
92909                     if (indexLE !== null) {
92910                       var intersectionLE = intersectionLEs.splice(indexLE)[0];
92911                       var ringEvents = events.splice(intersectionLE.index);
92912                       ringEvents.unshift(ringEvents[0].otherSE);
92913                       ringsOut.push(new RingOut(ringEvents.reverse()));
92914                       continue;
92915                     }
92916                     /* register the intersection */
92917
92918
92919                     intersectionLEs.push({
92920                       index: events.length,
92921                       point: event.point
92922                     });
92923                     /* Choose the left-most option to continue the walk */
92924
92925                     var comparator = event.getLeftmostComparator(prevEvent);
92926                     nextEvent = availableLEs.sort(comparator)[0].otherSE;
92927                     break;
92928                   }
92929                 }
92930
92931                 ringsOut.push(new RingOut(events));
92932               }
92933
92934               return ringsOut;
92935             }
92936           }]);
92937
92938           function RingOut(events) {
92939             _classCallCheck$1(this, RingOut);
92940
92941             this.events = events;
92942
92943             for (var i = 0, iMax = events.length; i < iMax; i++) {
92944               events[i].segment.ringOut = this;
92945             }
92946
92947             this.poly = null;
92948           }
92949
92950           _createClass$1(RingOut, [{
92951             key: "getGeom",
92952             value: function getGeom() {
92953               // Remove superfluous points (ie extra points along a straight line),
92954               var prevPt = this.events[0].point;
92955               var points = [prevPt];
92956
92957               for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
92958                 var _pt = this.events[i].point;
92959                 var _nextPt = this.events[i + 1].point;
92960                 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
92961                 points.push(_pt);
92962                 prevPt = _pt;
92963               } // ring was all (within rounding error of angle calc) colinear points
92964
92965
92966               if (points.length === 1) return null; // check if the starting point is necessary
92967
92968               var pt = points[0];
92969               var nextPt = points[1];
92970               if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
92971               points.push(points[0]);
92972               var step = this.isExteriorRing() ? 1 : -1;
92973               var iStart = this.isExteriorRing() ? 0 : points.length - 1;
92974               var iEnd = this.isExteriorRing() ? points.length : -1;
92975               var orderedPoints = [];
92976
92977               for (var _i = iStart; _i != iEnd; _i += step) {
92978                 orderedPoints.push([points[_i].x, points[_i].y]);
92979               }
92980
92981               return orderedPoints;
92982             }
92983           }, {
92984             key: "isExteriorRing",
92985             value: function isExteriorRing() {
92986               if (this._isExteriorRing === undefined) {
92987                 var enclosing = this.enclosingRing();
92988                 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
92989               }
92990
92991               return this._isExteriorRing;
92992             }
92993           }, {
92994             key: "enclosingRing",
92995             value: function enclosingRing() {
92996               if (this._enclosingRing === undefined) {
92997                 this._enclosingRing = this._calcEnclosingRing();
92998               }
92999
93000               return this._enclosingRing;
93001             }
93002             /* Returns the ring that encloses this one, if any */
93003
93004           }, {
93005             key: "_calcEnclosingRing",
93006             value: function _calcEnclosingRing() {
93007               // start with the ealier sweep line event so that the prevSeg
93008               // chain doesn't lead us inside of a loop of ours
93009               var leftMostEvt = this.events[0];
93010
93011               for (var i = 1, iMax = this.events.length; i < iMax; i++) {
93012                 var evt = this.events[i];
93013                 if (SweepEvent$1.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
93014               }
93015
93016               var prevSeg = leftMostEvt.segment.prevInResult();
93017               var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93018
93019               while (true) {
93020                 // no segment found, thus no ring can enclose us
93021                 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
93022                 // segment must loop back around and enclose us
93023
93024                 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
93025                 // segment must either loop around us or the ring of the prev prev
93026                 // seg, which would make us and the ring of the prev peers
93027
93028                 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
93029                   if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
93030                     return prevSeg.ringOut;
93031                   } else return prevSeg.ringOut.enclosingRing();
93032                 } // two segments are from the same ring, so this was a penisula
93033                 // of that ring. iterate downward, keep searching
93034
93035
93036                 prevSeg = prevPrevSeg.prevInResult();
93037                 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93038               }
93039             }
93040           }]);
93041
93042           return RingOut;
93043         }();
93044
93045         var PolyOut = /*#__PURE__*/function () {
93046           function PolyOut(exteriorRing) {
93047             _classCallCheck$1(this, PolyOut);
93048
93049             this.exteriorRing = exteriorRing;
93050             exteriorRing.poly = this;
93051             this.interiorRings = [];
93052           }
93053
93054           _createClass$1(PolyOut, [{
93055             key: "addInterior",
93056             value: function addInterior(ring) {
93057               this.interiorRings.push(ring);
93058               ring.poly = this;
93059             }
93060           }, {
93061             key: "getGeom",
93062             value: function getGeom() {
93063               var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
93064
93065               if (geom[0] === null) return null;
93066
93067               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93068                 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
93069
93070                 if (ringGeom === null) continue;
93071                 geom.push(ringGeom);
93072               }
93073
93074               return geom;
93075             }
93076           }]);
93077
93078           return PolyOut;
93079         }();
93080
93081         var MultiPolyOut = /*#__PURE__*/function () {
93082           function MultiPolyOut(rings) {
93083             _classCallCheck$1(this, MultiPolyOut);
93084
93085             this.rings = rings;
93086             this.polys = this._composePolys(rings);
93087           }
93088
93089           _createClass$1(MultiPolyOut, [{
93090             key: "getGeom",
93091             value: function getGeom() {
93092               var geom = [];
93093
93094               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93095                 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
93096
93097                 if (polyGeom === null) continue;
93098                 geom.push(polyGeom);
93099               }
93100
93101               return geom;
93102             }
93103           }, {
93104             key: "_composePolys",
93105             value: function _composePolys(rings) {
93106               var polys = [];
93107
93108               for (var i = 0, iMax = rings.length; i < iMax; i++) {
93109                 var ring = rings[i];
93110                 if (ring.poly) continue;
93111                 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
93112                   var enclosingRing = ring.enclosingRing();
93113                   if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
93114                   enclosingRing.poly.addInterior(ring);
93115                 }
93116               }
93117
93118               return polys;
93119             }
93120           }]);
93121
93122           return MultiPolyOut;
93123         }();
93124         /**
93125          * NOTE:  We must be careful not to change any segments while
93126          *        they are in the SplayTree. AFAIK, there's no way to tell
93127          *        the tree to rebalance itself - thus before splitting
93128          *        a segment that's in the tree, we remove it from the tree,
93129          *        do the split, then re-insert it. (Even though splitting a
93130          *        segment *shouldn't* change its correct position in the
93131          *        sweep line tree, the reality is because of rounding errors,
93132          *        it sometimes does.)
93133          */
93134
93135
93136         var SweepLine = /*#__PURE__*/function () {
93137           function SweepLine(queue) {
93138             var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
93139
93140             _classCallCheck$1(this, SweepLine);
93141
93142             this.queue = queue;
93143             this.tree = new Tree(comparator);
93144             this.segments = [];
93145           }
93146
93147           _createClass$1(SweepLine, [{
93148             key: "process",
93149             value: function process(event) {
93150               var segment = event.segment;
93151               var newEvents = []; // if we've already been consumed by another segment,
93152               // clean up our body parts and get out
93153
93154               if (event.consumedBy) {
93155                 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
93156                 return newEvents;
93157               }
93158
93159               var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
93160               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.');
93161               var prevNode = node;
93162               var nextNode = node;
93163               var prevSeg = undefined;
93164               var nextSeg = undefined; // skip consumed segments still in tree
93165
93166               while (prevSeg === undefined) {
93167                 prevNode = this.tree.prev(prevNode);
93168                 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
93169               } // skip consumed segments still in tree
93170
93171
93172               while (nextSeg === undefined) {
93173                 nextNode = this.tree.next(nextNode);
93174                 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
93175               }
93176
93177               if (event.isLeft) {
93178                 // Check for intersections against the previous segment in the sweep line
93179                 var prevMySplitter = null;
93180
93181                 if (prevSeg) {
93182                   var prevInter = prevSeg.getIntersection(segment);
93183
93184                   if (prevInter !== null) {
93185                     if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
93186
93187                     if (!prevSeg.isAnEndpoint(prevInter)) {
93188                       var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
93189
93190                       for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
93191                         newEvents.push(newEventsFromSplit[i]);
93192                       }
93193                     }
93194                   }
93195                 } // Check for intersections against the next segment in the sweep line
93196
93197
93198                 var nextMySplitter = null;
93199
93200                 if (nextSeg) {
93201                   var nextInter = nextSeg.getIntersection(segment);
93202
93203                   if (nextInter !== null) {
93204                     if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
93205
93206                     if (!nextSeg.isAnEndpoint(nextInter)) {
93207                       var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
93208
93209                       for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
93210                         newEvents.push(_newEventsFromSplit[_i]);
93211                       }
93212                     }
93213                   }
93214                 } // For simplicity, even if we find more than one intersection we only
93215                 // spilt on the 'earliest' (sweep-line style) of the intersections.
93216                 // The other intersection will be handled in a future process().
93217
93218
93219                 if (prevMySplitter !== null || nextMySplitter !== null) {
93220                   var mySplitter = null;
93221                   if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
93222                     var cmpSplitters = SweepEvent$1.comparePoints(prevMySplitter, nextMySplitter);
93223                     mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
93224                   } // Rounding errors can cause changes in ordering,
93225                   // so remove afected segments and right sweep events before splitting
93226
93227                   this.queue.remove(segment.rightSE);
93228                   newEvents.push(segment.rightSE);
93229
93230                   var _newEventsFromSplit2 = segment.split(mySplitter);
93231
93232                   for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
93233                     newEvents.push(_newEventsFromSplit2[_i2]);
93234                   }
93235                 }
93236
93237                 if (newEvents.length > 0) {
93238                   // We found some intersections, so re-do the current event to
93239                   // make sure sweep line ordering is totally consistent for later
93240                   // use with the segment 'prev' pointers
93241                   this.tree.remove(segment);
93242                   newEvents.push(event);
93243                 } else {
93244                   // done with left event
93245                   this.segments.push(segment);
93246                   segment.prev = prevSeg;
93247                 }
93248               } else {
93249                 // event.isRight
93250                 // since we're about to be removed from the sweep line, check for
93251                 // intersections between our previous and next segments
93252                 if (prevSeg && nextSeg) {
93253                   var inter = prevSeg.getIntersection(nextSeg);
93254
93255                   if (inter !== null) {
93256                     if (!prevSeg.isAnEndpoint(inter)) {
93257                       var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
93258
93259                       for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
93260                         newEvents.push(_newEventsFromSplit3[_i3]);
93261                       }
93262                     }
93263
93264                     if (!nextSeg.isAnEndpoint(inter)) {
93265                       var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
93266
93267                       for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
93268                         newEvents.push(_newEventsFromSplit4[_i4]);
93269                       }
93270                     }
93271                   }
93272                 }
93273
93274                 this.tree.remove(segment);
93275               }
93276
93277               return newEvents;
93278             }
93279             /* Safely split a segment that is currently in the datastructures
93280              * IE - a segment other than the one that is currently being processed. */
93281
93282           }, {
93283             key: "_splitSafely",
93284             value: function _splitSafely(seg, pt) {
93285               // Rounding errors can cause changes in ordering,
93286               // so remove afected segments and right sweep events before splitting
93287               // removeNode() doesn't work, so have re-find the seg
93288               // https://github.com/w8r/splay-tree/pull/5
93289               this.tree.remove(seg);
93290               var rightSE = seg.rightSE;
93291               this.queue.remove(rightSE);
93292               var newEvents = seg.split(pt);
93293               newEvents.push(rightSE); // splitting can trigger consumption
93294
93295               if (seg.consumedBy === undefined) this.tree.insert(seg);
93296               return newEvents;
93297             }
93298           }]);
93299
93300           return SweepLine;
93301         }();
93302
93303         var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
93304         var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
93305
93306         var Operation = /*#__PURE__*/function () {
93307           function Operation() {
93308             _classCallCheck$1(this, Operation);
93309           }
93310
93311           _createClass$1(Operation, [{
93312             key: "run",
93313             value: function run(type, geom, moreGeoms) {
93314               operation.type = type;
93315               rounder.reset();
93316               /* Convert inputs to MultiPoly objects */
93317
93318               var multipolys = [new MultiPolyIn(geom, true)];
93319
93320               for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
93321                 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
93322               }
93323
93324               operation.numMultiPolys = multipolys.length;
93325               /* BBox optimization for difference operation
93326                * If the bbox of a multipolygon that's part of the clipping doesn't
93327                * intersect the bbox of the subject at all, we can just drop that
93328                * multiploygon. */
93329
93330               if (operation.type === 'difference') {
93331                 // in place removal
93332                 var subject = multipolys[0];
93333                 var _i = 1;
93334
93335                 while (_i < multipolys.length) {
93336                   if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
93337                 }
93338               }
93339               /* BBox optimization for intersection operation
93340                * If we can find any pair of multipolygons whose bbox does not overlap,
93341                * then the result will be empty. */
93342
93343
93344               if (operation.type === 'intersection') {
93345                 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
93346                 //       it could be optimized to O(n * ln(n))
93347                 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
93348                   var mpA = multipolys[_i2];
93349
93350                   for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
93351                     if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
93352                   }
93353                 }
93354               }
93355               /* Put segment endpoints in a priority queue */
93356
93357
93358               var queue = new Tree(SweepEvent$1.compare);
93359
93360               for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
93361                 var sweepEvents = multipolys[_i3].getSweepEvents();
93362
93363                 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
93364                   queue.insert(sweepEvents[_j]);
93365
93366                   if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
93367                     // prevents an infinite loop, an otherwise common manifestation of bugs
93368                     throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
93369                   }
93370                 }
93371               }
93372               /* Pass the sweep line over those endpoints */
93373
93374
93375               var sweepLine = new SweepLine(queue);
93376               var prevQueueSize = queue.size;
93377               var node = queue.pop();
93378
93379               while (node) {
93380                 var evt = node.key;
93381
93382                 if (queue.size === prevQueueSize) {
93383                   // prevents an infinite loop, an otherwise common manifestation of bugs
93384                   var seg = evt.segment;
93385                   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.');
93386                 }
93387
93388                 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
93389                   // prevents an infinite loop, an otherwise common manifestation of bugs
93390                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
93391                 }
93392
93393                 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
93394                   // prevents an infinite loop, an otherwise common manifestation of bugs
93395                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
93396                 }
93397
93398                 var newEvents = sweepLine.process(evt);
93399
93400                 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
93401                   var _evt = newEvents[_i4];
93402                   if (_evt.consumedBy === undefined) queue.insert(_evt);
93403                 }
93404
93405                 prevQueueSize = queue.size;
93406                 node = queue.pop();
93407               } // free some memory we don't need anymore
93408
93409
93410               rounder.reset();
93411               /* Collect and compile segments we're keeping into a multipolygon */
93412
93413               var ringsOut = RingOut.factory(sweepLine.segments);
93414               var result = new MultiPolyOut(ringsOut);
93415               return result.getGeom();
93416             }
93417           }]);
93418
93419           return Operation;
93420         }(); // singleton available by import
93421
93422
93423         var operation = new Operation();
93424
93425         var union$1 = function union(geom) {
93426           for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
93427             moreGeoms[_key - 1] = arguments[_key];
93428           }
93429
93430           return operation.run('union', geom, moreGeoms);
93431         };
93432
93433         var intersection$1$1 = function intersection(geom) {
93434           for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
93435             moreGeoms[_key2 - 1] = arguments[_key2];
93436           }
93437
93438           return operation.run('intersection', geom, moreGeoms);
93439         };
93440
93441         var xor = function xor(geom) {
93442           for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
93443             moreGeoms[_key3 - 1] = arguments[_key3];
93444           }
93445
93446           return operation.run('xor', geom, moreGeoms);
93447         };
93448
93449         var difference = function difference(subjectGeom) {
93450           for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
93451             clippingGeoms[_key4 - 1] = arguments[_key4];
93452           }
93453
93454           return operation.run('difference', subjectGeom, clippingGeoms);
93455         };
93456
93457         var index$1 = {
93458           union: union$1,
93459           intersection: intersection$1$1,
93460           xor: xor,
93461           difference: difference
93462         };
93463
93464         var geojsonPrecision = createCommonjsModule(function (module) {
93465           (function () {
93466             function parse(t, coordinatePrecision, extrasPrecision) {
93467               function point(p) {
93468                 return p.map(function (e, index) {
93469                   if (index < 2) {
93470                     return 1 * e.toFixed(coordinatePrecision);
93471                   } else {
93472                     return 1 * e.toFixed(extrasPrecision);
93473                   }
93474                 });
93475               }
93476
93477               function multi(l) {
93478                 return l.map(point);
93479               }
93480
93481               function poly(p) {
93482                 return p.map(multi);
93483               }
93484
93485               function multiPoly(m) {
93486                 return m.map(poly);
93487               }
93488
93489               function geometry(obj) {
93490                 if (!obj) {
93491                   return {};
93492                 }
93493
93494                 switch (obj.type) {
93495                   case "Point":
93496                     obj.coordinates = point(obj.coordinates);
93497                     return obj;
93498
93499                   case "LineString":
93500                   case "MultiPoint":
93501                     obj.coordinates = multi(obj.coordinates);
93502                     return obj;
93503
93504                   case "Polygon":
93505                   case "MultiLineString":
93506                     obj.coordinates = poly(obj.coordinates);
93507                     return obj;
93508
93509                   case "MultiPolygon":
93510                     obj.coordinates = multiPoly(obj.coordinates);
93511                     return obj;
93512
93513                   case "GeometryCollection":
93514                     obj.geometries = obj.geometries.map(geometry);
93515                     return obj;
93516
93517                   default:
93518                     return {};
93519                 }
93520               }
93521
93522               function feature(obj) {
93523                 obj.geometry = geometry(obj.geometry);
93524                 return obj;
93525               }
93526
93527               function featureCollection(f) {
93528                 f.features = f.features.map(feature);
93529                 return f;
93530               }
93531
93532               function geometryCollection(g) {
93533                 g.geometries = g.geometries.map(geometry);
93534                 return g;
93535               }
93536
93537               if (!t) {
93538                 return t;
93539               }
93540
93541               switch (t.type) {
93542                 case "Feature":
93543                   return feature(t);
93544
93545                 case "GeometryCollection":
93546                   return geometryCollection(t);
93547
93548                 case "FeatureCollection":
93549                   return featureCollection(t);
93550
93551                 case "Point":
93552                 case "LineString":
93553                 case "Polygon":
93554                 case "MultiPoint":
93555                 case "MultiPolygon":
93556                 case "MultiLineString":
93557                   return geometry(t);
93558
93559                 default:
93560                   return t;
93561               }
93562             }
93563
93564             module.exports = parse;
93565             module.exports.parse = parse;
93566           })();
93567         });
93568
93569         function isObject$4(obj) {
93570           return _typeof(obj) === 'object' && obj !== null;
93571         }
93572
93573         function forEach(obj, cb) {
93574           if (Array.isArray(obj)) {
93575             obj.forEach(cb);
93576           } else if (isObject$4(obj)) {
93577             Object.keys(obj).forEach(function (key) {
93578               var val = obj[key];
93579               cb(val, key);
93580             });
93581           }
93582         }
93583
93584         function getTreeDepth(obj) {
93585           var depth = 0;
93586
93587           if (Array.isArray(obj) || isObject$4(obj)) {
93588             forEach(obj, function (val) {
93589               if (Array.isArray(val) || isObject$4(val)) {
93590                 var tmpDepth = getTreeDepth(val);
93591
93592                 if (tmpDepth > depth) {
93593                   depth = tmpDepth;
93594                 }
93595               }
93596             });
93597             return depth + 1;
93598           }
93599
93600           return depth;
93601         }
93602
93603         function stringify(obj, options) {
93604           options = options || {};
93605           var indent = JSON.stringify([1], null, get$5(options, 'indent', 2)).slice(2, -3);
93606           var addMargin = get$5(options, 'margins', false);
93607           var addArrayMargin = get$5(options, 'arrayMargins', false);
93608           var addObjectMargin = get$5(options, 'objectMargins', false);
93609           var maxLength = indent === '' ? Infinity : get$5(options, 'maxLength', 80);
93610           var maxNesting = get$5(options, 'maxNesting', Infinity);
93611           return function _stringify(obj, currentIndent, reserved) {
93612             if (obj && typeof obj.toJSON === 'function') {
93613               obj = obj.toJSON();
93614             }
93615
93616             var string = JSON.stringify(obj);
93617
93618             if (string === undefined) {
93619               return string;
93620             }
93621
93622             var length = maxLength - currentIndent.length - reserved;
93623             var treeDepth = getTreeDepth(obj);
93624
93625             if (treeDepth <= maxNesting && string.length <= length) {
93626               var prettified = prettify(string, {
93627                 addMargin: addMargin,
93628                 addArrayMargin: addArrayMargin,
93629                 addObjectMargin: addObjectMargin
93630               });
93631
93632               if (prettified.length <= length) {
93633                 return prettified;
93634               }
93635             }
93636
93637             if (isObject$4(obj)) {
93638               var nextIndent = currentIndent + indent;
93639               var items = [];
93640               var delimiters;
93641
93642               var comma = function comma(array, index) {
93643                 return index === array.length - 1 ? 0 : 1;
93644               };
93645
93646               if (Array.isArray(obj)) {
93647                 for (var index = 0; index < obj.length; index++) {
93648                   items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
93649                 }
93650
93651                 delimiters = '[]';
93652               } else {
93653                 Object.keys(obj).forEach(function (key, index, array) {
93654                   var keyPart = JSON.stringify(key) + ': ';
93655
93656                   var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
93657
93658                   if (value !== undefined) {
93659                     items.push(keyPart + value);
93660                   }
93661                 });
93662                 delimiters = '{}';
93663               }
93664
93665               if (items.length > 0) {
93666                 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
93667               }
93668             }
93669
93670             return string;
93671           }(obj, '', 0);
93672         } // Note: This regex matches even invalid JSON strings, but since we’re
93673         // working on the output of `JSON.stringify` we know that only valid strings
93674         // are present (unless the user supplied a weird `options.indent` but in
93675         // that case we don’t care since the output would be invalid anyway).
93676
93677
93678         var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
93679
93680         function prettify(string, options) {
93681           options = options || {};
93682           var tokens = {
93683             '{': '{',
93684             '}': '}',
93685             '[': '[',
93686             ']': ']',
93687             ',': ', ',
93688             ':': ': '
93689           };
93690
93691           if (options.addMargin || options.addObjectMargin) {
93692             tokens['{'] = '{ ';
93693             tokens['}'] = ' }';
93694           }
93695
93696           if (options.addMargin || options.addArrayMargin) {
93697             tokens['['] = '[ ';
93698             tokens[']'] = ' ]';
93699           }
93700
93701           return string.replace(stringOrChar, function (match, string) {
93702             return string ? match : tokens[match];
93703           });
93704         }
93705
93706         function get$5(options, name, defaultValue) {
93707           return name in options ? options[name] : defaultValue;
93708         }
93709
93710         var jsonStringifyPrettyCompact = stringify;
93711
93712         var _default$2 = /*#__PURE__*/function () {
93713           // constructor
93714           //
93715           // `fc`  Optional FeatureCollection of known features
93716           //
93717           // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
93718           // Each feature must have a filename-like `id`, for example: `something.geojson`
93719           //
93720           // {
93721           //   "type": "FeatureCollection"
93722           //   "features": [
93723           //     {
93724           //       "type": "Feature",
93725           //       "id": "philly_metro.geojson",
93726           //       "properties": { … },
93727           //       "geometry": { … }
93728           //     }
93729           //   ]
93730           // }
93731           function _default(fc) {
93732             var _this = this;
93733
93734             _classCallCheck(this, _default);
93735
93736             // The _cache retains resolved features, so if you ask for the same thing multiple times
93737             // we don't repeat the expensive resolving/clipping operations.
93738             //
93739             // Each feature has a stable identifier that is used as the cache key.
93740             // The identifiers look like:
93741             // - for point locations, the stringified point:          e.g. '[8.67039,49.41882]'
93742             // - for geojson locations, the geojson id:               e.g. 'de-hamburg.geojson'
93743             // - for countrycoder locations, feature.id property:     e.g. 'Q2'  (countrycoder uses Wikidata identifiers)
93744             // - for aggregated locationSets, +[include]-[exclude]:   e.g '+[Q2]-[Q18,Q27611]'
93745             this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
93746             // When strict mode = false, return `null` for invalid locations or locationSets.
93747
93748             this._strict = true; // process input FeatureCollection
93749
93750             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
93751               fc.features.forEach(function (feature) {
93752                 feature.properties = feature.properties || {};
93753                 var props = feature.properties; // get `id` from either `id` or `properties`
93754
93755                 var id = feature.id || props.id;
93756                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // ensure `id` exists and is lowercase
93757
93758                 id = id.toLowerCase();
93759                 feature.id = id;
93760                 props.id = id; // ensure `area` property exists
93761
93762                 if (!props.area) {
93763                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
93764
93765                   props.area = Number(area.toFixed(2));
93766                 }
93767
93768                 _this._cache[id] = feature;
93769               });
93770             } // Replace CountryCoder world geometry to be a polygon covering the world.
93771
93772
93773             var world = _cloneDeep(feature$1('Q2'));
93774
93775             world.geometry = {
93776               type: 'Polygon',
93777               coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
93778             };
93779             world.id = 'Q2';
93780             world.properties.id = 'Q2';
93781             world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
93782
93783             this._cache.Q2 = world;
93784           } // validateLocation
93785           // `location`  The location to validate
93786           //
93787           // Pass a `location` value to validate
93788           //
93789           // Returns a result like:
93790           //   {
93791           //     type:     'point', 'geojson', or 'countrycoder'
93792           //     location:  the queried location
93793           //     id:        the stable identifier for the feature
93794           //   }
93795           // or `null` if the location is invalid
93796           //
93797
93798
93799           _createClass(_default, [{
93800             key: "validateLocation",
93801             value: function validateLocation(location) {
93802               if (Array.isArray(location)) {
93803                 // a [lon,lat] coordinate pair?
93804                 if (location.length === 2 && Number.isFinite(location[0]) && Number.isFinite(location[1]) && location[0] >= -180 && location[0] <= 180 && location[1] >= -90 && location[1] <= 90) {
93805                   var id = '[' + location.toString() + ']';
93806                   return {
93807                     type: 'point',
93808                     location: location,
93809                     id: id
93810                   };
93811                 }
93812               } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
93813                 // a .geojson filename?
93814                 var _id = location.toLowerCase();
93815
93816                 if (this._cache[_id]) {
93817                   return {
93818                     type: 'geojson',
93819                     location: location,
93820                     id: _id
93821                   };
93822                 }
93823               } else if (typeof location === 'string' || typeof location === 'number') {
93824                 // a country-coder value?
93825                 var feature = feature$1(location);
93826
93827                 if (feature) {
93828                   // Use wikidata QID as the identifier, since that seems to be the one
93829                   // property that everything in CountryCoder is guaranteed to have.
93830                   var _id2 = feature.properties.wikidata;
93831                   return {
93832                     type: 'countrycoder',
93833                     location: location,
93834                     id: _id2
93835                   };
93836                 }
93837               }
93838
93839               if (this._strict) {
93840                 throw new Error("validateLocation:  Invalid location: \"".concat(location, "\"."));
93841               } else {
93842                 return null;
93843               }
93844             } // resolveLocation
93845             // `location`  The location to resolve
93846             //
93847             // Pass a `location` value to resolve
93848             //
93849             // Returns a result like:
93850             //   {
93851             //     type:      'point', 'geojson', or 'countrycoder'
93852             //     location:  the queried location
93853             //     id:        a stable identifier for the feature
93854             //     feature:   the resolved GeoJSON feature
93855             //   }
93856             //  or `null` if the location is invalid
93857             //
93858
93859           }, {
93860             key: "resolveLocation",
93861             value: function resolveLocation(location) {
93862               var valid = this.validateLocation(location);
93863               if (!valid) return null;
93864               var id = valid.id; // return a result from cache if we can
93865
93866               if (this._cache[id]) {
93867                 return Object.assign(valid, {
93868                   feature: this._cache[id]
93869                 });
93870               } // a [lon,lat] coordinate pair?
93871
93872
93873               if (valid.type === 'point') {
93874                 var RADIUS = 25000; // meters
93875
93876                 var EDGES = 10;
93877                 var PRECISION = 3;
93878                 var area = Math.PI * RADIUS * RADIUS / 1e6; // m² to km²
93879
93880                 var feature = this._cache[id] = geojsonPrecision({
93881                   type: 'Feature',
93882                   id: id,
93883                   properties: {
93884                     id: id,
93885                     area: Number(area.toFixed(2))
93886                   },
93887                   geometry: circleToPolygon(location, RADIUS, EDGES)
93888                 }, PRECISION);
93889                 return Object.assign(valid, {
93890                   feature: feature
93891                 }); // a .geojson filename?
93892               } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
93893                 var _feature = _cloneDeep(feature$1(id));
93894
93895                 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
93896                 // CountryCoder includes higher level features which are made up of members.
93897                 // These features don't have their own geometry, but CountryCoder provides an
93898                 //   `aggregateFeature` method to combine these members into a MultiPolygon.
93899                 // BUT, when we try to actually work with these aggregated MultiPolygons,
93900                 //   Turf/JSTS gets crashy because of topography bugs.
93901                 // SO, we'll aggregate the features ourselves by unioning them together.
93902                 // This approach also has the benefit of removing all the internal boaders and
93903                 //   simplifying the regional polygons a lot.
93904
93905                 if (Array.isArray(props.members)) {
93906                   var seed = _feature.geometry ? _feature : null;
93907                   var aggregate = props.members.reduce(_locationReducer.bind(this), seed);
93908                   _feature.geometry = aggregate.geometry;
93909                 } // ensure `area` property exists
93910
93911
93912                 if (!props.area) {
93913                   var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
93914
93915
93916                   props.area = Number(_area.toFixed(2));
93917                 } // ensure `id` property exists
93918
93919
93920                 _feature.id = id;
93921                 props.id = id;
93922                 this._cache[id] = _feature;
93923                 return Object.assign(valid, {
93924                   feature: _feature
93925                 });
93926               }
93927
93928               if (this._strict) {
93929                 throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, "\"."));
93930               } else {
93931                 return null;
93932               }
93933             } // validateLocationSet
93934             // `locationSet`  the locationSet to validate
93935             //
93936             // Pass a locationSet Object to validate like:
93937             //   {
93938             //     include: [ Array of locations ],
93939             //     exclude: [ Array of locations ]
93940             //   }
93941             //
93942             // Returns a result like:
93943             //   {
93944             //     type:         'locationset'
93945             //     locationSet:  the queried locationSet
93946             //     id:           the stable identifier for the feature
93947             //   }
93948             // or `null` if the locationSet is invalid
93949             //
93950
93951           }, {
93952             key: "validateLocationSet",
93953             value: function validateLocationSet(locationSet) {
93954               locationSet = locationSet || {};
93955               var validator = this.validateLocation.bind(this);
93956               var include = (locationSet.include || []).map(validator).filter(Boolean);
93957               var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
93958
93959               if (!include.length) {
93960                 if (this._strict) {
93961                   throw new Error("validateLocationSet:  LocationSet includes nothing.");
93962                 } else {
93963                   // non-strict mode, replace an empty locationSet with one that includes "the world"
93964                   locationSet.include = ['Q2'];
93965                   include = [{
93966                     type: 'countrycoder',
93967                     location: 'Q2',
93968                     id: 'Q2'
93969                   }];
93970                 }
93971               } // generate stable identifier
93972
93973
93974               include.sort(_sortLocations);
93975               var id = '+[' + include.map(function (d) {
93976                 return d.id;
93977               }).join(',') + ']';
93978
93979               if (exclude.length) {
93980                 exclude.sort(_sortLocations);
93981                 id += '-[' + exclude.map(function (d) {
93982                   return d.id;
93983                 }).join(',') + ']';
93984               }
93985
93986               return {
93987                 type: 'locationset',
93988                 locationSet: locationSet,
93989                 id: id
93990               };
93991             } // resolveLocationSet
93992             // `locationSet`  the locationSet to resolve
93993             //
93994             // Pass a locationSet Object to validate like:
93995             //   {
93996             //     include: [ Array of locations ],
93997             //     exclude: [ Array of locations ]
93998             //   }
93999             //
94000             // Returns a result like:
94001             //   {
94002             //     type:         'locationset'
94003             //     locationSet:  the queried locationSet
94004             //     id:           the stable identifier for the feature
94005             //     feature:      the resolved GeoJSON feature
94006             //   }
94007             // or `null` if the locationSet is invalid
94008             //
94009
94010           }, {
94011             key: "resolveLocationSet",
94012             value: function resolveLocationSet(locationSet) {
94013               locationSet = locationSet || {};
94014               var valid = this.validateLocationSet(locationSet);
94015               if (!valid) return null;
94016               var id = valid.id; // return a result from cache if we can
94017
94018               if (this._cache[id]) {
94019                 return Object.assign(valid, {
94020                   feature: this._cache[id]
94021                 });
94022               }
94023
94024               var resolver = this.resolveLocation.bind(this);
94025               var include = (locationSet.include || []).map(resolver).filter(Boolean);
94026               var exclude = (locationSet.exclude || []).map(resolver).filter(Boolean); // return quickly if it's a single included location..
94027
94028               if (include.length === 1 && exclude.length === 0) {
94029                 return Object.assign(valid, {
94030                   feature: include[0].feature
94031                 });
94032               } // calculate unions
94033
94034
94035               var includeGeoJSON = include.map(function (d) {
94036                 return d.location;
94037               }).reduce(_locationReducer.bind(this), null);
94038               var excludeGeoJSON = exclude.map(function (d) {
94039                 return d.location;
94040               }).reduce(_locationReducer.bind(this), null); // calculate difference, update `area` and return result
94041
94042               var resultGeoJSON = excludeGeoJSON ? _clip(includeGeoJSON, excludeGeoJSON, 'DIFFERENCE') : includeGeoJSON;
94043               var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
94044
94045               resultGeoJSON.id = id;
94046               resultGeoJSON.properties = {
94047                 id: id,
94048                 area: Number(area.toFixed(2))
94049               };
94050               this._cache[id] = resultGeoJSON;
94051               return Object.assign(valid, {
94052                 feature: resultGeoJSON
94053               });
94054             } // strict
94055             //
94056
94057           }, {
94058             key: "strict",
94059             value: function strict(val) {
94060               if (val === undefined) {
94061                 // get
94062                 return this._strict;
94063               } else {
94064                 // set
94065                 this._strict = val;
94066                 return this;
94067               }
94068             } // cache
94069             // convenience method to access the internal cache
94070
94071           }, {
94072             key: "cache",
94073             value: function cache() {
94074               return this._cache;
94075             } // stringify
94076             // convenience method to prettyStringify the given object
94077
94078           }, {
94079             key: "stringify",
94080             value: function stringify(obj, options) {
94081               return jsonStringifyPrettyCompact(obj, options);
94082             }
94083           }]);
94084
94085           return _default;
94086         }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
94087
94088         function _clip(a, b, which) {
94089           var fn = {
94090             UNION: index$1.union,
94091             DIFFERENCE: index$1.difference
94092           }[which];
94093           var coords = fn(a.geometry.coordinates, b.geometry.coordinates);
94094           return {
94095             type: 'Feature',
94096             properties: {},
94097             geometry: {
94098               type: whichType(coords),
94099               coordinates: coords
94100             }
94101           }; // is this a Polygon or a MultiPolygon?
94102
94103           function whichType(coords) {
94104             var a = Array.isArray(coords);
94105             var b = a && Array.isArray(coords[0]);
94106             var c = b && Array.isArray(coords[0][0]);
94107             var d = c && Array.isArray(coords[0][0][0]);
94108             return d ? 'MultiPolygon' : 'Polygon';
94109           }
94110         } // Reduce an array of locations into a single GeoJSON feature
94111
94112
94113         function _locationReducer(accumulator, location) {
94114           /* eslint-disable no-console, no-invalid-this */
94115           var result;
94116
94117           try {
94118             var resolved = this.resolveLocation(location);
94119
94120             if (!resolved || !resolved.feature) {
94121               console.warn("Warning:  Couldn't resolve location \"".concat(location, "\""));
94122               return accumulator;
94123             }
94124
94125             result = !accumulator ? resolved.feature : _clip(accumulator, resolved.feature, 'UNION');
94126           } catch (e) {
94127             console.warn("Warning:  Error resolving location \"".concat(location, "\""));
94128             console.warn(e);
94129             result = accumulator;
94130           }
94131
94132           return result;
94133           /* eslint-enable no-console, no-invalid-this */
94134         }
94135
94136         function _cloneDeep(obj) {
94137           return JSON.parse(JSON.stringify(obj));
94138         } // Sorting the location lists is ok because they end up unioned together.
94139         // This sorting makes it possible to generate a deterministic id.
94140
94141
94142         function _sortLocations(a, b) {
94143           var rank = {
94144             countrycoder: 1,
94145             geojson: 2,
94146             point: 3
94147           };
94148           var aRank = rank[a.type];
94149           var bRank = rank[b.type];
94150           return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
94151         }
94152
94153         var _oci = null;
94154         function uiSuccess(context) {
94155           var MAXEVENTS = 2;
94156           var dispatch$1 = dispatch('cancel');
94157
94158           var _changeset;
94159
94160           var _location;
94161
94162           ensureOSMCommunityIndex(); // start fetching the data
94163
94164           function ensureOSMCommunityIndex() {
94165             var data = _mainFileFetcher;
94166             return Promise.all([data.get('oci_resources'), data.get('oci_features')]).then(function (vals) {
94167               if (_oci) return _oci;
94168               var ociResources = vals[0].resources;
94169               var loco = new _default$2(vals[1]);
94170               var ociFeatures = {};
94171               Object.values(ociResources).forEach(function (resource) {
94172                 var feature = loco.resolveLocationSet(resource.locationSet).feature;
94173                 var ociFeature = ociFeatures[feature.id];
94174
94175                 if (!ociFeature) {
94176                   ociFeature = JSON.parse(JSON.stringify(feature)); // deep clone
94177
94178                   ociFeature.properties.resourceIDs = new Set();
94179                   ociFeatures[feature.id] = ociFeature;
94180                 }
94181
94182                 ociFeature.properties.resourceIDs.add(resource.id);
94183               });
94184               return _oci = {
94185                 features: ociFeatures,
94186                 resources: ociResources,
94187                 query: whichPolygon_1({
94188                   type: 'FeatureCollection',
94189                   features: Object.values(ociFeatures)
94190                 })
94191               };
94192             });
94193           } // string-to-date parsing in JavaScript is weird
94194
94195
94196           function parseEventDate(when) {
94197             if (!when) return;
94198             var raw = when.trim();
94199             if (!raw) return;
94200
94201             if (!/Z$/.test(raw)) {
94202               // if no trailing 'Z', add one
94203               raw += 'Z'; // this forces date to be parsed as a UTC date
94204             }
94205
94206             var parsed = new Date(raw);
94207             return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
94208           }
94209
94210           function success(selection) {
94211             var header = selection.append('div').attr('class', 'header fillL');
94212             header.append('h3').html(_t.html('success.just_edited'));
94213             header.append('button').attr('class', 'close').on('click', function () {
94214               return dispatch$1.call('cancel');
94215             }).call(svgIcon('#iD-icon-close'));
94216             var body = selection.append('div').attr('class', 'body save-success fillL');
94217             var summary = body.append('div').attr('class', 'save-summary');
94218             summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
94219               where: _location
94220             }));
94221             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'));
94222             var osm = context.connection();
94223             if (!osm) return;
94224             var changesetURL = osm.changesetURL(_changeset.id);
94225             var table = summary.append('table').attr('class', 'summary-table');
94226             var row = table.append('tr').attr('class', 'summary-row');
94227             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');
94228             var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
94229             summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
94230             summaryDetail.append('div').html(_t.html('success.changeset_id', {
94231               changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
94232             })); // Get OSM community index features intersecting the map..
94233
94234             ensureOSMCommunityIndex().then(function (oci) {
94235               var communities = [];
94236               var properties = oci.query(context.map().center(), true) || []; // Gather the communities from the result
94237
94238               properties.forEach(function (props) {
94239                 var resourceIDs = Array.from(props.resourceIDs);
94240                 resourceIDs.forEach(function (resourceID) {
94241                   var resource = oci.resources[resourceID];
94242                   communities.push({
94243                     area: props.area || Infinity,
94244                     order: resource.order || 0,
94245                     resource: resource
94246                   });
94247                 });
94248               }); // sort communities by feature area ascending, community order descending
94249
94250               communities.sort(function (a, b) {
94251                 return a.area - b.area || b.order - a.order;
94252               });
94253               body.call(showCommunityLinks, communities.map(function (c) {
94254                 return c.resource;
94255               }));
94256             });
94257           }
94258
94259           function showCommunityLinks(selection, resources) {
94260             var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
94261             communityLinks.append('h3').html(_t.html('success.like_osm'));
94262             var table = communityLinks.append('table').attr('class', 'community-table');
94263             var row = table.selectAll('.community-row').data(resources);
94264             var rowEnter = row.enter().append('tr').attr('class', 'community-row');
94265             rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
94266               return d.url;
94267             }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
94268               return "#community-".concat(d.type);
94269             });
94270             var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
94271             communityDetail.each(showCommunityDetails);
94272             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'));
94273           }
94274
94275           function showCommunityDetails(d) {
94276             var selection = select(this);
94277             var communityID = d.id;
94278             var replacements = {
94279               url: linkify(d.url),
94280               signupUrl: linkify(d.signupUrl || d.url)
94281             };
94282             selection.append('div').attr('class', 'community-name').append('a').attr('target', '_blank').attr('href', d.url).html(_t.html("community.".concat(d.id, ".name")));
94283             var descriptionHTML = _t.html("community.".concat(d.id, ".description"), replacements);
94284
94285             if (d.type === 'reddit') {
94286               // linkify subreddits  #4997
94287               descriptionHTML = descriptionHTML.replace(/(\/r\/\w*\/*)/i, function (match) {
94288                 return linkify(d.url, match);
94289               });
94290             }
94291
94292             selection.append('div').attr('class', 'community-description').html(descriptionHTML);
94293
94294             if (d.extendedDescription || d.languageCodes && d.languageCodes.length) {
94295               selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
94296             }
94297
94298             var nextEvents = (d.events || []).map(function (event) {
94299               event.date = parseEventDate(event.when);
94300               return event;
94301             }).filter(function (event) {
94302               // date is valid and future (or today)
94303               var t = event.date.getTime();
94304               var now = new Date().setHours(0, 0, 0, 0);
94305               return !isNaN(t) && t >= now;
94306             }).sort(function (a, b) {
94307               // sort by date ascending
94308               return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
94309             }).slice(0, MAXEVENTS); // limit number of events shown
94310
94311             if (nextEvents.length) {
94312               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);
94313             }
94314
94315             function showMore(selection) {
94316               var more = selection.selectAll('.community-more').data([0]);
94317               var moreEnter = more.enter().append('div').attr('class', 'community-more');
94318
94319               if (d.extendedDescription) {
94320                 moreEnter.append('div').attr('class', 'community-extended-description').html(_t.html("community.".concat(d.id, ".extendedDescription"), replacements));
94321               }
94322
94323               if (d.languageCodes && d.languageCodes.length) {
94324                 var languageList = d.languageCodes.map(function (code) {
94325                   return _mainLocalizer.languageName(code);
94326                 }).join(', ');
94327                 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
94328                   languages: languageList
94329                 }));
94330               }
94331             }
94332
94333             function showNextEvents(selection) {
94334               var events = selection.append('div').attr('class', 'community-events');
94335               var item = events.selectAll('.community-event').data(nextEvents);
94336               var itemEnter = item.enter().append('div').attr('class', 'community-event');
94337               itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
94338                 return d.url;
94339               }).html(function (d) {
94340                 var name = d.name;
94341
94342                 if (d.i18n && d.id) {
94343                   name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
94344                     "default": name
94345                   });
94346                 }
94347
94348                 return name;
94349               });
94350               itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
94351                 var options = {
94352                   weekday: 'short',
94353                   day: 'numeric',
94354                   month: 'short',
94355                   year: 'numeric'
94356                 };
94357
94358                 if (d.date.getHours() || d.date.getMinutes()) {
94359                   // include time if it has one
94360                   options.hour = 'numeric';
94361                   options.minute = 'numeric';
94362                 }
94363
94364                 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
94365               });
94366               itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
94367                 var where = d.where;
94368
94369                 if (d.i18n && d.id) {
94370                   where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
94371                     "default": where
94372                   });
94373                 }
94374
94375                 return where;
94376               });
94377               itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
94378                 var description = d.description;
94379
94380                 if (d.i18n && d.id) {
94381                   description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
94382                     "default": description
94383                   });
94384                 }
94385
94386                 return description;
94387               });
94388             }
94389
94390             function linkify(url, text) {
94391               text = text || url;
94392               return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
94393             }
94394           }
94395
94396           success.changeset = function (val) {
94397             if (!arguments.length) return _changeset;
94398             _changeset = val;
94399             return success;
94400           };
94401
94402           success.location = function (val) {
94403             if (!arguments.length) return _location;
94404             _location = val;
94405             return success;
94406           };
94407
94408           return utilRebind(success, dispatch$1, 'on');
94409         }
94410
94411         function modeSave(context) {
94412           var mode = {
94413             id: 'save'
94414           };
94415           var keybinding = utilKeybinding('modeSave');
94416           var commit = uiCommit(context).on('cancel', cancel);
94417
94418           var _conflictsUi; // uiConflicts
94419
94420
94421           var _location;
94422
94423           var _success;
94424
94425           var uploader = context.uploader().on('saveStarted.modeSave', function () {
94426             keybindingOff();
94427           }) // fire off some async work that we want to be ready later
94428           .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
94429             cancel();
94430           }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
94431
94432           function cancel() {
94433             context.enter(modeBrowse(context));
94434           }
94435
94436           function showProgress(num, total) {
94437             var modal = context.container().select('.loading-modal .modal-section');
94438             var progress = modal.selectAll('.progress').data([0]); // enter/update
94439
94440             progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
94441               num: num,
94442               total: total
94443             }));
94444           }
94445
94446           function showConflicts(changeset, conflicts, origChanges) {
94447             var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
94448             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
94449             _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
94450               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
94451               selection.remove();
94452               keybindingOn();
94453               uploader.cancelConflictResolution();
94454             }).on('save', function () {
94455               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
94456               selection.remove();
94457               uploader.processResolvedConflicts(changeset);
94458             });
94459             selection.call(_conflictsUi);
94460           }
94461
94462           function showErrors(errors) {
94463             keybindingOn();
94464             var selection = uiConfirm(context.container());
94465             selection.select('.modal-section.header').append('h3').text(_t('save.error'));
94466             addErrors(selection, errors);
94467             selection.okButton();
94468           }
94469
94470           function addErrors(selection, data) {
94471             var message = selection.select('.modal-section.message-text');
94472             var items = message.selectAll('.error-container').data(data);
94473             var enter = items.enter().append('div').attr('class', 'error-container');
94474             enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
94475               return d.msg || _t('save.unknown_error_details');
94476             }).on('click', function (d3_event) {
94477               d3_event.preventDefault();
94478               var error = select(this);
94479               var detail = select(this.nextElementSibling);
94480               var exp = error.classed('expanded');
94481               detail.style('display', exp ? 'none' : 'block');
94482               error.classed('expanded', !exp);
94483             });
94484             var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
94485             details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
94486               return d.details || [];
94487             }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
94488               return d;
94489             });
94490             items.exit().remove();
94491           }
94492
94493           function showSuccess(changeset) {
94494             commit.reset();
94495
94496             var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
94497               context.ui().sidebar.hide();
94498             });
94499
94500             context.enter(modeBrowse(context).sidebar(ui));
94501           }
94502
94503           function keybindingOn() {
94504             select(document).call(keybinding.on('⎋', cancel, true));
94505           }
94506
94507           function keybindingOff() {
94508             select(document).call(keybinding.unbind);
94509           } // Reverse geocode current map location so we can display a message on
94510           // the success screen like "Thank you for editing around place, region."
94511
94512
94513           function prepareForSuccess() {
94514             _success = uiSuccess(context);
94515             _location = null;
94516             if (!services.geocoder) return;
94517             services.geocoder.reverse(context.map().center(), function (err, result) {
94518               if (err || !result || !result.address) return;
94519               var addr = result.address;
94520               var place = addr && (addr.town || addr.city || addr.county) || '';
94521               var region = addr && (addr.state || addr.country) || '';
94522               var separator = place && region ? _t('success.thank_you_where.separator') : '';
94523               _location = _t('success.thank_you_where.format', {
94524                 place: place,
94525                 separator: separator,
94526                 region: region
94527               });
94528             });
94529           }
94530
94531           mode.selectedIDs = function () {
94532             return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
94533           };
94534
94535           mode.enter = function () {
94536             // Show sidebar
94537             context.ui().sidebar.expand();
94538
94539             function done() {
94540               context.ui().sidebar.show(commit);
94541             }
94542
94543             keybindingOn();
94544             context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
94545             var osm = context.connection();
94546
94547             if (!osm) {
94548               cancel();
94549               return;
94550             }
94551
94552             if (osm.authenticated()) {
94553               done();
94554             } else {
94555               osm.authenticate(function (err) {
94556                 if (err) {
94557                   cancel();
94558                 } else {
94559                   done();
94560                 }
94561               });
94562             }
94563           };
94564
94565           mode.exit = function () {
94566             keybindingOff();
94567             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
94568             context.ui().sidebar.hide();
94569           };
94570
94571           return mode;
94572         }
94573
94574         function uiToolOldDrawModes(context) {
94575           var tool = {
94576             id: 'old_modes',
94577             label: _t.html('toolbar.add_feature')
94578           };
94579           var modes = [modeAddPoint(context, {
94580             title: _t.html('modes.add_point.title'),
94581             button: 'point',
94582             description: _t.html('modes.add_point.description'),
94583             preset: _mainPresetIndex.item('point'),
94584             key: '1'
94585           }), modeAddLine(context, {
94586             title: _t.html('modes.add_line.title'),
94587             button: 'line',
94588             description: _t.html('modes.add_line.description'),
94589             preset: _mainPresetIndex.item('line'),
94590             key: '2'
94591           }), modeAddArea(context, {
94592             title: _t.html('modes.add_area.title'),
94593             button: 'area',
94594             description: _t.html('modes.add_area.description'),
94595             preset: _mainPresetIndex.item('area'),
94596             key: '3'
94597           })];
94598
94599           function enabled() {
94600             return osmEditable();
94601           }
94602
94603           function osmEditable() {
94604             return context.editable();
94605           }
94606
94607           modes.forEach(function (mode) {
94608             context.keybinding().on(mode.key, function () {
94609               if (!enabled()) return;
94610
94611               if (mode.id === context.mode().id) {
94612                 context.enter(modeBrowse(context));
94613               } else {
94614                 context.enter(mode);
94615               }
94616             });
94617           });
94618
94619           tool.render = function (selection) {
94620             var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
94621
94622             var debouncedUpdate = debounce(update, 500, {
94623               leading: true,
94624               trailing: true
94625             });
94626
94627             context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
94628             context.on('enter.modes', update);
94629             update();
94630
94631             function update() {
94632               var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
94633                 return d.id;
94634               }); // exit
94635
94636               buttons.exit().remove(); // enter
94637
94638               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
94639                 return d.id + ' add-button bar-button';
94640               }).on('click.mode-buttons', function (d3_event, d) {
94641                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
94642
94643                 var currMode = context.mode().id;
94644                 if (/^draw/.test(currMode)) return;
94645
94646                 if (d.id === currMode) {
94647                   context.enter(modeBrowse(context));
94648                 } else {
94649                   context.enter(d);
94650                 }
94651               }).call(uiTooltip().placement('bottom').title(function (d) {
94652                 return d.description;
94653               }).keys(function (d) {
94654                 return [d.key];
94655               }).scrollContainer(context.container().select('.top-toolbar')));
94656               buttonsEnter.each(function (d) {
94657                 select(this).call(svgIcon('#iD-icon-' + d.button));
94658               });
94659               buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
94660                 return mode.title;
94661               }); // if we are adding/removing the buttons, check if toolbar has overflowed
94662
94663               if (buttons.enter().size() || buttons.exit().size()) {
94664                 context.ui().checkOverflow('.top-toolbar', true);
94665               } // update
94666
94667
94668               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
94669                 return !enabled();
94670               }).classed('active', function (d) {
94671                 return context.mode() && context.mode().button === d.button;
94672               });
94673             }
94674           };
94675
94676           return tool;
94677         }
94678
94679         function uiToolNotes(context) {
94680           var tool = {
94681             id: 'notes',
94682             label: _t.html('modes.add_note.label')
94683           };
94684           var mode = modeAddNote(context);
94685
94686           function enabled() {
94687             return notesEnabled() && notesEditable();
94688           }
94689
94690           function notesEnabled() {
94691             var noteLayer = context.layers().layer('notes');
94692             return noteLayer && noteLayer.enabled();
94693           }
94694
94695           function notesEditable() {
94696             var mode = context.mode();
94697             return context.map().notesEditable() && mode && mode.id !== 'save';
94698           }
94699
94700           context.keybinding().on(mode.key, function () {
94701             if (!enabled()) return;
94702
94703             if (mode.id === context.mode().id) {
94704               context.enter(modeBrowse(context));
94705             } else {
94706               context.enter(mode);
94707             }
94708           });
94709
94710           tool.render = function (selection) {
94711             var debouncedUpdate = debounce(update, 500, {
94712               leading: true,
94713               trailing: true
94714             });
94715
94716             context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
94717             context.on('enter.notes', update);
94718             update();
94719
94720             function update() {
94721               var showNotes = notesEnabled();
94722               var data = showNotes ? [mode] : [];
94723               var buttons = selection.selectAll('button.add-button').data(data, function (d) {
94724                 return d.id;
94725               }); // exit
94726
94727               buttons.exit().remove(); // enter
94728
94729               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
94730                 return d.id + ' add-button bar-button';
94731               }).on('click.notes', function (d3_event, d) {
94732                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
94733
94734                 var currMode = context.mode().id;
94735                 if (/^draw/.test(currMode)) return;
94736
94737                 if (d.id === currMode) {
94738                   context.enter(modeBrowse(context));
94739                 } else {
94740                   context.enter(d);
94741                 }
94742               }).call(uiTooltip().placement('bottom').title(function (d) {
94743                 return d.description;
94744               }).keys(function (d) {
94745                 return [d.key];
94746               }).scrollContainer(context.container().select('.top-toolbar')));
94747               buttonsEnter.each(function (d) {
94748                 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
94749               }); // if we are adding/removing the buttons, check if toolbar has overflowed
94750
94751               if (buttons.enter().size() || buttons.exit().size()) {
94752                 context.ui().checkOverflow('.top-toolbar', true);
94753               } // update
94754
94755
94756               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
94757                 return !enabled();
94758               }).classed('active', function (d) {
94759                 return context.mode() && context.mode().button === d.button;
94760               });
94761             }
94762           };
94763
94764           tool.uninstall = function () {
94765             context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
94766             context.map().on('move.notes', null).on('drawn.notes', null);
94767           };
94768
94769           return tool;
94770         }
94771
94772         function uiToolSave(context) {
94773           var tool = {
94774             id: 'save',
94775             label: _t.html('save.title')
94776           };
94777           var button = null;
94778           var tooltipBehavior = null;
94779           var history = context.history();
94780           var key = uiCmd('⌘S');
94781           var _numChanges = 0;
94782
94783           function isSaving() {
94784             var mode = context.mode();
94785             return mode && mode.id === 'save';
94786           }
94787
94788           function isDisabled() {
94789             return _numChanges === 0 || isSaving();
94790           }
94791
94792           function save(d3_event) {
94793             d3_event.preventDefault();
94794
94795             if (!context.inIntro() && !isSaving() && history.hasChanges()) {
94796               context.enter(modeSave(context));
94797             }
94798           }
94799
94800           function bgColor() {
94801             var step;
94802
94803             if (_numChanges === 0) {
94804               return null;
94805             } else if (_numChanges <= 50) {
94806               step = _numChanges / 50;
94807               return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
94808             } else {
94809               step = Math.min((_numChanges - 50) / 50, 1.0);
94810               return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
94811             }
94812           }
94813
94814           function updateCount() {
94815             var val = history.difference().summary().length;
94816             if (val === _numChanges) return;
94817             _numChanges = val;
94818
94819             if (tooltipBehavior) {
94820               tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
94821             }
94822
94823             if (button) {
94824               button.classed('disabled', isDisabled()).style('background', bgColor());
94825               button.select('span.count').html(_numChanges);
94826             }
94827           }
94828
94829           tool.render = function (selection) {
94830             tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
94831             var lastPointerUpType;
94832             button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
94833               lastPointerUpType = d3_event.pointerType;
94834             }).on('click', function (d3_event) {
94835               save(d3_event);
94836
94837               if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
94838                 // there are no tooltips for touch interactions so flash feedback instead
94839                 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
94840               }
94841
94842               lastPointerUpType = null;
94843             }).call(tooltipBehavior);
94844             button.call(svgIcon('#iD-icon-save'));
94845             button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
94846             updateCount();
94847             context.keybinding().on(key, save, true);
94848             context.history().on('change.save', updateCount);
94849             context.on('enter.save', function () {
94850               if (button) {
94851                 button.classed('disabled', isDisabled());
94852
94853                 if (isSaving()) {
94854                   button.call(tooltipBehavior.hide);
94855                 }
94856               }
94857             });
94858           };
94859
94860           tool.uninstall = function () {
94861             context.keybinding().off(key, true);
94862             context.history().on('change.save', null);
94863             context.on('enter.save', null);
94864             button = null;
94865             tooltipBehavior = null;
94866           };
94867
94868           return tool;
94869         }
94870
94871         function uiToolSidebarToggle(context) {
94872           var tool = {
94873             id: 'sidebar_toggle',
94874             label: _t.html('toolbar.inspect')
94875           };
94876
94877           tool.render = function (selection) {
94878             selection.append('button').attr('class', 'bar-button').on('click', function () {
94879               context.ui().sidebar.toggle();
94880             }).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')));
94881           };
94882
94883           return tool;
94884         }
94885
94886         function uiToolUndoRedo(context) {
94887           var tool = {
94888             id: 'undo_redo',
94889             label: _t.html('toolbar.undo_redo')
94890           };
94891           var commands = [{
94892             id: 'undo',
94893             cmd: uiCmd('⌘Z'),
94894             action: function action() {
94895               context.undo();
94896             },
94897             annotation: function annotation() {
94898               return context.history().undoAnnotation();
94899             },
94900             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
94901           }, {
94902             id: 'redo',
94903             cmd: uiCmd('⌘⇧Z'),
94904             action: function action() {
94905               context.redo();
94906             },
94907             annotation: function annotation() {
94908               return context.history().redoAnnotation();
94909             },
94910             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
94911           }];
94912
94913           function editable() {
94914             return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
94915             /* ignore min zoom */
94916             );
94917           }
94918
94919           tool.render = function (selection) {
94920             var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
94921               return d.annotation() ? _t.html(d.id + '.tooltip', {
94922                 action: d.annotation()
94923               }) : _t.html(d.id + '.nothing');
94924             }).keys(function (d) {
94925               return [d.cmd];
94926             }).scrollContainer(context.container().select('.top-toolbar'));
94927             var lastPointerUpType;
94928             var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
94929               return 'disabled ' + d.id + '-button bar-button';
94930             }).on('pointerup', function (d3_event) {
94931               // `pointerup` is always called before `click`
94932               lastPointerUpType = d3_event.pointerType;
94933             }).on('click', function (d3_event, d) {
94934               d3_event.preventDefault();
94935               var annotation = d.annotation();
94936
94937               if (editable() && annotation) {
94938                 d.action();
94939               }
94940
94941               if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
94942                 // there are no tooltips for touch interactions so flash feedback instead
94943                 var text = annotation ? _t(d.id + '.tooltip', {
94944                   action: annotation
94945                 }) : _t(d.id + '.nothing');
94946                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
94947               }
94948
94949               lastPointerUpType = null;
94950             }).call(tooltipBehavior);
94951             buttons.each(function (d) {
94952               select(this).call(svgIcon('#' + d.icon));
94953             });
94954             context.keybinding().on(commands[0].cmd, function (d3_event) {
94955               d3_event.preventDefault();
94956               if (editable()) commands[0].action();
94957             }).on(commands[1].cmd, function (d3_event) {
94958               d3_event.preventDefault();
94959               if (editable()) commands[1].action();
94960             });
94961
94962             var debouncedUpdate = debounce(update, 500, {
94963               leading: true,
94964               trailing: true
94965             });
94966
94967             context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
94968             context.history().on('change.undo_redo', function (difference) {
94969               if (difference) update();
94970             });
94971             context.on('enter.undo_redo', update);
94972
94973             function update() {
94974               buttons.classed('disabled', function (d) {
94975                 return !editable() || !d.annotation();
94976               }).each(function () {
94977                 var selection = select(this);
94978
94979                 if (!selection.select('.tooltip.in').empty()) {
94980                   selection.call(tooltipBehavior.updateContent);
94981                 }
94982               });
94983             }
94984           };
94985
94986           tool.uninstall = function () {
94987             context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
94988             context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
94989             context.history().on('change.undo_redo', null);
94990             context.on('enter.undo_redo', null);
94991           };
94992
94993           return tool;
94994         }
94995
94996         function uiTopToolbar(context) {
94997           var sidebarToggle = uiToolSidebarToggle(context),
94998               modes = uiToolOldDrawModes(context),
94999               notes = uiToolNotes(context),
95000               undoRedo = uiToolUndoRedo(context),
95001               save = uiToolSave(context);
95002
95003           function notesEnabled() {
95004             var noteLayer = context.layers().layer('notes');
95005             return noteLayer && noteLayer.enabled();
95006           }
95007
95008           function topToolbar(bar) {
95009             bar.on('wheel.topToolbar', function (d3_event) {
95010               if (!d3_event.deltaX) {
95011                 // translate vertical scrolling into horizontal scrolling in case
95012                 // the user doesn't have an input device that can scroll horizontally
95013                 bar.node().scrollLeft += d3_event.deltaY;
95014               }
95015             });
95016
95017             var debouncedUpdate = debounce(update, 500, {
95018               leading: true,
95019               trailing: true
95020             });
95021
95022             context.layers().on('change.topToolbar', debouncedUpdate);
95023             update();
95024
95025             function update() {
95026               var tools = [sidebarToggle, 'spacer', modes];
95027               tools.push('spacer');
95028
95029               if (notesEnabled()) {
95030                 tools = tools.concat([notes, 'spacer']);
95031               }
95032
95033               tools = tools.concat([undoRedo, save]);
95034               var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
95035                 return d.id || d;
95036               });
95037               toolbarItems.exit().each(function (d) {
95038                 if (d.uninstall) {
95039                   d.uninstall();
95040                 }
95041               }).remove();
95042               var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
95043                 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
95044                 if (d.klass) classes += ' ' + d.klass;
95045                 return classes;
95046               });
95047               var actionableItems = itemsEnter.filter(function (d) {
95048                 return d !== 'spacer';
95049               });
95050               actionableItems.append('div').attr('class', 'item-content').each(function (d) {
95051                 select(this).call(d.render, bar);
95052               });
95053               actionableItems.append('div').attr('class', 'item-label').html(function (d) {
95054                 return d.label;
95055               });
95056             }
95057           }
95058
95059           return topToolbar;
95060         }
95061
95062         var sawVersion = null;
95063         var isNewVersion = false;
95064         var isNewUser = false;
95065         function uiVersion(context) {
95066           var currVersion = context.version;
95067           var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
95068
95069           if (sawVersion === null && matchedVersion !== null) {
95070             if (corePreferences('sawVersion')) {
95071               isNewUser = false;
95072               isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
95073             } else {
95074               isNewUser = true;
95075               isNewVersion = true;
95076             }
95077
95078             corePreferences('sawVersion', currVersion);
95079             sawVersion = currVersion;
95080           }
95081
95082           return function (selection) {
95083             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
95084
95085             if (isNewVersion && !isNewUser) {
95086               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', {
95087                 version: currVersion
95088               })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
95089             }
95090           };
95091         }
95092
95093         function uiZoom(context) {
95094           var zooms = [{
95095             id: 'zoom-in',
95096             icon: 'iD-icon-plus',
95097             title: _t.html('zoom.in'),
95098             action: zoomIn,
95099             disabled: function disabled() {
95100               return !context.map().canZoomIn();
95101             },
95102             disabledTitle: _t.html('zoom.disabled.in'),
95103             key: '+'
95104           }, {
95105             id: 'zoom-out',
95106             icon: 'iD-icon-minus',
95107             title: _t.html('zoom.out'),
95108             action: zoomOut,
95109             disabled: function disabled() {
95110               return !context.map().canZoomOut();
95111             },
95112             disabledTitle: _t.html('zoom.disabled.out'),
95113             key: '-'
95114           }];
95115
95116           function zoomIn(d3_event) {
95117             if (d3_event.shiftKey) return;
95118             d3_event.preventDefault();
95119             context.map().zoomIn();
95120           }
95121
95122           function zoomOut(d3_event) {
95123             if (d3_event.shiftKey) return;
95124             d3_event.preventDefault();
95125             context.map().zoomOut();
95126           }
95127
95128           function zoomInFurther(d3_event) {
95129             if (d3_event.shiftKey) return;
95130             d3_event.preventDefault();
95131             context.map().zoomInFurther();
95132           }
95133
95134           function zoomOutFurther(d3_event) {
95135             if (d3_event.shiftKey) return;
95136             d3_event.preventDefault();
95137             context.map().zoomOutFurther();
95138           }
95139
95140           return function (selection) {
95141             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
95142               if (d.disabled()) {
95143                 return d.disabledTitle;
95144               }
95145
95146               return d.title;
95147             }).keys(function (d) {
95148               return [d.key];
95149             });
95150             var lastPointerUpType;
95151             var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
95152               return d.id;
95153             }).on('pointerup.editor', function (d3_event) {
95154               lastPointerUpType = d3_event.pointerType;
95155             }).on('click.editor', function (d3_event, d) {
95156               if (!d.disabled()) {
95157                 d.action(d3_event);
95158               } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
95159                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
95160               }
95161
95162               lastPointerUpType = null;
95163             }).call(tooltipBehavior);
95164             buttons.each(function (d) {
95165               select(this).call(svgIcon('#' + d.icon, 'light'));
95166             });
95167             utilKeybinding.plusKeys.forEach(function (key) {
95168               context.keybinding().on([key], zoomIn);
95169               context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
95170             });
95171             utilKeybinding.minusKeys.forEach(function (key) {
95172               context.keybinding().on([key], zoomOut);
95173               context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
95174             });
95175
95176             function updateButtonStates() {
95177               buttons.classed('disabled', function (d) {
95178                 return d.disabled();
95179               }).each(function () {
95180                 var selection = select(this);
95181
95182                 if (!selection.select('.tooltip.in').empty()) {
95183                   selection.call(tooltipBehavior.updateContent);
95184                 }
95185               });
95186             }
95187
95188             updateButtonStates();
95189             context.map().on('move.uiZoom', updateButtonStates);
95190           };
95191         }
95192
95193         function uiZoomToSelection(context) {
95194           function isDisabled() {
95195             var mode = context.mode();
95196             return !mode || !mode.zoomToSelected;
95197           }
95198
95199           var _lastPointerUpType;
95200
95201           function pointerup(d3_event) {
95202             _lastPointerUpType = d3_event.pointerType;
95203           }
95204
95205           function click(d3_event) {
95206             d3_event.preventDefault();
95207
95208             if (isDisabled()) {
95209               if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
95210                 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
95211               }
95212             } else {
95213               var mode = context.mode();
95214
95215               if (mode && mode.zoomToSelected) {
95216                 mode.zoomToSelected();
95217               }
95218             }
95219
95220             _lastPointerUpType = null;
95221           }
95222
95223           return function (selection) {
95224             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
95225               if (isDisabled()) {
95226                 return _t.html('inspector.zoom_to.no_selection');
95227               }
95228
95229               return _t.html('inspector.zoom_to.title');
95230             }).keys([_t('inspector.zoom_to.key')]);
95231             var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
95232
95233             function setEnabledState() {
95234               button.classed('disabled', isDisabled());
95235
95236               if (!button.select('.tooltip.in').empty()) {
95237                 button.call(tooltipBehavior.updateContent);
95238               }
95239             }
95240
95241             context.on('enter.uiZoomToSelection', setEnabledState);
95242             setEnabledState();
95243           };
95244         }
95245
95246         function uiPane(id, context) {
95247           var _key;
95248
95249           var _label = '';
95250           var _description = '';
95251           var _iconName = '';
95252
95253           var _sections; // array of uiSection objects
95254
95255
95256           var _paneSelection = select(null);
95257
95258           var _paneTooltip;
95259
95260           var pane = {
95261             id: id
95262           };
95263
95264           pane.label = function (val) {
95265             if (!arguments.length) return _label;
95266             _label = val;
95267             return pane;
95268           };
95269
95270           pane.key = function (val) {
95271             if (!arguments.length) return _key;
95272             _key = val;
95273             return pane;
95274           };
95275
95276           pane.description = function (val) {
95277             if (!arguments.length) return _description;
95278             _description = val;
95279             return pane;
95280           };
95281
95282           pane.iconName = function (val) {
95283             if (!arguments.length) return _iconName;
95284             _iconName = val;
95285             return pane;
95286           };
95287
95288           pane.sections = function (val) {
95289             if (!arguments.length) return _sections;
95290             _sections = val;
95291             return pane;
95292           };
95293
95294           pane.selection = function () {
95295             return _paneSelection;
95296           };
95297
95298           function hidePane() {
95299             context.ui().togglePanes();
95300           }
95301
95302           pane.togglePane = function (d3_event) {
95303             if (d3_event) d3_event.preventDefault();
95304
95305             _paneTooltip.hide();
95306
95307             context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
95308           };
95309
95310           pane.renderToggleButton = function (selection) {
95311             if (!_paneTooltip) {
95312               _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
95313             }
95314
95315             selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
95316           };
95317
95318           pane.renderContent = function (selection) {
95319             // override to fully customize content
95320             if (_sections) {
95321               _sections.forEach(function (section) {
95322                 selection.call(section.render);
95323               });
95324             }
95325           };
95326
95327           pane.renderPane = function (selection) {
95328             _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
95329
95330             var heading = _paneSelection.append('div').attr('class', 'pane-heading');
95331
95332             heading.append('h2').html(_label);
95333             heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
95334
95335             _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
95336
95337             if (_key) {
95338               context.keybinding().on(_key, pane.togglePane);
95339             }
95340           };
95341
95342           return pane;
95343         }
95344
95345         function uiSectionBackgroundDisplayOptions(context) {
95346           var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
95347
95348           var _detected = utilDetect();
95349
95350           var _storedOpacity = corePreferences('background-opacity');
95351
95352           var _minVal = 0;
95353
95354           var _maxVal = _detected.cssfilters ? 3 : 1;
95355
95356           var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
95357
95358           var _options = {
95359             brightness: _storedOpacity !== null ? +_storedOpacity : 1,
95360             contrast: 1,
95361             saturation: 1,
95362             sharpness: 1
95363           };
95364
95365           function clamp(x, min, max) {
95366             return Math.max(min, Math.min(x, max));
95367           }
95368
95369           function updateValue(d, val) {
95370             val = clamp(val, _minVal, _maxVal);
95371             _options[d] = val;
95372             context.background()[d](val);
95373
95374             if (d === 'brightness') {
95375               corePreferences('background-opacity', val);
95376             }
95377
95378             section.reRender();
95379           }
95380
95381           function renderDisclosureContent(selection) {
95382             var container = selection.selectAll('.display-options-container').data([0]);
95383             var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
95384
95385             var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
95386               return 'display-control display-control-' + d;
95387             });
95388             slidersEnter.append('h5').html(function (d) {
95389               return _t.html('background.' + d);
95390             }).append('span').attr('class', function (d) {
95391               return 'display-option-value display-option-value-' + d;
95392             });
95393             var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
95394             sildersControlEnter.append('input').attr('class', function (d) {
95395               return 'display-option-input display-option-input-' + d;
95396             }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
95397               var val = select(this).property('value');
95398
95399               if (!val && d3_event && d3_event.target) {
95400                 val = d3_event.target.value;
95401               }
95402
95403               updateValue(d, val);
95404             });
95405             sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
95406               return 'display-option-reset display-option-reset-' + d;
95407             }).on('click', function (d3_event, d) {
95408               if (d3_event.button !== 0) return;
95409               updateValue(d, 1);
95410             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
95411
95412             containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
95413               d3_event.preventDefault();
95414
95415               for (var i = 0; i < _sliders.length; i++) {
95416                 updateValue(_sliders[i], 1);
95417               }
95418             }); // update
95419
95420             container = containerEnter.merge(container);
95421             container.selectAll('.display-option-input').property('value', function (d) {
95422               return _options[d];
95423             });
95424             container.selectAll('.display-option-value').html(function (d) {
95425               return Math.floor(_options[d] * 100) + '%';
95426             });
95427             container.selectAll('.display-option-reset').classed('disabled', function (d) {
95428               return _options[d] === 1;
95429             }); // first time only, set brightness if needed
95430
95431             if (containerEnter.size() && _options.brightness !== 1) {
95432               context.background().brightness(_options.brightness);
95433             }
95434           }
95435
95436           return section;
95437         }
95438
95439         function uiSettingsCustomBackground() {
95440           var dispatch$1 = dispatch('change');
95441
95442           function render(selection) {
95443             // keep separate copies of original and current settings
95444             var _origSettings = {
95445               template: corePreferences('background-custom-template')
95446             };
95447             var _currSettings = {
95448               template: corePreferences('background-custom-template')
95449             };
95450             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
95451             var modal = uiConfirm(selection).okButton();
95452             modal.classed('settings-modal settings-custom-background', true);
95453             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
95454             var textSection = modal.select('.modal-section.message-text');
95455             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, "`");
95456             textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
95457             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
95458
95459             var buttonSection = modal.select('.modal-section.buttons');
95460             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
95461             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
95462             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
95463
95464             function isSaveDisabled() {
95465               return null;
95466             } // restore the original template
95467
95468
95469             function clickCancel() {
95470               textSection.select('.field-template').property('value', _origSettings.template);
95471               corePreferences('background-custom-template', _origSettings.template);
95472               this.blur();
95473               modal.close();
95474             } // accept the current template
95475
95476
95477             function clickSave() {
95478               _currSettings.template = textSection.select('.field-template').property('value');
95479               corePreferences('background-custom-template', _currSettings.template);
95480               this.blur();
95481               modal.close();
95482               dispatch$1.call('change', this, _currSettings);
95483             }
95484           }
95485
95486           return utilRebind(render, dispatch$1, 'on');
95487         }
95488
95489         function uiSectionBackgroundList(context) {
95490           var _backgroundList = select(null);
95491
95492           var _customSource = context.background().findSource('custom');
95493
95494           var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
95495
95496           var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
95497
95498           function previousBackgroundID() {
95499             return corePreferences('background-last-used-toggle');
95500           }
95501
95502           function renderDisclosureContent(selection) {
95503             // the background list
95504             var container = selection.selectAll('.layer-background-list').data([0]);
95505             _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
95506
95507             var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
95508             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'));
95509             minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
95510               d3_event.preventDefault();
95511               uiMapInMap.toggle();
95512             });
95513             minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
95514             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'));
95515             panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
95516               d3_event.preventDefault();
95517               context.ui().info.toggle('background');
95518             });
95519             panelLabelEnter.append('span').html(_t.html('background.panel.description'));
95520             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'));
95521             locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
95522               d3_event.preventDefault();
95523               context.ui().info.toggle('location');
95524             });
95525             locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
95526
95527             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'));
95528
95529             _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
95530               chooseBackground(d);
95531             }, function (d) {
95532               return !d.isHidden() && !d.overlay;
95533             });
95534           }
95535
95536           function setTooltips(selection) {
95537             selection.each(function (d, i, nodes) {
95538               var item = select(this).select('label');
95539               var span = item.select('span');
95540               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
95541               var description = d.description();
95542               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
95543               item.call(uiTooltip().destroyAny);
95544
95545               if (d.id === previousBackgroundID()) {
95546                 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
95547               } else if (description || isOverflowing) {
95548                 item.call(uiTooltip().placement(placement).title(description || d.label()));
95549               }
95550             });
95551           }
95552
95553           function drawListItems(layerList, type, change, filter) {
95554             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
95555               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
95556             });
95557             var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
95558             // arrow key navigation of radio values likes to work in the order
95559             // they were added, not the display document order.
95560             .data(sources, function (d, i) {
95561               return d.id + '---' + i;
95562             });
95563             layerLinks.exit().remove();
95564             var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
95565               return d.id === 'custom';
95566             }).classed('best', function (d) {
95567               return d.best();
95568             });
95569             var label = enter.append('label');
95570             label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
95571               return d.id;
95572             }).on('change', change);
95573             label.append('span').html(function (d) {
95574               return d.label();
95575             });
95576             enter.filter(function (d) {
95577               return d.id === 'custom';
95578             }).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) {
95579               d3_event.preventDefault();
95580               editCustom();
95581             }).call(svgIcon('#iD-icon-more'));
95582             enter.filter(function (d) {
95583               return d.best();
95584             }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('&#9733;');
95585             layerList.call(updateLayerSelections);
95586           }
95587
95588           function updateLayerSelections(selection) {
95589             function active(d) {
95590               return context.background().showsLayer(d);
95591             }
95592
95593             selection.selectAll('li').classed('active', active).classed('switch', function (d) {
95594               return d.id === previousBackgroundID();
95595             }).call(setTooltips).selectAll('input').property('checked', active);
95596           }
95597
95598           function chooseBackground(d) {
95599             if (d.id === 'custom' && !d.template()) {
95600               return editCustom();
95601             }
95602
95603             var previousBackground = context.background().baseLayerSource();
95604             corePreferences('background-last-used-toggle', previousBackground.id);
95605             corePreferences('background-last-used', d.id);
95606             context.background().baseLayerSource(d);
95607           }
95608
95609           function customChanged(d) {
95610             if (d && d.template) {
95611               _customSource.template(d.template);
95612
95613               chooseBackground(_customSource);
95614             } else {
95615               _customSource.template('');
95616
95617               chooseBackground(context.background().findSource('none'));
95618             }
95619           }
95620
95621           function editCustom() {
95622             context.container().call(_settingsCustomBackground);
95623           }
95624
95625           context.background().on('change.background_list', function () {
95626             _backgroundList.call(updateLayerSelections);
95627           });
95628           context.map().on('move.background_list', debounce(function () {
95629             // layers in-view may have changed due to map move
95630             window.requestIdleCallback(section.reRender);
95631           }, 1000));
95632           return section;
95633         }
95634
95635         function uiSectionBackgroundOffset(context) {
95636           var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
95637
95638           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
95639
95640           var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
95641
95642           function updateValue() {
95643             var meters = geoOffsetToMeters(context.background().offset());
95644             var x = +meters[0].toFixed(2);
95645             var y = +meters[1].toFixed(2);
95646             context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
95647             context.container().selectAll('.nudge-reset').classed('disabled', function () {
95648               return x === 0 && y === 0;
95649             });
95650           }
95651
95652           function resetOffset() {
95653             context.background().offset([0, 0]);
95654             updateValue();
95655           }
95656
95657           function nudge(d) {
95658             context.background().nudge(d, context.map().zoom());
95659             updateValue();
95660           }
95661
95662           function inputOffset() {
95663             var input = select(this);
95664             var d = input.node().value;
95665             if (d === '') return resetOffset();
95666             d = d.replace(/;/g, ',').split(',').map(function (n) {
95667               // if n is NaN, it will always get mapped to false.
95668               return !isNaN(n) && n;
95669             });
95670
95671             if (d.length !== 2 || !d[0] || !d[1]) {
95672               input.classed('error', true);
95673               return;
95674             }
95675
95676             context.background().offset(geoMetersToOffset(d));
95677             updateValue();
95678           }
95679
95680           function dragOffset(d3_event) {
95681             if (d3_event.button !== 0) return;
95682             var origin = [d3_event.clientX, d3_event.clientY];
95683             var pointerId = d3_event.pointerId || 'mouse';
95684             context.container().append('div').attr('class', 'nudge-surface');
95685             select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
95686
95687             if (_pointerPrefix === 'pointer') {
95688               select(window).on('pointercancel.drag-bg-offset', pointerup);
95689             }
95690
95691             function pointermove(d3_event) {
95692               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
95693               var latest = [d3_event.clientX, d3_event.clientY];
95694               var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
95695               origin = latest;
95696               nudge(d);
95697             }
95698
95699             function pointerup(d3_event) {
95700               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
95701               if (d3_event.button !== 0) return;
95702               context.container().selectAll('.nudge-surface').remove();
95703               select(window).on('.drag-bg-offset', null);
95704             }
95705           }
95706
95707           function renderDisclosureContent(selection) {
95708             var container = selection.selectAll('.nudge-container').data([0]);
95709             var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
95710             containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
95711             var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
95712             var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
95713             nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
95714             nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
95715               return d[0] + ' nudge';
95716             }).on('click', function (d3_event, d) {
95717               nudge(d[1]);
95718             });
95719             nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
95720               d3_event.preventDefault();
95721               resetOffset();
95722             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
95723             updateValue();
95724           }
95725
95726           context.background().on('change.backgroundOffset-update', updateValue);
95727           return section;
95728         }
95729
95730         function uiSectionOverlayList(context) {
95731           var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
95732
95733           var _overlayList = select(null);
95734
95735           function setTooltips(selection) {
95736             selection.each(function (d, i, nodes) {
95737               var item = select(this).select('label');
95738               var span = item.select('span');
95739               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
95740               var description = d.description();
95741               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
95742               item.call(uiTooltip().destroyAny);
95743
95744               if (description || isOverflowing) {
95745                 item.call(uiTooltip().placement(placement).title(description || d.name()));
95746               }
95747             });
95748           }
95749
95750           function updateLayerSelections(selection) {
95751             function active(d) {
95752               return context.background().showsLayer(d);
95753             }
95754
95755             selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
95756           }
95757
95758           function chooseOverlay(d3_event, d) {
95759             d3_event.preventDefault();
95760             context.background().toggleOverlayLayer(d);
95761
95762             _overlayList.call(updateLayerSelections);
95763
95764             document.activeElement.blur();
95765           }
95766
95767           function drawListItems(layerList, type, change, filter) {
95768             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
95769             var layerLinks = layerList.selectAll('li').data(sources, function (d) {
95770               return d.name();
95771             });
95772             layerLinks.exit().remove();
95773             var enter = layerLinks.enter().append('li');
95774             var label = enter.append('label');
95775             label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
95776             label.append('span').html(function (d) {
95777               return d.label();
95778             });
95779             layerList.selectAll('li').sort(sortSources);
95780             layerList.call(updateLayerSelections);
95781
95782             function sortSources(a, b) {
95783               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
95784             }
95785           }
95786
95787           function renderDisclosureContent(selection) {
95788             var container = selection.selectAll('.layer-overlay-list').data([0]);
95789             _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
95790
95791             _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
95792               return !d.isHidden() && d.overlay;
95793             });
95794           }
95795
95796           context.map().on('move.overlay_list', debounce(function () {
95797             // layers in-view may have changed due to map move
95798             window.requestIdleCallback(section.reRender);
95799           }, 1000));
95800           return section;
95801         }
95802
95803         function uiPaneBackground(context) {
95804           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)]);
95805           return backgroundPane;
95806         }
95807
95808         function uiPaneHelp(context) {
95809           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']]];
95810           var headings = {
95811             'help.help.open_data_h': 3,
95812             'help.help.before_start_h': 3,
95813             'help.help.open_source_h': 3,
95814             'help.overview.navigation_h': 3,
95815             'help.overview.features_h': 3,
95816             'help.editing.select_h': 3,
95817             'help.editing.multiselect_h': 3,
95818             'help.editing.undo_redo_h': 3,
95819             'help.editing.save_h': 3,
95820             'help.editing.upload_h': 3,
95821             'help.editing.backups_h': 3,
95822             'help.editing.keyboard_h': 3,
95823             'help.feature_editor.type_h': 3,
95824             'help.feature_editor.fields_h': 3,
95825             'help.feature_editor.tags_h': 3,
95826             'help.points.add_point_h': 3,
95827             'help.points.move_point_h': 3,
95828             'help.points.delete_point_h': 3,
95829             'help.lines.add_line_h': 3,
95830             'help.lines.modify_line_h': 3,
95831             'help.lines.connect_line_h': 3,
95832             'help.lines.disconnect_line_h': 3,
95833             'help.lines.move_line_h': 3,
95834             'help.lines.delete_line_h': 3,
95835             'help.areas.point_or_area_h': 3,
95836             'help.areas.add_area_h': 3,
95837             'help.areas.square_area_h': 3,
95838             'help.areas.modify_area_h': 3,
95839             'help.areas.delete_area_h': 3,
95840             'help.relations.edit_relation_h': 3,
95841             'help.relations.maintain_relation_h': 3,
95842             'help.relations.relation_types_h': 2,
95843             'help.relations.multipolygon_h': 3,
95844             'help.relations.turn_restriction_h': 3,
95845             'help.relations.route_h': 3,
95846             'help.relations.boundary_h': 3,
95847             'help.notes.add_note_h': 3,
95848             'help.notes.update_note_h': 3,
95849             'help.notes.save_note_h': 3,
95850             'help.imagery.sources_h': 3,
95851             'help.imagery.offsets_h': 3,
95852             'help.streetlevel.using_h': 3,
95853             'help.gps.using_h': 3,
95854             'help.qa.tools_h': 3,
95855             'help.qa.issues_h': 3
95856           }; // For each section, squash all the texts into a single markdown document
95857
95858           var docs = docKeys.map(function (key) {
95859             var helpkey = 'help.' + key[0];
95860             var helpPaneReplacements = {
95861               version: context.version
95862             };
95863             var text = key[1].reduce(function (all, part) {
95864               var subkey = helpkey + '.' + part;
95865               var depth = headings[subkey]; // is this subkey a heading?
95866
95867               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
95868
95869               return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
95870             }, '');
95871             return {
95872               title: _t.html(helpkey + '.title'),
95873               content: marked_1(text.trim()) // use keyboard key styling for shortcuts
95874               .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
95875             };
95876           });
95877           var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
95878
95879           helpPane.renderContent = function (content) {
95880             function clickHelp(d, i) {
95881               var rtl = _mainLocalizer.textDirection() === 'rtl';
95882               content.property('scrollTop', 0);
95883               helpPane.selection().select('.pane-heading h2').html(d.title);
95884               body.html(d.content);
95885               body.selectAll('a').attr('target', '_blank');
95886               menuItems.classed('selected', function (m) {
95887                 return m.title === d.title;
95888               });
95889               nav.html('');
95890
95891               if (rtl) {
95892                 nav.call(drawNext).call(drawPrevious);
95893               } else {
95894                 nav.call(drawPrevious).call(drawNext);
95895               }
95896
95897               function drawNext(selection) {
95898                 if (i < docs.length - 1) {
95899                   var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
95900                     d3_event.preventDefault();
95901                     clickHelp(docs[i + 1], i + 1);
95902                   });
95903                   nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
95904                 }
95905               }
95906
95907               function drawPrevious(selection) {
95908                 if (i > 0) {
95909                   var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
95910                     d3_event.preventDefault();
95911                     clickHelp(docs[i - 1], i - 1);
95912                   });
95913                   prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
95914                 }
95915               }
95916             }
95917
95918             function clickWalkthrough(d3_event) {
95919               d3_event.preventDefault();
95920               if (context.inIntro()) return;
95921               context.container().call(uiIntro(context));
95922               context.ui().togglePanes();
95923             }
95924
95925             function clickShortcuts(d3_event) {
95926               d3_event.preventDefault();
95927               context.container().call(context.ui().shortcuts, true);
95928             }
95929
95930             var toc = content.append('ul').attr('class', 'toc');
95931             var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
95932               return d.title;
95933             }).on('click', function (d3_event, d) {
95934               d3_event.preventDefault();
95935               clickHelp(d, docs.indexOf(d));
95936             });
95937             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);
95938             shortcuts.append('div').html(_t.html('shortcuts.title'));
95939             var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
95940             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
95941             walkthrough.append('div').html(_t.html('splash.walkthrough'));
95942             var helpContent = content.append('div').attr('class', 'left-content');
95943             var body = helpContent.append('div').attr('class', 'body');
95944             var nav = helpContent.append('div').attr('class', 'nav');
95945             clickHelp(docs[0], 0);
95946           };
95947
95948           return helpPane;
95949         }
95950
95951         function uiSectionValidationIssues(id, severity, context) {
95952           var _issues = [];
95953           var section = uiSection(id, context).label(function () {
95954             if (!_issues) return '';
95955             var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
95956             return _t('inspector.title_count', {
95957               title: _t.html('issues.' + severity + 's.list_title'),
95958               count: issueCountText
95959             });
95960           }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
95961             return _issues && _issues.length;
95962           });
95963
95964           function getOptions() {
95965             return {
95966               what: corePreferences('validate-what') || 'edited',
95967               where: corePreferences('validate-where') || 'all'
95968             };
95969           } // get and cache the issues to display, unordered
95970
95971
95972           function reloadIssues() {
95973             _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
95974           }
95975
95976           function renderDisclosureContent(selection) {
95977             var center = context.map().center();
95978             var graph = context.graph(); // sort issues by distance away from the center of the map
95979
95980             var issues = _issues.map(function withDistance(issue) {
95981               var extent = issue.extent(graph);
95982               var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
95983               return Object.assign(issue, {
95984                 dist: dist
95985               });
95986             }).sort(function byDistance(a, b) {
95987               return a.dist - b.dist;
95988             }); // cut off at 1000
95989
95990
95991             issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
95992
95993             selection.call(drawIssuesList, issues);
95994           }
95995
95996           function drawIssuesList(selection, issues) {
95997             var list = selection.selectAll('.issues-list').data([0]);
95998             list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
95999             var items = list.selectAll('li').data(issues, function (d) {
96000               return d.id;
96001             }); // Exit
96002
96003             items.exit().remove(); // Enter
96004
96005             var itemsEnter = items.enter().append('li').attr('class', function (d) {
96006               return 'issue severity-' + d.severity;
96007             });
96008             var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
96009               context.validator().focusIssue(d);
96010             }).on('mouseover', function (d3_event, d) {
96011               utilHighlightEntities(d.entityIds, true, context);
96012             }).on('mouseout', function (d3_event, d) {
96013               utilHighlightEntities(d.entityIds, false, context);
96014             });
96015             var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
96016             textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
96017               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
96018               select(this).call(svgIcon(iconName));
96019             });
96020             textEnter.append('span').attr('class', 'issue-message');
96021             /*
96022             labelsEnter
96023                 .append('span')
96024                 .attr('class', 'issue-autofix')
96025                 .each(function(d) {
96026                     if (!d.autoFix) return;
96027                      d3_select(this)
96028                         .append('button')
96029                         .attr('title', t('issues.fix_one.title'))
96030                         .datum(d.autoFix)  // set button datum to the autofix
96031                         .attr('class', 'autofix action')
96032                         .on('click', function(d3_event, d) {
96033                             d3_event.preventDefault();
96034                             d3_event.stopPropagation();
96035                              var issuesEntityIDs = d.issue.entityIds;
96036                             utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
96037                              context.perform.apply(context, d.autoArgs);
96038                             context.validator().validate();
96039                         })
96040                         .call(svgIcon('#iD-icon-wrench'));
96041                 });
96042             */
96043             // Update
96044
96045             items = items.merge(itemsEnter).order();
96046             items.selectAll('.issue-message').html(function (d) {
96047               return d.message(context);
96048             });
96049             /*
96050             // autofix
96051             var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
96052              var autoFixAll = selection.selectAll('.autofix-all')
96053                 .data(canAutoFix.length ? [0] : []);
96054              // exit
96055             autoFixAll.exit()
96056                 .remove();
96057              // enter
96058             var autoFixAllEnter = autoFixAll.enter()
96059                 .insert('div', '.issues-list')
96060                 .attr('class', 'autofix-all');
96061              var linkEnter = autoFixAllEnter
96062                 .append('a')
96063                 .attr('class', 'autofix-all-link')
96064                 .attr('href', '#');
96065              linkEnter
96066                 .append('span')
96067                 .attr('class', 'autofix-all-link-text')
96068                 .html(t.html('issues.fix_all.title'));
96069              linkEnter
96070                 .append('span')
96071                 .attr('class', 'autofix-all-link-icon')
96072                 .call(svgIcon('#iD-icon-wrench'));
96073              if (severity === 'warning') {
96074                 renderIgnoredIssuesReset(selection);
96075             }
96076              // update
96077             autoFixAll = autoFixAll
96078                 .merge(autoFixAllEnter);
96079              autoFixAll.selectAll('.autofix-all-link')
96080                 .on('click', function() {
96081                     context.pauseChangeDispatch();
96082                     context.perform(actionNoop());
96083                     canAutoFix.forEach(function(issue) {
96084                         var args = issue.autoFix.autoArgs.slice();  // copy
96085                         if (typeof args[args.length - 1] !== 'function') {
96086                             args.pop();
96087                         }
96088                         args.push(t('issues.fix_all.annotation'));
96089                         context.replace.apply(context, args);
96090                     });
96091                     context.resumeChangeDispatch();
96092                     context.validator().validate();
96093                 });
96094             */
96095           }
96096
96097           context.validator().on('validated.uiSectionValidationIssues' + id, function () {
96098             window.requestIdleCallback(function () {
96099               reloadIssues();
96100               section.reRender();
96101             });
96102           });
96103           context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
96104             window.requestIdleCallback(function () {
96105               if (getOptions().where === 'visible') {
96106                 // must refetch issues if they are viewport-dependent
96107                 reloadIssues();
96108               } // always reload list to re-sort-by-distance
96109
96110
96111               section.reRender();
96112             });
96113           }, 1000));
96114           return section;
96115         }
96116
96117         function uiSectionValidationOptions(context) {
96118           var section = uiSection('issues-options', context).content(renderContent);
96119
96120           function renderContent(selection) {
96121             var container = selection.selectAll('.issues-options-container').data([0]);
96122             container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
96123             var data = [{
96124               key: 'what',
96125               values: ['edited', 'all']
96126             }, {
96127               key: 'where',
96128               values: ['visible', 'all']
96129             }];
96130             var options = container.selectAll('.issues-option').data(data, function (d) {
96131               return d.key;
96132             });
96133             var optionsEnter = options.enter().append('div').attr('class', function (d) {
96134               return 'issues-option issues-option-' + d.key;
96135             });
96136             optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
96137               return _t.html('issues.options.' + d.key + '.title');
96138             });
96139             var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
96140               return d.values.map(function (val) {
96141                 return {
96142                   value: val,
96143                   key: d.key
96144                 };
96145               });
96146             }).enter().append('label');
96147             valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
96148               return 'issues-option-' + d.key;
96149             }).attr('value', function (d) {
96150               return d.value;
96151             }).property('checked', function (d) {
96152               return getOptions()[d.key] === d.value;
96153             }).on('change', function (d3_event, d) {
96154               updateOptionValue(d3_event, d.key, d.value);
96155             });
96156             valuesEnter.append('span').html(function (d) {
96157               return _t.html('issues.options.' + d.key + '.' + d.value);
96158             });
96159           }
96160
96161           function getOptions() {
96162             return {
96163               what: corePreferences('validate-what') || 'edited',
96164               // 'all', 'edited'
96165               where: corePreferences('validate-where') || 'all' // 'all', 'visible'
96166
96167             };
96168           }
96169
96170           function updateOptionValue(d3_event, d, val) {
96171             if (!val && d3_event && d3_event.target) {
96172               val = d3_event.target.value;
96173             }
96174
96175             corePreferences('validate-' + d, val);
96176             context.validator().validate();
96177           }
96178
96179           return section;
96180         }
96181
96182         function uiSectionValidationRules(context) {
96183           var MINSQUARE = 0;
96184           var MAXSQUARE = 20;
96185           var DEFAULTSQUARE = 5; // see also unsquare_way.js
96186
96187           var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
96188
96189           var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
96190             return key !== 'maprules';
96191           }).sort(function (key1, key2) {
96192             // alphabetize by localized title
96193             return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
96194           });
96195
96196           function renderDisclosureContent(selection) {
96197             var container = selection.selectAll('.issues-rulelist-container').data([0]);
96198             var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
96199             containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
96200             var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
96201             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
96202               d3_event.preventDefault();
96203               context.validator().disableRules(_ruleKeys);
96204             });
96205             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
96206               d3_event.preventDefault();
96207               context.validator().disableRules([]);
96208             }); // Update
96209
96210             container = container.merge(containerEnter);
96211             container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
96212           }
96213
96214           function drawListItems(selection, data, type, name, change, active) {
96215             var items = selection.selectAll('li').data(data); // Exit
96216
96217             items.exit().remove(); // Enter
96218
96219             var enter = items.enter().append('li');
96220
96221             if (name === 'rule') {
96222               enter.call(uiTooltip().title(function (d) {
96223                 return _t.html('issues.' + d + '.tip');
96224               }).placement('top'));
96225             }
96226
96227             var label = enter.append('label');
96228             label.append('input').attr('type', type).attr('name', name).on('change', change);
96229             label.append('span').html(function (d) {
96230               var params = {};
96231
96232               if (d === 'unsquare_way') {
96233                 params.val = '<span class="square-degrees"></span>';
96234               }
96235
96236               return _t.html('issues.' + d + '.title', params);
96237             }); // Update
96238
96239             items = items.merge(enter);
96240             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
96241
96242             var degStr = corePreferences('validate-square-degrees');
96243
96244             if (degStr === null) {
96245               degStr = DEFAULTSQUARE.toString();
96246             }
96247
96248             var span = items.selectAll('.square-degrees');
96249             var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
96250
96251             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) {
96252               d3_event.preventDefault();
96253               d3_event.stopPropagation();
96254               this.select();
96255             }).on('keyup', function (d3_event) {
96256               if (d3_event.keyCode === 13) {
96257                 // ↩ Return
96258                 this.blur();
96259                 this.select();
96260               }
96261             }).on('blur', changeSquare).merge(input).property('value', degStr);
96262           }
96263
96264           function changeSquare() {
96265             var input = select(this);
96266             var degStr = utilGetSetValue(input).trim();
96267             var degNum = parseFloat(degStr, 10);
96268
96269             if (!isFinite(degNum)) {
96270               degNum = DEFAULTSQUARE;
96271             } else if (degNum > MAXSQUARE) {
96272               degNum = MAXSQUARE;
96273             } else if (degNum < MINSQUARE) {
96274               degNum = MINSQUARE;
96275             }
96276
96277             degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
96278
96279             degStr = degNum.toString();
96280             input.property('value', degStr);
96281             corePreferences('validate-square-degrees', degStr);
96282             context.validator().reloadUnsquareIssues();
96283           }
96284
96285           function isRuleEnabled(d) {
96286             return context.validator().isRuleEnabled(d);
96287           }
96288
96289           function toggleRule(d3_event, d) {
96290             context.validator().toggleRule(d);
96291           }
96292
96293           context.validator().on('validated.uiSectionValidationRules', function () {
96294             window.requestIdleCallback(section.reRender);
96295           });
96296           return section;
96297         }
96298
96299         function uiSectionValidationStatus(context) {
96300           var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
96301             var issues = context.validator().getIssues(getOptions());
96302             return issues.length === 0;
96303           });
96304
96305           function getOptions() {
96306             return {
96307               what: corePreferences('validate-what') || 'edited',
96308               where: corePreferences('validate-where') || 'all'
96309             };
96310           }
96311
96312           function renderContent(selection) {
96313             var box = selection.selectAll('.box').data([0]);
96314             var boxEnter = box.enter().append('div').attr('class', 'box');
96315             boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
96316             var noIssuesMessage = boxEnter.append('span');
96317             noIssuesMessage.append('strong').attr('class', 'message');
96318             noIssuesMessage.append('br');
96319             noIssuesMessage.append('span').attr('class', 'details');
96320             renderIgnoredIssuesReset(selection);
96321             setNoIssuesText(selection);
96322           }
96323
96324           function renderIgnoredIssuesReset(selection) {
96325             var ignoredIssues = context.validator().getIssues({
96326               what: 'all',
96327               where: 'all',
96328               includeDisabledRules: true,
96329               includeIgnored: 'only'
96330             });
96331             var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
96332
96333             resetIgnored.exit().remove(); // enter
96334
96335             var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
96336             resetIgnoredEnter.append('a').attr('href', '#'); // update
96337
96338             resetIgnored = resetIgnored.merge(resetIgnoredEnter);
96339             resetIgnored.select('a').html(_t('inspector.title_count', {
96340               title: _t.html('issues.reset_ignored'),
96341               count: ignoredIssues.length
96342             }));
96343             resetIgnored.on('click', function (d3_event) {
96344               d3_event.preventDefault();
96345               context.validator().resetIgnoredIssues();
96346             });
96347           }
96348
96349           function setNoIssuesText(selection) {
96350             var opts = getOptions();
96351
96352             function checkForHiddenIssues(cases) {
96353               for (var type in cases) {
96354                 var hiddenOpts = cases[type];
96355                 var hiddenIssues = context.validator().getIssues(hiddenOpts);
96356
96357                 if (hiddenIssues.length) {
96358                   selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
96359                     count: hiddenIssues.length.toString()
96360                   }));
96361                   return;
96362                 }
96363               }
96364
96365               selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
96366             }
96367
96368             var messageType;
96369
96370             if (opts.what === 'edited' && opts.where === 'visible') {
96371               messageType = 'edits_in_view';
96372               checkForHiddenIssues({
96373                 elsewhere: {
96374                   what: 'edited',
96375                   where: 'all'
96376                 },
96377                 everything_else: {
96378                   what: 'all',
96379                   where: 'visible'
96380                 },
96381                 disabled_rules: {
96382                   what: 'edited',
96383                   where: 'visible',
96384                   includeDisabledRules: 'only'
96385                 },
96386                 everything_else_elsewhere: {
96387                   what: 'all',
96388                   where: 'all'
96389                 },
96390                 disabled_rules_elsewhere: {
96391                   what: 'edited',
96392                   where: 'all',
96393                   includeDisabledRules: 'only'
96394                 },
96395                 ignored_issues: {
96396                   what: 'edited',
96397                   where: 'visible',
96398                   includeIgnored: 'only'
96399                 },
96400                 ignored_issues_elsewhere: {
96401                   what: 'edited',
96402                   where: 'all',
96403                   includeIgnored: 'only'
96404                 }
96405               });
96406             } else if (opts.what === 'edited' && opts.where === 'all') {
96407               messageType = 'edits';
96408               checkForHiddenIssues({
96409                 everything_else: {
96410                   what: 'all',
96411                   where: 'all'
96412                 },
96413                 disabled_rules: {
96414                   what: 'edited',
96415                   where: 'all',
96416                   includeDisabledRules: 'only'
96417                 },
96418                 ignored_issues: {
96419                   what: 'edited',
96420                   where: 'all',
96421                   includeIgnored: 'only'
96422                 }
96423               });
96424             } else if (opts.what === 'all' && opts.where === 'visible') {
96425               messageType = 'everything_in_view';
96426               checkForHiddenIssues({
96427                 elsewhere: {
96428                   what: 'all',
96429                   where: 'all'
96430                 },
96431                 disabled_rules: {
96432                   what: 'all',
96433                   where: 'visible',
96434                   includeDisabledRules: 'only'
96435                 },
96436                 disabled_rules_elsewhere: {
96437                   what: 'all',
96438                   where: 'all',
96439                   includeDisabledRules: 'only'
96440                 },
96441                 ignored_issues: {
96442                   what: 'all',
96443                   where: 'visible',
96444                   includeIgnored: 'only'
96445                 },
96446                 ignored_issues_elsewhere: {
96447                   what: 'all',
96448                   where: 'all',
96449                   includeIgnored: 'only'
96450                 }
96451               });
96452             } else if (opts.what === 'all' && opts.where === 'all') {
96453               messageType = 'everything';
96454               checkForHiddenIssues({
96455                 disabled_rules: {
96456                   what: 'all',
96457                   where: 'all',
96458                   includeDisabledRules: 'only'
96459                 },
96460                 ignored_issues: {
96461                   what: 'all',
96462                   where: 'all',
96463                   includeIgnored: 'only'
96464                 }
96465               });
96466             }
96467
96468             if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
96469               messageType = 'no_edits';
96470             }
96471
96472             selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
96473           }
96474
96475           context.validator().on('validated.uiSectionValidationStatus', function () {
96476             window.requestIdleCallback(section.reRender);
96477           });
96478           context.map().on('move.uiSectionValidationStatus', debounce(function () {
96479             window.requestIdleCallback(section.reRender);
96480           }, 1000));
96481           return section;
96482         }
96483
96484         function uiPaneIssues(context) {
96485           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)]);
96486           return issuesPane;
96487         }
96488
96489         function uiSettingsCustomData(context) {
96490           var dispatch$1 = dispatch('change');
96491
96492           function render(selection) {
96493             var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
96494
96495             var _origSettings = {
96496               fileList: dataLayer && dataLayer.fileList() || null,
96497               url: corePreferences('settings-custom-data-url')
96498             };
96499             var _currSettings = {
96500               fileList: dataLayer && dataLayer.fileList() || null,
96501               url: corePreferences('settings-custom-data-url')
96502             }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
96503
96504             var modal = uiConfirm(selection).okButton();
96505             modal.classed('settings-modal settings-custom-data', true);
96506             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
96507             var textSection = modal.select('.modal-section.message-text');
96508             textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
96509             textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
96510             .on('change', function (d3_event) {
96511               var files = d3_event.target.files;
96512
96513               if (files && files.length) {
96514                 _currSettings.url = '';
96515                 textSection.select('.field-url').property('value', '');
96516                 _currSettings.fileList = files;
96517               } else {
96518                 _currSettings.fileList = null;
96519               }
96520             });
96521             textSection.append('h4').html(_t.html('settings.custom_data.or'));
96522             textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
96523             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
96524
96525             var buttonSection = modal.select('.modal-section.buttons');
96526             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
96527             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
96528             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
96529
96530             function isSaveDisabled() {
96531               return null;
96532             } // restore the original url
96533
96534
96535             function clickCancel() {
96536               textSection.select('.field-url').property('value', _origSettings.url);
96537               corePreferences('settings-custom-data-url', _origSettings.url);
96538               this.blur();
96539               modal.close();
96540             } // accept the current url
96541
96542
96543             function clickSave() {
96544               _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
96545
96546               if (_currSettings.url) {
96547                 _currSettings.fileList = null;
96548               }
96549
96550               if (_currSettings.fileList) {
96551                 _currSettings.url = '';
96552               }
96553
96554               corePreferences('settings-custom-data-url', _currSettings.url);
96555               this.blur();
96556               modal.close();
96557               dispatch$1.call('change', this, _currSettings);
96558             }
96559           }
96560
96561           return utilRebind(render, dispatch$1, 'on');
96562         }
96563
96564         function uiSectionDataLayers(context) {
96565           var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
96566           var layers = context.layers();
96567           var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
96568
96569           function renderDisclosureContent(selection) {
96570             var container = selection.selectAll('.data-layer-container').data([0]);
96571             container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
96572             .call(drawPanelItems);
96573           }
96574
96575           function showsLayer(which) {
96576             var layer = layers.layer(which);
96577
96578             if (layer) {
96579               return layer.enabled();
96580             }
96581
96582             return false;
96583           }
96584
96585           function setLayer(which, enabled) {
96586             // Don't allow layer changes while drawing - #6584
96587             var mode = context.mode();
96588             if (mode && /^draw/.test(mode.id)) return;
96589             var layer = layers.layer(which);
96590
96591             if (layer) {
96592               layer.enabled(enabled);
96593
96594               if (!enabled && (which === 'osm' || which === 'notes')) {
96595                 context.enter(modeBrowse(context));
96596               }
96597             }
96598           }
96599
96600           function toggleLayer(which) {
96601             setLayer(which, !showsLayer(which));
96602           }
96603
96604           function drawOsmItems(selection) {
96605             var osmKeys = ['osm', 'notes'];
96606             var osmLayers = layers.all().filter(function (obj) {
96607               return osmKeys.indexOf(obj.id) !== -1;
96608             });
96609             var ul = selection.selectAll('.layer-list-osm').data([0]);
96610             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
96611             var li = ul.selectAll('.list-item').data(osmLayers);
96612             li.exit().remove();
96613             var liEnter = li.enter().append('li').attr('class', function (d) {
96614               return 'list-item list-item-' + d.id;
96615             });
96616             var labelEnter = liEnter.append('label').each(function (d) {
96617               if (d.id === 'osm') {
96618                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
96619               } else {
96620                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
96621               }
96622             });
96623             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
96624               toggleLayer(d.id);
96625             });
96626             labelEnter.append('span').html(function (d) {
96627               return _t.html('map_data.layers.' + d.id + '.title');
96628             }); // Update
96629
96630             li.merge(liEnter).classed('active', function (d) {
96631               return d.layer.enabled();
96632             }).selectAll('input').property('checked', function (d) {
96633               return d.layer.enabled();
96634             });
96635           }
96636
96637           function drawQAItems(selection) {
96638             var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
96639             var qaLayers = layers.all().filter(function (obj) {
96640               return qaKeys.indexOf(obj.id) !== -1;
96641             });
96642             var ul = selection.selectAll('.layer-list-qa').data([0]);
96643             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
96644             var li = ul.selectAll('.list-item').data(qaLayers);
96645             li.exit().remove();
96646             var liEnter = li.enter().append('li').attr('class', function (d) {
96647               return 'list-item list-item-' + d.id;
96648             });
96649             var labelEnter = liEnter.append('label').each(function (d) {
96650               select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
96651             });
96652             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
96653               toggleLayer(d.id);
96654             });
96655             labelEnter.append('span').html(function (d) {
96656               return _t.html('map_data.layers.' + d.id + '.title');
96657             }); // Update
96658
96659             li.merge(liEnter).classed('active', function (d) {
96660               return d.layer.enabled();
96661             }).selectAll('input').property('checked', function (d) {
96662               return d.layer.enabled();
96663             });
96664           } // Beta feature - sample vector layers to support Detroit Mapping Challenge
96665           // https://github.com/osmus/detroit-mapping-challenge
96666
96667
96668           function drawVectorItems(selection) {
96669             var dataLayer = layers.layer('data');
96670             var vtData = [{
96671               name: 'Detroit Neighborhoods/Parks',
96672               src: 'neighborhoods-parks',
96673               tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
96674               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'
96675             }, {
96676               name: 'Detroit Composite POIs',
96677               src: 'composite-poi',
96678               tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
96679               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'
96680             }, {
96681               name: 'Detroit All-The-Places POIs',
96682               src: 'alltheplaces-poi',
96683               tooltip: 'Public domain business location data created by web scrapers.',
96684               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'
96685             }]; // Only show this if the map is around Detroit..
96686
96687             var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
96688             var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
96689             var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
96690             container.exit().remove();
96691             var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
96692             containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
96693             containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
96694             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');
96695             container = container.merge(containerEnter);
96696             var ul = container.selectAll('.layer-list-vectortile');
96697             var li = ul.selectAll('.list-item').data(vtData);
96698             li.exit().remove();
96699             var liEnter = li.enter().append('li').attr('class', function (d) {
96700               return 'list-item list-item-' + d.src;
96701             });
96702             var labelEnter = liEnter.append('label').each(function (d) {
96703               select(this).call(uiTooltip().title(d.tooltip).placement('top'));
96704             });
96705             labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
96706             labelEnter.append('span').html(function (d) {
96707               return d.name;
96708             }); // Update
96709
96710             li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
96711
96712             function isVTLayerSelected(d) {
96713               return dataLayer && dataLayer.template() === d.template;
96714             }
96715
96716             function selectVTLayer(d3_event, d) {
96717               corePreferences('settings-custom-data-url', d.template);
96718
96719               if (dataLayer) {
96720                 dataLayer.template(d.template, d.src);
96721                 dataLayer.enabled(true);
96722               }
96723             }
96724           }
96725
96726           function drawCustomDataItems(selection) {
96727             var dataLayer = layers.layer('data');
96728             var hasData = dataLayer && dataLayer.hasData();
96729             var showsData = hasData && dataLayer.enabled();
96730             var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
96731
96732             ul.exit().remove(); // Enter
96733
96734             var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
96735             var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
96736             var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
96737             labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
96738               toggleLayer('data');
96739             });
96740             labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
96741             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) {
96742               d3_event.preventDefault();
96743               editCustom();
96744             }).call(svgIcon('#iD-icon-more'));
96745             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) {
96746               if (select(this).classed('disabled')) return;
96747               d3_event.preventDefault();
96748               d3_event.stopPropagation();
96749               dataLayer.fitZoom();
96750             }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
96751
96752             ul = ul.merge(ulEnter);
96753             ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
96754             ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
96755           }
96756
96757           function editCustom() {
96758             context.container().call(settingsCustomData);
96759           }
96760
96761           function customChanged(d) {
96762             var dataLayer = layers.layer('data');
96763
96764             if (d && d.url) {
96765               dataLayer.url(d.url);
96766             } else if (d && d.fileList) {
96767               dataLayer.fileList(d.fileList);
96768             }
96769           }
96770
96771           function drawPanelItems(selection) {
96772             var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
96773             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'));
96774             historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96775               d3_event.preventDefault();
96776               context.ui().info.toggle('history');
96777             });
96778             historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
96779             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'));
96780             measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96781               d3_event.preventDefault();
96782               context.ui().info.toggle('measurement');
96783             });
96784             measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
96785           }
96786
96787           context.layers().on('change.uiSectionDataLayers', section.reRender);
96788           context.map().on('move.uiSectionDataLayers', debounce(function () {
96789             // Detroit layers may have moved in or out of view
96790             window.requestIdleCallback(section.reRender);
96791           }, 1000));
96792           return section;
96793         }
96794
96795         function uiSectionMapFeatures(context) {
96796           var _features = context.features().keys();
96797
96798           var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
96799
96800           function renderDisclosureContent(selection) {
96801             var container = selection.selectAll('.layer-feature-list-container').data([0]);
96802             var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
96803             containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
96804             var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
96805             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
96806               d3_event.preventDefault();
96807               context.features().disableAll();
96808             });
96809             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
96810               d3_event.preventDefault();
96811               context.features().enableAll();
96812             }); // Update
96813
96814             container = container.merge(containerEnter);
96815             container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
96816           }
96817
96818           function drawListItems(selection, data, type, name, change, active) {
96819             var items = selection.selectAll('li').data(data); // Exit
96820
96821             items.exit().remove(); // Enter
96822
96823             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
96824               var tip = _t.html(name + '.' + d + '.tooltip');
96825
96826               if (autoHiddenFeature(d)) {
96827                 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
96828                 tip += '<div>' + msg + '</div>';
96829               }
96830
96831               return tip;
96832             }).placement('top'));
96833             var label = enter.append('label');
96834             label.append('input').attr('type', type).attr('name', name).on('change', change);
96835             label.append('span').html(function (d) {
96836               return _t.html(name + '.' + d + '.description');
96837             }); // Update
96838
96839             items = items.merge(enter);
96840             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
96841           }
96842
96843           function autoHiddenFeature(d) {
96844             return context.features().autoHidden(d);
96845           }
96846
96847           function showsFeature(d) {
96848             return context.features().enabled(d);
96849           }
96850
96851           function clickFeature(d3_event, d) {
96852             context.features().toggle(d);
96853           }
96854
96855           function showsLayer(id) {
96856             var layer = context.layers().layer(id);
96857             return layer && layer.enabled();
96858           } // add listeners
96859
96860
96861           context.features().on('change.map_features', section.reRender);
96862           return section;
96863         }
96864
96865         function uiSectionMapStyleOptions(context) {
96866           var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
96867
96868           function renderDisclosureContent(selection) {
96869             var container = selection.selectAll('.layer-fill-list').data([0]);
96870             container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
96871             var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
96872             container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
96873               return context.surface().classed('highlight-edited');
96874             });
96875           }
96876
96877           function drawListItems(selection, data, type, name, change, active) {
96878             var items = selection.selectAll('li').data(data); // Exit
96879
96880             items.exit().remove(); // Enter
96881
96882             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
96883               return _t.html(name + '.' + d + '.tooltip');
96884             }).keys(function (d) {
96885               var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
96886               if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
96887               return key ? [key] : null;
96888             }).placement('top'));
96889             var label = enter.append('label');
96890             label.append('input').attr('type', type).attr('name', name).on('change', change);
96891             label.append('span').html(function (d) {
96892               return _t.html(name + '.' + d + '.description');
96893             }); // Update
96894
96895             items = items.merge(enter);
96896             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
96897           }
96898
96899           function isActiveFill(d) {
96900             return context.map().activeAreaFill() === d;
96901           }
96902
96903           function toggleHighlightEdited(d3_event) {
96904             d3_event.preventDefault();
96905             context.map().toggleHighlightEdited();
96906           }
96907
96908           function setFill(d3_event, d) {
96909             context.map().activeAreaFill(d);
96910           }
96911
96912           context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
96913           return section;
96914         }
96915
96916         function uiSectionPhotoOverlays(context) {
96917           var layers = context.layers();
96918           var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
96919
96920           function renderDisclosureContent(selection) {
96921             var container = selection.selectAll('.photo-overlay-container').data([0]);
96922             container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
96923           }
96924
96925           function drawPhotoItems(selection) {
96926             var photoKeys = context.photos().overlayLayerIDs();
96927             var photoLayers = layers.all().filter(function (obj) {
96928               return photoKeys.indexOf(obj.id) !== -1;
96929             });
96930             var data = photoLayers.filter(function (obj) {
96931               return obj.layer.supported();
96932             });
96933
96934             function layerSupported(d) {
96935               return d.layer && d.layer.supported();
96936             }
96937
96938             function layerEnabled(d) {
96939               return layerSupported(d) && d.layer.enabled();
96940             }
96941
96942             var ul = selection.selectAll('.layer-list-photos').data([0]);
96943             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
96944             var li = ul.selectAll('.list-item-photos').data(data);
96945             li.exit().remove();
96946             var liEnter = li.enter().append('li').attr('class', function (d) {
96947               var classes = 'list-item-photos list-item-' + d.id;
96948
96949               if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
96950                 classes += ' indented';
96951               }
96952
96953               return classes;
96954             });
96955             var labelEnter = liEnter.append('label').each(function (d) {
96956               var titleID;
96957               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';
96958               select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
96959             });
96960             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
96961               toggleLayer(d.id);
96962             });
96963             labelEnter.append('span').html(function (d) {
96964               var id = d.id;
96965               if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
96966               return _t.html(id.replace(/-/g, '_') + '.title');
96967             }); // Update
96968
96969             li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
96970           }
96971
96972           function drawPhotoTypeItems(selection) {
96973             var data = context.photos().allPhotoTypes();
96974
96975             function typeEnabled(d) {
96976               return context.photos().showsPhotoType(d);
96977             }
96978
96979             var ul = selection.selectAll('.layer-list-photo-types').data([0]);
96980             ul.exit().remove();
96981             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
96982             var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
96983             li.exit().remove();
96984             var liEnter = li.enter().append('li').attr('class', function (d) {
96985               return 'list-item-photo-types list-item-' + d;
96986             });
96987             var labelEnter = liEnter.append('label').each(function (d) {
96988               select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
96989             });
96990             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
96991               context.photos().togglePhotoType(d);
96992             });
96993             labelEnter.append('span').html(function (d) {
96994               return _t.html('photo_overlays.photo_type.' + d + '.title');
96995             }); // Update
96996
96997             li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
96998           }
96999
97000           function drawDateFilter(selection) {
97001             var data = context.photos().dateFilters();
97002
97003             function filterEnabled(d) {
97004               return context.photos().dateFilterValue(d);
97005             }
97006
97007             var ul = selection.selectAll('.layer-list-date-filter').data([0]);
97008             ul.exit().remove();
97009             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
97010             var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
97011             li.exit().remove();
97012             var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
97013             var labelEnter = liEnter.append('label').each(function (d) {
97014               select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
97015             });
97016             labelEnter.append('span').html(function (d) {
97017               return _t.html('photo_overlays.date_filter.' + d + '.title');
97018             });
97019             labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
97020               utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97021             }).on('change', function (d3_event, d) {
97022               var value = utilGetSetValue(select(this)).trim();
97023               context.photos().setDateFilter(d, value, true); // reload the displayed dates
97024
97025               li.selectAll('input').each(function (d) {
97026                 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97027               });
97028             });
97029             li = li.merge(liEnter).classed('active', filterEnabled);
97030           }
97031
97032           function drawUsernameFilter(selection) {
97033             function filterEnabled() {
97034               return context.photos().usernames();
97035             }
97036
97037             var ul = selection.selectAll('.layer-list-username-filter').data([0]);
97038             ul.exit().remove();
97039             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
97040             var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
97041             li.exit().remove();
97042             var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
97043             var labelEnter = liEnter.append('label').each(function () {
97044               select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
97045             });
97046             labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
97047             labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
97048               var value = select(this).property('value');
97049               context.photos().setUsernameFilter(value, true);
97050               select(this).property('value', usernameValue);
97051             });
97052             li.merge(liEnter).classed('active', filterEnabled);
97053
97054             function usernameValue() {
97055               var usernames = context.photos().usernames();
97056               if (usernames) return usernames.join('; ');
97057               return usernames;
97058             }
97059           }
97060
97061           function toggleLayer(which) {
97062             setLayer(which, !showsLayer(which));
97063           }
97064
97065           function showsLayer(which) {
97066             var layer = layers.layer(which);
97067
97068             if (layer) {
97069               return layer.enabled();
97070             }
97071
97072             return false;
97073           }
97074
97075           function setLayer(which, enabled) {
97076             var layer = layers.layer(which);
97077
97078             if (layer) {
97079               layer.enabled(enabled);
97080             }
97081           }
97082
97083           context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
97084           context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
97085           return section;
97086         }
97087
97088         function uiPaneMapData(context) {
97089           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)]);
97090           return mapDataPane;
97091         }
97092
97093         function uiSectionPrivacy(context) {
97094           var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
97095
97096           var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
97097
97098           function renderDisclosureContent(selection) {
97099             // enter
97100             var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
97101             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'));
97102             thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97103               d3_event.preventDefault();
97104               _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
97105               corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
97106               update();
97107             });
97108             thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
97109
97110             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'));
97111             update();
97112
97113             function update() {
97114               selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
97115             }
97116           }
97117
97118           return section;
97119         }
97120
97121         function uiPanePreferences(context) {
97122           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)]);
97123           return preferencesPane;
97124         }
97125
97126         function uiInit(context) {
97127           var _initCounter = 0;
97128           var _needWidth = {};
97129
97130           var _lastPointerType;
97131
97132           function render(container) {
97133             container.on('click.ui', function (d3_event) {
97134               // we're only concerned with the primary mouse button
97135               if (d3_event.button !== 0) return;
97136               if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
97137
97138               var isOkayTarget = d3_event.composedPath().some(function (node) {
97139                 // we only care about element nodes
97140                 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
97141                 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
97142                 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
97143                 node.nodeName === 'A');
97144               });
97145               if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
97146
97147               d3_event.preventDefault();
97148             });
97149             var detected = utilDetect(); // only WebKit supports gesture events
97150
97151             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
97152             // but we only need to do this on desktop Safari anyway. – #7694
97153             !detected.isMobileWebKit) {
97154               // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
97155               // CSS property, but on desktop Safari we need to manually cancel the
97156               // default gesture events.
97157               container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
97158                 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
97159                 d3_event.preventDefault();
97160               });
97161             }
97162
97163             if ('PointerEvent' in window) {
97164               select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
97165                 var pointerType = d3_event.pointerType || 'mouse';
97166
97167                 if (_lastPointerType !== pointerType) {
97168                   _lastPointerType = pointerType;
97169                   container.attr('pointer', pointerType);
97170                 }
97171               }, true);
97172             } else {
97173               _lastPointerType = 'mouse';
97174               container.attr('pointer', 'mouse');
97175             }
97176
97177             container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
97178
97179             container.call(uiFullScreen(context));
97180             var map = context.map();
97181             map.redrawEnable(false); // don't draw until we've set zoom/lat/long
97182
97183             map.on('hitMinZoom.ui', function () {
97184               ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
97185             });
97186             container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
97187             container.append('div').attr('class', 'sidebar').call(ui.sidebar);
97188             var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
97189
97190             content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
97191             content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
97192             var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
97193             // pressing, even if it's not targeted. This conflicts with long-pressing
97194             // to show the edit menu. We add a selectable offscreen element as the first
97195             // child to trick Safari into not showing the selection UI.
97196
97197             overMap.append('div').attr('class', 'select-trap').text('t');
97198             overMap.call(uiMapInMap(context)).call(uiNotice(context));
97199             overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
97200
97201             var controls = overMap.append('div').attr('class', 'map-controls');
97202             controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
97203             controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
97204             controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context)); // Add panes
97205             // This should happen after map is initialized, as some require surface()
97206
97207             var panes = overMap.append('div').attr('class', 'map-panes');
97208             var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
97209             uiPanes.forEach(function (pane) {
97210               controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
97211               panes.call(pane.renderPane);
97212             });
97213             ui.info = uiInfo(context);
97214             overMap.call(ui.info);
97215             overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left,  'ar'=right
97216             .classed('hide', true).call(ui.photoviewer);
97217             overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
97218
97219             var about = content.append('div').attr('class', 'map-footer');
97220             about.append('div').attr('class', 'api-status').call(uiStatus(context));
97221             var footer = about.append('div').attr('class', 'map-footer-bar fillD');
97222             footer.append('div').attr('class', 'flash-wrap footer-hide');
97223             var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
97224             footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
97225             var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
97226             aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
97227             var apiConnections = context.apiConnections();
97228
97229             if (apiConnections && apiConnections.length > 1) {
97230               aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
97231             }
97232
97233             aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
97234             aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
97235             var issueLinks = aboutList.append('li');
97236             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'));
97237             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'));
97238             aboutList.append('li').attr('class', 'version').call(uiVersion(context));
97239
97240             if (!context.embed()) {
97241               aboutList.call(uiAccount(context));
97242             } // Setup map dimensions and move map to initial center/zoom.
97243             // This should happen after .main-content and toolbars exist.
97244
97245
97246             ui.onResize();
97247             map.redrawEnable(true);
97248             ui.hash = behaviorHash(context);
97249             ui.hash();
97250
97251             if (!ui.hash.hadHash) {
97252               map.centerZoom([0, 0], 2);
97253             } // Bind events
97254
97255
97256             window.onbeforeunload = function () {
97257               return context.save();
97258             };
97259
97260             window.onunload = function () {
97261               context.history().unlock();
97262             };
97263
97264             select(window).on('resize.editor', function () {
97265               ui.onResize();
97266             });
97267             var panPixels = 80;
97268             context.keybinding().on('⌫', function (d3_event) {
97269               d3_event.preventDefault();
97270             }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
97271             .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) {
97272               if (d3_event) {
97273                 d3_event.stopImmediatePropagation();
97274                 d3_event.preventDefault();
97275               }
97276
97277               var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
97278
97279               if (previousBackground) {
97280                 var currentBackground = context.background().baseLayerSource();
97281                 corePreferences('background-last-used-toggle', currentBackground.id);
97282                 corePreferences('background-last-used', previousBackground.id);
97283                 context.background().baseLayerSource(previousBackground);
97284               }
97285             }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
97286               d3_event.preventDefault();
97287               d3_event.stopPropagation();
97288               context.map().toggleWireframe();
97289             }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
97290               d3_event.preventDefault();
97291               d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
97292
97293               var mode = context.mode();
97294               if (mode && /^draw/.test(mode.id)) return;
97295               var layer = context.layers().layer('osm');
97296
97297               if (layer) {
97298                 layer.enabled(!layer.enabled());
97299
97300                 if (!layer.enabled()) {
97301                   context.enter(modeBrowse(context));
97302                 }
97303               }
97304             }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
97305               d3_event.preventDefault();
97306               context.map().toggleHighlightEdited();
97307             });
97308             context.on('enter.editor', function (entered) {
97309               container.classed('mode-' + entered.id, true);
97310             }).on('exit.editor', function (exited) {
97311               container.classed('mode-' + exited.id, false);
97312             });
97313             context.enter(modeBrowse(context));
97314
97315             if (!_initCounter++) {
97316               if (!ui.hash.startWalkthrough) {
97317                 context.container().call(uiSplash(context)).call(uiRestore(context));
97318               }
97319
97320               context.container().call(ui.shortcuts);
97321             }
97322
97323             var osm = context.connection();
97324             var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
97325
97326             if (osm && auth) {
97327               osm.on('authLoading.ui', function () {
97328                 context.container().call(auth);
97329               }).on('authDone.ui', function () {
97330                 auth.close();
97331               });
97332             }
97333
97334             _initCounter++;
97335
97336             if (ui.hash.startWalkthrough) {
97337               ui.hash.startWalkthrough = false;
97338               context.container().call(uiIntro(context));
97339             }
97340
97341             function pan(d) {
97342               return function (d3_event) {
97343                 if (d3_event.shiftKey) return;
97344                 if (context.container().select('.combobox').size()) return;
97345                 d3_event.preventDefault();
97346                 context.map().pan(d, 100);
97347               };
97348             }
97349           }
97350
97351           var ui = {};
97352
97353           var _loadPromise; // renders the iD interface into the container node
97354
97355
97356           ui.ensureLoaded = function () {
97357             if (_loadPromise) return _loadPromise;
97358             return _loadPromise = Promise.all([// must have strings and presets before loading the UI
97359             _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
97360               if (!context.container().empty()) render(context.container());
97361             })["catch"](function (err) {
97362               return console.error(err);
97363             }); // eslint-disable-line
97364           }; // `ui.restart()` will destroy and rebuild the entire iD interface,
97365           // for example to switch the locale while iD is running.
97366
97367
97368           ui.restart = function () {
97369             context.keybinding().clear();
97370             _loadPromise = null;
97371             context.container().selectAll('*').remove();
97372             ui.ensureLoaded();
97373           };
97374
97375           ui.lastPointerType = function () {
97376             return _lastPointerType;
97377           };
97378
97379           ui.svgDefs = svgDefs(context);
97380           ui.flash = uiFlash(context);
97381           ui.sidebar = uiSidebar(context);
97382           ui.photoviewer = uiPhotoviewer(context);
97383           ui.shortcuts = uiShortcuts(context);
97384
97385           ui.onResize = function (withPan) {
97386             var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
97387             // This will call `getBoundingClientRect` and trigger reflow,
97388             //  but the values will be cached for later use.
97389
97390             var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
97391             utilGetDimensions(context.container().select('.sidebar'), true);
97392
97393             if (withPan !== undefined) {
97394               map.redrawEnable(false);
97395               map.pan(withPan);
97396               map.redrawEnable(true);
97397             }
97398
97399             map.dimensions(mapDimensions);
97400             ui.photoviewer.onMapResize(); // check if header or footer have overflowed
97401
97402             ui.checkOverflow('.top-toolbar');
97403             ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
97404
97405             var resizeWindowEvent = document.createEvent('Event');
97406             resizeWindowEvent.initEvent('resizeWindow', true, true);
97407             document.dispatchEvent(resizeWindowEvent);
97408           }; // Call checkOverflow when resizing or whenever the contents change.
97409
97410
97411           ui.checkOverflow = function (selector, reset) {
97412             if (reset) {
97413               delete _needWidth[selector];
97414             }
97415
97416             var selection = context.container().select(selector);
97417             if (selection.empty()) return;
97418             var scrollWidth = selection.property('scrollWidth');
97419             var clientWidth = selection.property('clientWidth');
97420             var needed = _needWidth[selector] || scrollWidth;
97421
97422             if (scrollWidth > clientWidth) {
97423               // overflow happening
97424               selection.classed('narrow', true);
97425
97426               if (!_needWidth[selector]) {
97427                 _needWidth[selector] = scrollWidth;
97428               }
97429             } else if (scrollWidth >= needed) {
97430               selection.classed('narrow', false);
97431             }
97432           };
97433
97434           ui.togglePanes = function (showPane) {
97435             var hidePanes = context.container().selectAll('.map-pane.shown');
97436             var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
97437             hidePanes.classed('shown', false).classed('hide', true);
97438             context.container().selectAll('.map-pane-control button').classed('active', false);
97439
97440             if (showPane) {
97441               hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
97442               context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
97443               showPane.classed('shown', true).classed('hide', false);
97444
97445               if (hidePanes.empty()) {
97446                 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
97447               } else {
97448                 showPane.style(side, '0px');
97449               }
97450             } else {
97451               hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
97452                 select(this).classed('shown', false).classed('hide', true);
97453               });
97454             }
97455           };
97456
97457           var _editMenu = uiEditMenu(context);
97458
97459           ui.editMenu = function () {
97460             return _editMenu;
97461           };
97462
97463           ui.showEditMenu = function (anchorPoint, triggerType, operations) {
97464             // remove any displayed menu
97465             ui.closeEditMenu();
97466             if (!operations && context.mode().operations) operations = context.mode().operations();
97467             if (!operations || !operations.length) return; // disable menu if in wide selection, for example
97468
97469             if (!context.map().editableDataEnabled()) return;
97470             var surfaceNode = context.surface().node();
97471
97472             if (surfaceNode.focus) {
97473               // FF doesn't support it
97474               // focus the surface or else clicking off the menu may not trigger modeBrowse
97475               surfaceNode.focus();
97476             }
97477
97478             operations.forEach(function (operation) {
97479               if (operation.point) operation.point(anchorPoint);
97480             });
97481
97482             _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
97483
97484
97485             context.map().supersurface.call(_editMenu);
97486           };
97487
97488           ui.closeEditMenu = function () {
97489             // remove any existing menu no matter how it was added
97490             context.map().supersurface.select('.edit-menu').remove();
97491           };
97492
97493           var _saveLoading = select(null);
97494
97495           context.uploader().on('saveStarted.ui', function () {
97496             _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
97497             context.container().call(_saveLoading); // block input during upload
97498           }).on('saveEnded.ui', function () {
97499             _saveLoading.close();
97500
97501             _saveLoading = select(null);
97502           });
97503           return ui;
97504         }
97505
97506         function coreContext() {
97507           var _this = this;
97508
97509           var dispatch$1 = dispatch('enter', 'exit', 'change');
97510           var context = utilRebind({}, dispatch$1, 'on');
97511
97512           var _deferred = new Set();
97513
97514           context.version = '2.19.6';
97515           context.privacyVersion = '20200407'; // iD will alter the hash so cache the parameters intended to setup the session
97516
97517           context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
97518           context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
97519           /* Changeset */
97520           // An osmChangeset object. Not loaded until needed.
97521
97522           context.changeset = null;
97523           var _defaultChangesetComment = context.initialHashParams.comment;
97524           var _defaultChangesetSource = context.initialHashParams.source;
97525           var _defaultChangesetHashtags = context.initialHashParams.hashtags;
97526
97527           context.defaultChangesetComment = function (val) {
97528             if (!arguments.length) return _defaultChangesetComment;
97529             _defaultChangesetComment = val;
97530             return context;
97531           };
97532
97533           context.defaultChangesetSource = function (val) {
97534             if (!arguments.length) return _defaultChangesetSource;
97535             _defaultChangesetSource = val;
97536             return context;
97537           };
97538
97539           context.defaultChangesetHashtags = function (val) {
97540             if (!arguments.length) return _defaultChangesetHashtags;
97541             _defaultChangesetHashtags = val;
97542             return context;
97543           };
97544           /* Document title */
97545
97546           /* (typically shown as the label for the browser window/tab) */
97547           // If true, iD will update the title based on what the user is doing
97548
97549
97550           var _setsDocumentTitle = true;
97551
97552           context.setsDocumentTitle = function (val) {
97553             if (!arguments.length) return _setsDocumentTitle;
97554             _setsDocumentTitle = val;
97555             return context;
97556           }; // The part of the title that is always the same
97557
97558
97559           var _documentTitleBase = document.title;
97560
97561           context.documentTitleBase = function (val) {
97562             if (!arguments.length) return _documentTitleBase;
97563             _documentTitleBase = val;
97564             return context;
97565           };
97566           /* User interface and keybinding */
97567
97568
97569           var _ui;
97570
97571           context.ui = function () {
97572             return _ui;
97573           };
97574
97575           context.lastPointerType = function () {
97576             return _ui.lastPointerType();
97577           };
97578
97579           var _keybinding = utilKeybinding('context');
97580
97581           context.keybinding = function () {
97582             return _keybinding;
97583           };
97584
97585           select(document).call(_keybinding);
97586           /* Straight accessors. Avoid using these if you can. */
97587           // Instantiate the connection here because it doesn't require passing in
97588           // `context` and it's needed for pre-init calls like `preauth`
97589
97590           var _connection = services.osm;
97591
97592           var _history;
97593
97594           var _validator;
97595
97596           var _uploader;
97597
97598           context.connection = function () {
97599             return _connection;
97600           };
97601
97602           context.history = function () {
97603             return _history;
97604           };
97605
97606           context.validator = function () {
97607             return _validator;
97608           };
97609
97610           context.uploader = function () {
97611             return _uploader;
97612           };
97613           /* Connection */
97614
97615
97616           context.preauth = function (options) {
97617             if (_connection) {
97618               _connection["switch"](options);
97619             }
97620
97621             return context;
97622           };
97623           /* connection options for source switcher (optional) */
97624
97625
97626           var _apiConnections;
97627
97628           context.apiConnections = function (val) {
97629             if (!arguments.length) return _apiConnections;
97630             _apiConnections = val;
97631             return context;
97632           }; // A string or array or locale codes to prefer over the browser's settings
97633
97634
97635           context.locale = function (locale) {
97636             if (!arguments.length) return _mainLocalizer.localeCode();
97637             _mainLocalizer.preferredLocaleCodes(locale);
97638             return context;
97639           };
97640
97641           function afterLoad(cid, callback) {
97642             return function (err, result) {
97643               if (err) {
97644                 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
97645                 if (err.status === 400 || err.status === 401 || err.status === 403) {
97646                   if (_connection) {
97647                     _connection.logout();
97648                   }
97649                 }
97650
97651                 if (typeof callback === 'function') {
97652                   callback(err);
97653                 }
97654
97655                 return;
97656               } else if (_connection && _connection.getConnectionId() !== cid) {
97657                 if (typeof callback === 'function') {
97658                   callback({
97659                     message: 'Connection Switched',
97660                     status: -1
97661                   });
97662                 }
97663
97664                 return;
97665               } else {
97666                 _history.merge(result.data, result.extent);
97667
97668                 if (typeof callback === 'function') {
97669                   callback(err, result);
97670                 }
97671
97672                 return;
97673               }
97674             };
97675           }
97676
97677           context.loadTiles = function (projection, callback) {
97678             var handle = window.requestIdleCallback(function () {
97679               _deferred["delete"](handle);
97680
97681               if (_connection && context.editableDataEnabled()) {
97682                 var cid = _connection.getConnectionId();
97683
97684                 _connection.loadTiles(projection, afterLoad(cid, callback));
97685               }
97686             });
97687
97688             _deferred.add(handle);
97689           };
97690
97691           context.loadTileAtLoc = function (loc, callback) {
97692             var handle = window.requestIdleCallback(function () {
97693               _deferred["delete"](handle);
97694
97695               if (_connection && context.editableDataEnabled()) {
97696                 var cid = _connection.getConnectionId();
97697
97698                 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
97699               }
97700             });
97701
97702             _deferred.add(handle);
97703           };
97704
97705           context.loadEntity = function (entityID, callback) {
97706             if (_connection) {
97707               var cid = _connection.getConnectionId();
97708
97709               _connection.loadEntity(entityID, afterLoad(cid, callback));
97710             }
97711           };
97712
97713           context.zoomToEntity = function (entityID, zoomTo) {
97714             // be sure to load the entity even if we're not going to zoom to it
97715             context.loadEntity(entityID, function (err, result) {
97716               if (err) return;
97717
97718               if (zoomTo !== false) {
97719                 var entity = result.data.find(function (e) {
97720                   return e.id === entityID;
97721                 });
97722
97723                 if (entity) {
97724                   _map.zoomTo(entity);
97725                 }
97726               }
97727             });
97728
97729             _map.on('drawn.zoomToEntity', function () {
97730               if (!context.hasEntity(entityID)) return;
97731
97732               _map.on('drawn.zoomToEntity', null);
97733
97734               context.on('enter.zoomToEntity', null);
97735               context.enter(modeSelect(context, [entityID]));
97736             });
97737
97738             context.on('enter.zoomToEntity', function () {
97739               if (_mode.id !== 'browse') {
97740                 _map.on('drawn.zoomToEntity', null);
97741
97742                 context.on('enter.zoomToEntity', null);
97743               }
97744             });
97745           };
97746
97747           var _minEditableZoom = 16;
97748
97749           context.minEditableZoom = function (val) {
97750             if (!arguments.length) return _minEditableZoom;
97751             _minEditableZoom = val;
97752
97753             if (_connection) {
97754               _connection.tileZoom(val);
97755             }
97756
97757             return context;
97758           }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
97759
97760
97761           context.maxCharsForTagKey = function () {
97762             return 255;
97763           };
97764
97765           context.maxCharsForTagValue = function () {
97766             return 255;
97767           };
97768
97769           context.maxCharsForRelationRole = function () {
97770             return 255;
97771           };
97772
97773           function cleanOsmString(val, maxChars) {
97774             // be lenient with input
97775             if (val === undefined || val === null) {
97776               val = '';
97777             } else {
97778               val = val.toString();
97779             } // remove whitespace
97780
97781
97782             val = val.trim(); // use the canonical form of the string
97783
97784             if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
97785
97786             return utilUnicodeCharsTruncated(val, maxChars);
97787           }
97788
97789           context.cleanTagKey = function (val) {
97790             return cleanOsmString(val, context.maxCharsForTagKey());
97791           };
97792
97793           context.cleanTagValue = function (val) {
97794             return cleanOsmString(val, context.maxCharsForTagValue());
97795           };
97796
97797           context.cleanRelationRole = function (val) {
97798             return cleanOsmString(val, context.maxCharsForRelationRole());
97799           };
97800           /* History */
97801
97802
97803           var _inIntro = false;
97804
97805           context.inIntro = function (val) {
97806             if (!arguments.length) return _inIntro;
97807             _inIntro = val;
97808             return context;
97809           }; // Immediately save the user's history to localstorage, if possible
97810           // This is called someteimes, but also on the `window.onbeforeunload` handler
97811
97812
97813           context.save = function () {
97814             // no history save, no message onbeforeunload
97815             if (_inIntro || context.container().select('.modal').size()) return;
97816             var canSave;
97817
97818             if (_mode && _mode.id === 'save') {
97819               canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
97820
97821               if (services.osm && services.osm.isChangesetInflight()) {
97822                 _history.clearSaved();
97823
97824                 return;
97825               }
97826             } else {
97827               canSave = context.selectedIDs().every(function (id) {
97828                 var entity = context.hasEntity(id);
97829                 return entity && !entity.isDegenerate();
97830               });
97831             }
97832
97833             if (canSave) {
97834               _history.save();
97835             }
97836
97837             if (_history.hasChanges()) {
97838               return _t('save.unsaved_changes');
97839             }
97840           }; // Debounce save, since it's a synchronous localStorage write,
97841           // and history changes can happen frequently (e.g. when dragging).
97842
97843
97844           context.debouncedSave = debounce(context.save, 350);
97845
97846           function withDebouncedSave(fn) {
97847             return function () {
97848               var result = fn.apply(_history, arguments);
97849               context.debouncedSave();
97850               return result;
97851             };
97852           }
97853           /* Graph */
97854
97855
97856           context.hasEntity = function (id) {
97857             return _history.graph().hasEntity(id);
97858           };
97859
97860           context.entity = function (id) {
97861             return _history.graph().entity(id);
97862           };
97863           /* Modes */
97864
97865
97866           var _mode;
97867
97868           context.mode = function () {
97869             return _mode;
97870           };
97871
97872           context.enter = function (newMode) {
97873             if (_mode) {
97874               _mode.exit();
97875
97876               dispatch$1.call('exit', _this, _mode);
97877             }
97878
97879             _mode = newMode;
97880
97881             _mode.enter();
97882
97883             dispatch$1.call('enter', _this, _mode);
97884           };
97885
97886           context.selectedIDs = function () {
97887             return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
97888           };
97889
97890           context.activeID = function () {
97891             return _mode && _mode.activeID && _mode.activeID();
97892           };
97893
97894           var _selectedNoteID;
97895
97896           context.selectedNoteID = function (noteID) {
97897             if (!arguments.length) return _selectedNoteID;
97898             _selectedNoteID = noteID;
97899             return context;
97900           }; // NOTE: Don't change the name of this until UI v3 is merged
97901
97902
97903           var _selectedErrorID;
97904
97905           context.selectedErrorID = function (errorID) {
97906             if (!arguments.length) return _selectedErrorID;
97907             _selectedErrorID = errorID;
97908             return context;
97909           };
97910           /* Behaviors */
97911
97912
97913           context.install = function (behavior) {
97914             return context.surface().call(behavior);
97915           };
97916
97917           context.uninstall = function (behavior) {
97918             return context.surface().call(behavior.off);
97919           };
97920           /* Copy/Paste */
97921
97922
97923           var _copyGraph;
97924
97925           context.copyGraph = function () {
97926             return _copyGraph;
97927           };
97928
97929           var _copyIDs = [];
97930
97931           context.copyIDs = function (val) {
97932             if (!arguments.length) return _copyIDs;
97933             _copyIDs = val;
97934             _copyGraph = _history.graph();
97935             return context;
97936           };
97937
97938           var _copyLonLat;
97939
97940           context.copyLonLat = function (val) {
97941             if (!arguments.length) return _copyLonLat;
97942             _copyLonLat = val;
97943             return context;
97944           };
97945           /* Background */
97946
97947
97948           var _background;
97949
97950           context.background = function () {
97951             return _background;
97952           };
97953           /* Features */
97954
97955
97956           var _features;
97957
97958           context.features = function () {
97959             return _features;
97960           };
97961
97962           context.hasHiddenConnections = function (id) {
97963             var graph = _history.graph();
97964
97965             var entity = graph.entity(id);
97966             return _features.hasHiddenConnections(entity, graph);
97967           };
97968           /* Photos */
97969
97970
97971           var _photos;
97972
97973           context.photos = function () {
97974             return _photos;
97975           };
97976           /* Map */
97977
97978
97979           var _map;
97980
97981           context.map = function () {
97982             return _map;
97983           };
97984
97985           context.layers = function () {
97986             return _map.layers();
97987           };
97988
97989           context.surface = function () {
97990             return _map.surface;
97991           };
97992
97993           context.editableDataEnabled = function () {
97994             return _map.editableDataEnabled();
97995           };
97996
97997           context.surfaceRect = function () {
97998             return _map.surface.node().getBoundingClientRect();
97999           };
98000
98001           context.editable = function () {
98002             // don't allow editing during save
98003             var mode = context.mode();
98004             if (!mode || mode.id === 'save') return false;
98005             return _map.editableDataEnabled();
98006           };
98007           /* Debug */
98008
98009
98010           var _debugFlags = {
98011             tile: false,
98012             // tile boundaries
98013             collision: false,
98014             // label collision bounding boxes
98015             imagery: false,
98016             // imagery bounding polygons
98017             target: false,
98018             // touch targets
98019             downloaded: false // downloaded data from osm
98020
98021           };
98022
98023           context.debugFlags = function () {
98024             return _debugFlags;
98025           };
98026
98027           context.getDebug = function (flag) {
98028             return flag && _debugFlags[flag];
98029           };
98030
98031           context.setDebug = function (flag, val) {
98032             if (arguments.length === 1) val = true;
98033             _debugFlags[flag] = val;
98034             dispatch$1.call('change');
98035             return context;
98036           };
98037           /* Container */
98038
98039
98040           var _container = select(null);
98041
98042           context.container = function (val) {
98043             if (!arguments.length) return _container;
98044             _container = val;
98045
98046             _container.classed('ideditor', true);
98047
98048             return context;
98049           };
98050
98051           context.containerNode = function (val) {
98052             if (!arguments.length) return context.container().node();
98053             context.container(select(val));
98054             return context;
98055           };
98056
98057           var _embed;
98058
98059           context.embed = function (val) {
98060             if (!arguments.length) return _embed;
98061             _embed = val;
98062             return context;
98063           };
98064           /* Assets */
98065
98066
98067           var _assetPath = '';
98068
98069           context.assetPath = function (val) {
98070             if (!arguments.length) return _assetPath;
98071             _assetPath = val;
98072             _mainFileFetcher.assetPath(val);
98073             return context;
98074           };
98075
98076           var _assetMap = {};
98077
98078           context.assetMap = function (val) {
98079             if (!arguments.length) return _assetMap;
98080             _assetMap = val;
98081             _mainFileFetcher.assetMap(val);
98082             return context;
98083           };
98084
98085           context.asset = function (val) {
98086             if (/^http(s)?:\/\//i.test(val)) return val;
98087             var filename = _assetPath + val;
98088             return _assetMap[filename] || filename;
98089           };
98090
98091           context.imagePath = function (val) {
98092             return context.asset("img/".concat(val));
98093           };
98094           /* reset (aka flush) */
98095
98096
98097           context.reset = context.flush = function () {
98098             context.debouncedSave.cancel();
98099             Array.from(_deferred).forEach(function (handle) {
98100               window.cancelIdleCallback(handle);
98101
98102               _deferred["delete"](handle);
98103             });
98104             Object.values(services).forEach(function (service) {
98105               if (service && typeof service.reset === 'function') {
98106                 service.reset(context);
98107               }
98108             });
98109             context.changeset = null;
98110
98111             _validator.reset();
98112
98113             _features.reset();
98114
98115             _history.reset();
98116
98117             _uploader.reset(); // don't leave stale state in the inspector
98118
98119
98120             context.container().select('.inspector-wrap *').remove();
98121             return context;
98122           };
98123           /* Projections */
98124
98125
98126           context.projection = geoRawMercator();
98127           context.curtainProjection = geoRawMercator();
98128           /* Init */
98129
98130           context.init = function () {
98131             instantiateInternal();
98132             initializeDependents();
98133             return context; // Load variables and properties. No property of `context` should be accessed
98134             // until this is complete since load statuses are indeterminate. The order
98135             // of instantiation shouldn't matter.
98136
98137             function instantiateInternal() {
98138               _history = coreHistory(context);
98139               context.graph = _history.graph;
98140               context.pauseChangeDispatch = _history.pauseChangeDispatch;
98141               context.resumeChangeDispatch = _history.resumeChangeDispatch;
98142               context.perform = withDebouncedSave(_history.perform);
98143               context.replace = withDebouncedSave(_history.replace);
98144               context.pop = withDebouncedSave(_history.pop);
98145               context.overwrite = withDebouncedSave(_history.overwrite);
98146               context.undo = withDebouncedSave(_history.undo);
98147               context.redo = withDebouncedSave(_history.redo);
98148               _validator = coreValidator(context);
98149               _uploader = coreUploader(context);
98150               _background = rendererBackground(context);
98151               _features = rendererFeatures(context);
98152               _map = rendererMap(context);
98153               _photos = rendererPhotos(context);
98154               _ui = uiInit(context);
98155             } // Set up objects that might need to access properties of `context`. The order
98156             // might matter if dependents make calls to each other. Be wary of async calls.
98157
98158
98159             function initializeDependents() {
98160               if (context.initialHashParams.presets) {
98161                 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
98162               }
98163
98164               if (context.initialHashParams.locale) {
98165                 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
98166               } // kick off some async work
98167
98168
98169               _mainLocalizer.ensureLoaded();
98170
98171               _background.ensureLoaded();
98172
98173               _mainPresetIndex.ensureLoaded();
98174               Object.values(services).forEach(function (service) {
98175                 if (service && typeof service.init === 'function') {
98176                   service.init();
98177                 }
98178               });
98179
98180               _map.init();
98181
98182               _validator.init();
98183
98184               _features.init();
98185
98186               if (services.maprules && context.initialHashParams.maprules) {
98187                 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
98188                   services.maprules.init();
98189                   mapcss.forEach(function (mapcssSelector) {
98190                     return services.maprules.addRule(mapcssSelector);
98191                   });
98192                 })["catch"](function () {
98193                   /* ignore */
98194                 });
98195               } // if the container isn't available, e.g. when testing, don't load the UI
98196
98197
98198               if (!context.container().empty()) {
98199                 _ui.ensureLoaded().then(function () {
98200                   _photos.init();
98201                 });
98202               }
98203             }
98204           };
98205
98206           return context;
98207         }
98208
98209         // This is only done in testing because of the performance penalty.
98210
98211         var debug = false; // Reexport just what our tests use, see #4379
98212         var d3 = {
98213           dispatch: dispatch,
98214           geoMercator: mercator,
98215           geoProjection: projection,
98216           polygonArea: d3_polygonArea,
98217           polygonCentroid: d3_polygonCentroid,
98218           select: select,
98219           selectAll: selectAll,
98220           timerFlush: timerFlush
98221         };
98222
98223         var iD = /*#__PURE__*/Object.freeze({
98224                 __proto__: null,
98225                 debug: debug,
98226                 d3: d3,
98227                 actionAddEntity: actionAddEntity,
98228                 actionAddMember: actionAddMember,
98229                 actionAddMidpoint: actionAddMidpoint,
98230                 actionAddVertex: actionAddVertex,
98231                 actionChangeMember: actionChangeMember,
98232                 actionChangePreset: actionChangePreset,
98233                 actionChangeTags: actionChangeTags,
98234                 actionCircularize: actionCircularize,
98235                 actionConnect: actionConnect,
98236                 actionCopyEntities: actionCopyEntities,
98237                 actionDeleteMember: actionDeleteMember,
98238                 actionDeleteMultiple: actionDeleteMultiple,
98239                 actionDeleteNode: actionDeleteNode,
98240                 actionDeleteRelation: actionDeleteRelation,
98241                 actionDeleteWay: actionDeleteWay,
98242                 actionDiscardTags: actionDiscardTags,
98243                 actionDisconnect: actionDisconnect,
98244                 actionExtract: actionExtract,
98245                 actionJoin: actionJoin,
98246                 actionMerge: actionMerge,
98247                 actionMergeNodes: actionMergeNodes,
98248                 actionMergePolygon: actionMergePolygon,
98249                 actionMergeRemoteChanges: actionMergeRemoteChanges,
98250                 actionMove: actionMove,
98251                 actionMoveMember: actionMoveMember,
98252                 actionMoveNode: actionMoveNode,
98253                 actionNoop: actionNoop,
98254                 actionOrthogonalize: actionOrthogonalize,
98255                 actionRestrictTurn: actionRestrictTurn,
98256                 actionReverse: actionReverse,
98257                 actionRevert: actionRevert,
98258                 actionRotate: actionRotate,
98259                 actionScale: actionScale,
98260                 actionSplit: actionSplit,
98261                 actionStraightenNodes: actionStraightenNodes,
98262                 actionStraightenWay: actionStraightenWay,
98263                 actionUnrestrictTurn: actionUnrestrictTurn,
98264                 actionReflect: actionReflect,
98265                 actionUpgradeTags: actionUpgradeTags,
98266                 behaviorAddWay: behaviorAddWay,
98267                 behaviorBreathe: behaviorBreathe,
98268                 behaviorDrag: behaviorDrag,
98269                 behaviorDrawWay: behaviorDrawWay,
98270                 behaviorDraw: behaviorDraw,
98271                 behaviorEdit: behaviorEdit,
98272                 behaviorHash: behaviorHash,
98273                 behaviorHover: behaviorHover,
98274                 behaviorLasso: behaviorLasso,
98275                 behaviorOperation: behaviorOperation,
98276                 behaviorPaste: behaviorPaste,
98277                 behaviorSelect: behaviorSelect,
98278                 coreContext: coreContext,
98279                 coreFileFetcher: coreFileFetcher,
98280                 fileFetcher: _mainFileFetcher,
98281                 coreDifference: coreDifference,
98282                 coreGraph: coreGraph,
98283                 coreHistory: coreHistory,
98284                 coreLocalizer: coreLocalizer,
98285                 t: _t,
98286                 localizer: _mainLocalizer,
98287                 prefs: corePreferences,
98288                 coreTree: coreTree,
98289                 coreUploader: coreUploader,
98290                 coreValidator: coreValidator,
98291                 geoExtent: geoExtent,
98292                 geoLatToMeters: geoLatToMeters,
98293                 geoLonToMeters: geoLonToMeters,
98294                 geoMetersToLat: geoMetersToLat,
98295                 geoMetersToLon: geoMetersToLon,
98296                 geoMetersToOffset: geoMetersToOffset,
98297                 geoOffsetToMeters: geoOffsetToMeters,
98298                 geoScaleToZoom: geoScaleToZoom,
98299                 geoSphericalClosestNode: geoSphericalClosestNode,
98300                 geoSphericalDistance: geoSphericalDistance,
98301                 geoZoomToScale: geoZoomToScale,
98302                 geoAngle: geoAngle,
98303                 geoChooseEdge: geoChooseEdge,
98304                 geoEdgeEqual: geoEdgeEqual,
98305                 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
98306                 geoHasLineIntersections: geoHasLineIntersections,
98307                 geoHasSelfIntersections: geoHasSelfIntersections,
98308                 geoRotate: geoRotate,
98309                 geoLineIntersection: geoLineIntersection,
98310                 geoPathHasIntersections: geoPathHasIntersections,
98311                 geoPathIntersections: geoPathIntersections,
98312                 geoPathLength: geoPathLength,
98313                 geoPointInPolygon: geoPointInPolygon,
98314                 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
98315                 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
98316                 geoViewportEdge: geoViewportEdge,
98317                 geoRawMercator: geoRawMercator,
98318                 geoVecAdd: geoVecAdd,
98319                 geoVecAngle: geoVecAngle,
98320                 geoVecCross: geoVecCross,
98321                 geoVecDot: geoVecDot,
98322                 geoVecEqual: geoVecEqual,
98323                 geoVecFloor: geoVecFloor,
98324                 geoVecInterp: geoVecInterp,
98325                 geoVecLength: geoVecLength,
98326                 geoVecLengthSquare: geoVecLengthSquare,
98327                 geoVecNormalize: geoVecNormalize,
98328                 geoVecNormalizedDot: geoVecNormalizedDot,
98329                 geoVecProject: geoVecProject,
98330                 geoVecSubtract: geoVecSubtract,
98331                 geoVecScale: geoVecScale,
98332                 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
98333                 geoOrthoCalcScore: geoOrthoCalcScore,
98334                 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
98335                 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
98336                 modeAddArea: modeAddArea,
98337                 modeAddLine: modeAddLine,
98338                 modeAddPoint: modeAddPoint,
98339                 modeAddNote: modeAddNote,
98340                 modeBrowse: modeBrowse,
98341                 modeDragNode: modeDragNode,
98342                 modeDragNote: modeDragNote,
98343                 modeDrawArea: modeDrawArea,
98344                 modeDrawLine: modeDrawLine,
98345                 modeMove: modeMove,
98346                 modeRotate: modeRotate,
98347                 modeSave: modeSave,
98348                 modeSelect: modeSelect,
98349                 modeSelectData: modeSelectData,
98350                 modeSelectError: modeSelectError,
98351                 modeSelectNote: modeSelectNote,
98352                 operationCircularize: operationCircularize,
98353                 operationContinue: operationContinue,
98354                 operationCopy: operationCopy,
98355                 operationDelete: operationDelete,
98356                 operationDisconnect: operationDisconnect,
98357                 operationDowngrade: operationDowngrade,
98358                 operationExtract: operationExtract,
98359                 operationMerge: operationMerge,
98360                 operationMove: operationMove,
98361                 operationOrthogonalize: operationOrthogonalize,
98362                 operationPaste: operationPaste,
98363                 operationReflectShort: operationReflectShort,
98364                 operationReflectLong: operationReflectLong,
98365                 operationReverse: operationReverse,
98366                 operationRotate: operationRotate,
98367                 operationSplit: operationSplit,
98368                 operationStraighten: operationStraighten,
98369                 osmChangeset: osmChangeset,
98370                 osmEntity: osmEntity,
98371                 osmNode: osmNode,
98372                 osmNote: osmNote,
98373                 osmRelation: osmRelation,
98374                 osmWay: osmWay,
98375                 QAItem: QAItem,
98376                 osmIntersection: osmIntersection,
98377                 osmTurn: osmTurn,
98378                 osmInferRestriction: osmInferRestriction,
98379                 osmLanes: osmLanes,
98380                 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
98381                 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
98382                 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
98383                 osmJoinWays: osmJoinWays,
98384                 get osmAreaKeys () { return osmAreaKeys; },
98385                 osmSetAreaKeys: osmSetAreaKeys,
98386                 osmTagSuggestingArea: osmTagSuggestingArea,
98387                 get osmPointTags () { return osmPointTags; },
98388                 osmSetPointTags: osmSetPointTags,
98389                 get osmVertexTags () { return osmVertexTags; },
98390                 osmSetVertexTags: osmSetVertexTags,
98391                 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
98392                 osmOneWayTags: osmOneWayTags,
98393                 osmPavedTags: osmPavedTags,
98394                 osmIsInterestingTag: osmIsInterestingTag,
98395                 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
98396                 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
98397                 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
98398                 presetCategory: presetCategory,
98399                 presetCollection: presetCollection,
98400                 presetField: presetField,
98401                 presetPreset: presetPreset,
98402                 presetManager: _mainPresetIndex,
98403                 presetIndex: presetIndex,
98404                 rendererBackgroundSource: rendererBackgroundSource,
98405                 rendererBackground: rendererBackground,
98406                 rendererFeatures: rendererFeatures,
98407                 rendererMap: rendererMap,
98408                 rendererPhotos: rendererPhotos,
98409                 rendererTileLayer: rendererTileLayer,
98410                 services: services,
98411                 serviceKeepRight: serviceKeepRight,
98412                 serviceImproveOSM: serviceImproveOSM,
98413                 serviceOsmose: serviceOsmose,
98414                 serviceMapillary: serviceMapillary,
98415                 serviceMapRules: serviceMapRules,
98416                 serviceNominatim: serviceNominatim,
98417                 serviceOpenstreetcam: serviceOpenstreetcam,
98418                 serviceOsm: serviceOsm,
98419                 serviceOsmWikibase: serviceOsmWikibase,
98420                 serviceStreetside: serviceStreetside,
98421                 serviceTaginfo: serviceTaginfo,
98422                 serviceVectorTile: serviceVectorTile,
98423                 serviceWikidata: serviceWikidata,
98424                 serviceWikipedia: serviceWikipedia,
98425                 svgAreas: svgAreas,
98426                 svgData: svgData,
98427                 svgDebug: svgDebug,
98428                 svgDefs: svgDefs,
98429                 svgKeepRight: svgKeepRight,
98430                 svgIcon: svgIcon,
98431                 svgGeolocate: svgGeolocate,
98432                 svgLabels: svgLabels,
98433                 svgLayers: svgLayers,
98434                 svgLines: svgLines,
98435                 svgMapillaryImages: svgMapillaryImages,
98436                 svgMapillarySigns: svgMapillarySigns,
98437                 svgMidpoints: svgMidpoints,
98438                 svgNotes: svgNotes,
98439                 svgMarkerSegments: svgMarkerSegments,
98440                 svgOpenstreetcamImages: svgOpenstreetcamImages,
98441                 svgOsm: svgOsm,
98442                 svgPassiveVertex: svgPassiveVertex,
98443                 svgPath: svgPath,
98444                 svgPointTransform: svgPointTransform,
98445                 svgPoints: svgPoints,
98446                 svgRelationMemberTags: svgRelationMemberTags,
98447                 svgSegmentWay: svgSegmentWay,
98448                 svgStreetside: svgStreetside,
98449                 svgTagClasses: svgTagClasses,
98450                 svgTagPattern: svgTagPattern,
98451                 svgTouch: svgTouch,
98452                 svgTurns: svgTurns,
98453                 svgVertices: svgVertices,
98454                 uiFieldDefaultCheck: uiFieldCheck,
98455                 uiFieldOnewayCheck: uiFieldCheck,
98456                 uiFieldCheck: uiFieldCheck,
98457                 uiFieldManyCombo: uiFieldCombo,
98458                 uiFieldMultiCombo: uiFieldCombo,
98459                 uiFieldNetworkCombo: uiFieldCombo,
98460                 uiFieldSemiCombo: uiFieldCombo,
98461                 uiFieldTypeCombo: uiFieldCombo,
98462                 uiFieldCombo: uiFieldCombo,
98463                 uiFieldUrl: uiFieldText,
98464                 uiFieldIdentifier: uiFieldText,
98465                 uiFieldNumber: uiFieldText,
98466                 uiFieldTel: uiFieldText,
98467                 uiFieldEmail: uiFieldText,
98468                 uiFieldText: uiFieldText,
98469                 uiFieldAccess: uiFieldAccess,
98470                 uiFieldAddress: uiFieldAddress,
98471                 uiFieldCycleway: uiFieldCycleway,
98472                 uiFieldLanes: uiFieldLanes,
98473                 uiFieldLocalized: uiFieldLocalized,
98474                 uiFieldMaxspeed: uiFieldMaxspeed,
98475                 uiFieldStructureRadio: uiFieldRadio,
98476                 uiFieldRadio: uiFieldRadio,
98477                 uiFieldRestrictions: uiFieldRestrictions,
98478                 uiFieldTextarea: uiFieldTextarea,
98479                 uiFieldWikidata: uiFieldWikidata,
98480                 uiFieldWikipedia: uiFieldWikipedia,
98481                 uiFields: uiFields,
98482                 uiIntro: uiIntro,
98483                 uiPanelBackground: uiPanelBackground,
98484                 uiPanelHistory: uiPanelHistory,
98485                 uiPanelLocation: uiPanelLocation,
98486                 uiPanelMeasurement: uiPanelMeasurement,
98487                 uiInfoPanels: uiInfoPanels,
98488                 uiPaneBackground: uiPaneBackground,
98489                 uiPaneHelp: uiPaneHelp,
98490                 uiPaneIssues: uiPaneIssues,
98491                 uiPaneMapData: uiPaneMapData,
98492                 uiPanePreferences: uiPanePreferences,
98493                 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
98494                 uiSectionBackgroundList: uiSectionBackgroundList,
98495                 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
98496                 uiSectionChanges: uiSectionChanges,
98497                 uiSectionDataLayers: uiSectionDataLayers,
98498                 uiSectionEntityIssues: uiSectionEntityIssues,
98499                 uiSectionFeatureType: uiSectionFeatureType,
98500                 uiSectionMapFeatures: uiSectionMapFeatures,
98501                 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
98502                 uiSectionOverlayList: uiSectionOverlayList,
98503                 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
98504                 uiSectionPresetFields: uiSectionPresetFields,
98505                 uiSectionPrivacy: uiSectionPrivacy,
98506                 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
98507                 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
98508                 uiSectionRawTagEditor: uiSectionRawTagEditor,
98509                 uiSectionSelectionList: uiSectionSelectionList,
98510                 uiSectionValidationIssues: uiSectionValidationIssues,
98511                 uiSectionValidationOptions: uiSectionValidationOptions,
98512                 uiSectionValidationRules: uiSectionValidationRules,
98513                 uiSectionValidationStatus: uiSectionValidationStatus,
98514                 uiSettingsCustomBackground: uiSettingsCustomBackground,
98515                 uiSettingsCustomData: uiSettingsCustomData,
98516                 uiInit: uiInit,
98517                 uiAccount: uiAccount,
98518                 uiAttribution: uiAttribution,
98519                 uiChangesetEditor: uiChangesetEditor,
98520                 uiCmd: uiCmd,
98521                 uiCombobox: uiCombobox,
98522                 uiCommit: uiCommit,
98523                 uiCommitWarnings: uiCommitWarnings,
98524                 uiConfirm: uiConfirm,
98525                 uiConflicts: uiConflicts,
98526                 uiContributors: uiContributors,
98527                 uiCurtain: uiCurtain,
98528                 uiDataEditor: uiDataEditor,
98529                 uiDataHeader: uiDataHeader,
98530                 uiDisclosure: uiDisclosure,
98531                 uiEditMenu: uiEditMenu,
98532                 uiEntityEditor: uiEntityEditor,
98533                 uiFeatureInfo: uiFeatureInfo,
98534                 uiFeatureList: uiFeatureList,
98535                 uiField: uiField,
98536                 uiFieldHelp: uiFieldHelp,
98537                 uiFlash: uiFlash,
98538                 uiFormFields: uiFormFields,
98539                 uiFullScreen: uiFullScreen,
98540                 uiGeolocate: uiGeolocate,
98541                 uiImproveOsmComments: uiImproveOsmComments,
98542                 uiImproveOsmDetails: uiImproveOsmDetails,
98543                 uiImproveOsmEditor: uiImproveOsmEditor,
98544                 uiImproveOsmHeader: uiImproveOsmHeader,
98545                 uiInfo: uiInfo,
98546                 uiInspector: uiInspector,
98547                 uiIssuesInfo: uiIssuesInfo,
98548                 uiKeepRightDetails: uiKeepRightDetails,
98549                 uiKeepRightEditor: uiKeepRightEditor,
98550                 uiKeepRightHeader: uiKeepRightHeader,
98551                 uiLasso: uiLasso,
98552                 uiLoading: uiLoading,
98553                 uiMapInMap: uiMapInMap,
98554                 uiModal: uiModal,
98555                 uiNotice: uiNotice,
98556                 uiNoteComments: uiNoteComments,
98557                 uiNoteEditor: uiNoteEditor,
98558                 uiNoteHeader: uiNoteHeader,
98559                 uiNoteReport: uiNoteReport,
98560                 uiPopover: uiPopover,
98561                 uiPresetIcon: uiPresetIcon,
98562                 uiPresetList: uiPresetList,
98563                 uiRestore: uiRestore,
98564                 uiScale: uiScale,
98565                 uiSidebar: uiSidebar,
98566                 uiSourceSwitch: uiSourceSwitch,
98567                 uiSpinner: uiSpinner,
98568                 uiSplash: uiSplash,
98569                 uiStatus: uiStatus,
98570                 uiSuccess: uiSuccess,
98571                 uiTagReference: uiTagReference,
98572                 uiToggle: uiToggle,
98573                 uiTooltip: uiTooltip,
98574                 uiVersion: uiVersion,
98575                 uiViewOnOSM: uiViewOnOSM,
98576                 uiViewOnKeepRight: uiViewOnKeepRight,
98577                 uiZoom: uiZoom,
98578                 utilAesEncrypt: utilAesEncrypt,
98579                 utilAesDecrypt: utilAesDecrypt,
98580                 utilArrayChunk: utilArrayChunk,
98581                 utilArrayDifference: utilArrayDifference,
98582                 utilArrayFlatten: utilArrayFlatten,
98583                 utilArrayGroupBy: utilArrayGroupBy,
98584                 utilArrayIdentical: utilArrayIdentical,
98585                 utilArrayIntersection: utilArrayIntersection,
98586                 utilArrayUnion: utilArrayUnion,
98587                 utilArrayUniq: utilArrayUniq,
98588                 utilArrayUniqBy: utilArrayUniqBy,
98589                 utilAsyncMap: utilAsyncMap,
98590                 utilCleanTags: utilCleanTags,
98591                 utilCombinedTags: utilCombinedTags,
98592                 utilDeepMemberSelector: utilDeepMemberSelector,
98593                 utilDetect: utilDetect,
98594                 utilDisplayName: utilDisplayName,
98595                 utilDisplayNameForPath: utilDisplayNameForPath,
98596                 utilDisplayType: utilDisplayType,
98597                 utilDisplayLabel: utilDisplayLabel,
98598                 utilEntityRoot: utilEntityRoot,
98599                 utilEditDistance: utilEditDistance,
98600                 utilEntitySelector: utilEntitySelector,
98601                 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
98602                 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
98603                 utilFastMouse: utilFastMouse,
98604                 utilFunctor: utilFunctor,
98605                 utilGetAllNodes: utilGetAllNodes,
98606                 utilGetSetValue: utilGetSetValue,
98607                 utilHashcode: utilHashcode,
98608                 utilHighlightEntities: utilHighlightEntities,
98609                 utilKeybinding: utilKeybinding,
98610                 utilNoAuto: utilNoAuto,
98611                 utilObjectOmit: utilObjectOmit,
98612                 utilPrefixCSSProperty: utilPrefixCSSProperty,
98613                 utilPrefixDOMProperty: utilPrefixDOMProperty,
98614                 utilQsString: utilQsString,
98615                 utilRebind: utilRebind,
98616                 utilSafeClassName: utilSafeClassName,
98617                 utilSetTransform: utilSetTransform,
98618                 utilSessionMutex: utilSessionMutex,
98619                 utilStringQs: utilStringQs,
98620                 utilTagDiff: utilTagDiff,
98621                 utilTagText: utilTagText,
98622                 utilTiler: utilTiler,
98623                 utilTotalExtent: utilTotalExtent,
98624                 utilTriggerEvent: utilTriggerEvent,
98625                 utilUnicodeCharsCount: utilUnicodeCharsCount,
98626                 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
98627                 utilUniqueDomId: utilUniqueDomId,
98628                 utilWrap: utilWrap,
98629                 validationAlmostJunction: validationAlmostJunction,
98630                 validationCloseNodes: validationCloseNodes,
98631                 validationCrossingWays: validationCrossingWays,
98632                 validationDisconnectedWay: validationDisconnectedWay,
98633                 validationFormatting: validationFormatting,
98634                 validationHelpRequest: validationHelpRequest,
98635                 validationImpossibleOneway: validationImpossibleOneway,
98636                 validationIncompatibleSource: validationIncompatibleSource,
98637                 validationMaprules: validationMaprules,
98638                 validationMismatchedGeometry: validationMismatchedGeometry,
98639                 validationMissingRole: validationMissingRole,
98640                 validationMissingTag: validationMissingTag,
98641                 validationOutdatedTags: validationOutdatedTags,
98642                 validationPrivateData: validationPrivateData,
98643                 validationSuspiciousName: validationSuspiciousName,
98644                 validationUnsquareWay: validationUnsquareWay
98645         });
98646
98647         window.requestIdleCallback = window.requestIdleCallback || function (cb) {
98648           var start = Date.now();
98649           return window.requestAnimationFrame(function () {
98650             cb({
98651               didTimeout: false,
98652               timeRemaining: function timeRemaining() {
98653                 return Math.max(0, 50 - (Date.now() - start));
98654               }
98655             });
98656           });
98657         };
98658
98659         window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
98660           window.cancelAnimationFrame(id);
98661         };
98662         window.iD = iD;
98663
98664 }());