]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Merge remote-tracking branch 'upstream/pull/2947' into master
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2
3         var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
4
5         function getDefaultExportFromCjs (x) {
6                 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
7         }
8
9         function createCommonjsModule(fn, basedir, module) {
10                 return module = {
11                         path: basedir,
12                         exports: {},
13                         require: function (path, base) {
14                                 return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
15                         }
16                 }, fn(module, module.exports), module.exports;
17         }
18
19         function commonjsRequire () {
20                 throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
21         }
22
23         var check = function (it) {
24           return it && it.Math == Math && it;
25         };
26
27         // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
28         var global_1 =
29           // eslint-disable-next-line no-undef
30           check(typeof globalThis == 'object' && globalThis) ||
31           check(typeof window == 'object' && window) ||
32           check(typeof self == 'object' && self) ||
33           check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
34           // eslint-disable-next-line no-new-func
35           (function () { return this; })() || Function('return this')();
36
37         var fails = function (exec) {
38           try {
39             return !!exec();
40           } catch (error) {
41             return true;
42           }
43         };
44
45         // Thank's IE8 for his funny defineProperty
46         var descriptors = !fails(function () {
47           return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
48         });
49
50         var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
51         var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
52
53         // Nashorn ~ JDK8 bug
54         var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1);
55
56         // `Object.prototype.propertyIsEnumerable` method implementation
57         // https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable
58         var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
59           var descriptor = getOwnPropertyDescriptor(this, V);
60           return !!descriptor && descriptor.enumerable;
61         } : nativePropertyIsEnumerable;
62
63         var objectPropertyIsEnumerable = {
64                 f: f
65         };
66
67         var createPropertyDescriptor = function (bitmap, value) {
68           return {
69             enumerable: !(bitmap & 1),
70             configurable: !(bitmap & 2),
71             writable: !(bitmap & 4),
72             value: value
73           };
74         };
75
76         var toString = {}.toString;
77
78         var classofRaw = function (it) {
79           return toString.call(it).slice(8, -1);
80         };
81
82         var split = ''.split;
83
84         // fallback for non-array-like ES3 and non-enumerable old V8 strings
85         var indexedObject = fails(function () {
86           // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
87           // eslint-disable-next-line no-prototype-builtins
88           return !Object('z').propertyIsEnumerable(0);
89         }) ? function (it) {
90           return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
91         } : Object;
92
93         // `RequireObjectCoercible` abstract operation
94         // https://tc39.github.io/ecma262/#sec-requireobjectcoercible
95         var requireObjectCoercible = function (it) {
96           if (it == undefined) throw TypeError("Can't call method on " + it);
97           return it;
98         };
99
100         // toObject with fallback for non-array-like ES3 strings
101
102
103
104         var toIndexedObject = function (it) {
105           return indexedObject(requireObjectCoercible(it));
106         };
107
108         var isObject = function (it) {
109           return typeof it === 'object' ? it !== null : typeof it === 'function';
110         };
111
112         // `ToPrimitive` abstract operation
113         // https://tc39.github.io/ecma262/#sec-toprimitive
114         // instead of the ES6 spec version, we didn't implement @@toPrimitive case
115         // and the second argument - flag - preferred type is a string
116         var toPrimitive = function (input, PREFERRED_STRING) {
117           if (!isObject(input)) return input;
118           var fn, val;
119           if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
120           if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
121           if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
122           throw TypeError("Can't convert object to primitive value");
123         };
124
125         var hasOwnProperty = {}.hasOwnProperty;
126
127         var has = function (it, key) {
128           return hasOwnProperty.call(it, key);
129         };
130
131         var document$1 = global_1.document;
132         // typeof document.createElement is 'object' in old IE
133         var EXISTS = isObject(document$1) && isObject(document$1.createElement);
134
135         var documentCreateElement = function (it) {
136           return EXISTS ? document$1.createElement(it) : {};
137         };
138
139         // Thank's IE8 for his funny defineProperty
140         var ie8DomDefine = !descriptors && !fails(function () {
141           return Object.defineProperty(documentCreateElement('div'), 'a', {
142             get: function () { return 7; }
143           }).a != 7;
144         });
145
146         var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
147
148         // `Object.getOwnPropertyDescriptor` method
149         // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor
150         var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
151           O = toIndexedObject(O);
152           P = toPrimitive(P, true);
153           if (ie8DomDefine) try {
154             return nativeGetOwnPropertyDescriptor(O, P);
155           } catch (error) { /* empty */ }
156           if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
157         };
158
159         var objectGetOwnPropertyDescriptor = {
160                 f: f$1
161         };
162
163         var anObject = function (it) {
164           if (!isObject(it)) {
165             throw TypeError(String(it) + ' is not an object');
166           } return it;
167         };
168
169         var nativeDefineProperty = Object.defineProperty;
170
171         // `Object.defineProperty` method
172         // https://tc39.github.io/ecma262/#sec-object.defineproperty
173         var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
174           anObject(O);
175           P = toPrimitive(P, true);
176           anObject(Attributes);
177           if (ie8DomDefine) try {
178             return nativeDefineProperty(O, P, Attributes);
179           } catch (error) { /* empty */ }
180           if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
181           if ('value' in Attributes) O[P] = Attributes.value;
182           return O;
183         };
184
185         var objectDefineProperty = {
186                 f: f$2
187         };
188
189         var createNonEnumerableProperty = descriptors ? function (object, key, value) {
190           return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
191         } : function (object, key, value) {
192           object[key] = value;
193           return object;
194         };
195
196         var setGlobal = function (key, value) {
197           try {
198             createNonEnumerableProperty(global_1, key, value);
199           } catch (error) {
200             global_1[key] = value;
201           } return value;
202         };
203
204         var SHARED = '__core-js_shared__';
205         var store = global_1[SHARED] || setGlobal(SHARED, {});
206
207         var sharedStore = store;
208
209         var functionToString = Function.toString;
210
211         // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper
212         if (typeof sharedStore.inspectSource != 'function') {
213           sharedStore.inspectSource = function (it) {
214             return functionToString.call(it);
215           };
216         }
217
218         var inspectSource = sharedStore.inspectSource;
219
220         var WeakMap = global_1.WeakMap;
221
222         var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap));
223
224         var isPure = false;
225
226         var shared = createCommonjsModule(function (module) {
227         (module.exports = function (key, value) {
228           return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
229         })('versions', []).push({
230           version: '3.7.0',
231           mode:  'global',
232           copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
233         });
234         });
235
236         var id = 0;
237         var postfix = Math.random();
238
239         var uid = function (key) {
240           return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
241         };
242
243         var keys = shared('keys');
244
245         var sharedKey = function (key) {
246           return keys[key] || (keys[key] = uid(key));
247         };
248
249         var hiddenKeys = {};
250
251         var WeakMap$1 = global_1.WeakMap;
252         var set, get, has$1;
253
254         var enforce = function (it) {
255           return has$1(it) ? get(it) : set(it, {});
256         };
257
258         var getterFor = function (TYPE) {
259           return function (it) {
260             var state;
261             if (!isObject(it) || (state = get(it)).type !== TYPE) {
262               throw TypeError('Incompatible receiver, ' + TYPE + ' required');
263             } return state;
264           };
265         };
266
267         if (nativeWeakMap) {
268           var store$1 = sharedStore.state || (sharedStore.state = new WeakMap$1());
269           var wmget = store$1.get;
270           var wmhas = store$1.has;
271           var wmset = store$1.set;
272           set = function (it, metadata) {
273             metadata.facade = it;
274             wmset.call(store$1, it, metadata);
275             return metadata;
276           };
277           get = function (it) {
278             return wmget.call(store$1, it) || {};
279           };
280           has$1 = function (it) {
281             return wmhas.call(store$1, it);
282           };
283         } else {
284           var STATE = sharedKey('state');
285           hiddenKeys[STATE] = true;
286           set = function (it, metadata) {
287             metadata.facade = it;
288             createNonEnumerableProperty(it, STATE, metadata);
289             return metadata;
290           };
291           get = function (it) {
292             return has(it, STATE) ? it[STATE] : {};
293           };
294           has$1 = function (it) {
295             return has(it, STATE);
296           };
297         }
298
299         var internalState = {
300           set: set,
301           get: get,
302           has: has$1,
303           enforce: enforce,
304           getterFor: getterFor
305         };
306
307         var redefine = createCommonjsModule(function (module) {
308         var getInternalState = internalState.get;
309         var enforceInternalState = internalState.enforce;
310         var TEMPLATE = String(String).split('String');
311
312         (module.exports = function (O, key, value, options) {
313           var unsafe = options ? !!options.unsafe : false;
314           var simple = options ? !!options.enumerable : false;
315           var noTargetGet = options ? !!options.noTargetGet : false;
316           var state;
317           if (typeof value == 'function') {
318             if (typeof key == 'string' && !has(value, 'name')) {
319               createNonEnumerableProperty(value, 'name', key);
320             }
321             state = enforceInternalState(value);
322             if (!state.source) {
323               state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
324             }
325           }
326           if (O === global_1) {
327             if (simple) O[key] = value;
328             else setGlobal(key, value);
329             return;
330           } else if (!unsafe) {
331             delete O[key];
332           } else if (!noTargetGet && O[key]) {
333             simple = true;
334           }
335           if (simple) O[key] = value;
336           else createNonEnumerableProperty(O, key, value);
337         // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
338         })(Function.prototype, 'toString', function toString() {
339           return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
340         });
341         });
342
343         var path = global_1;
344
345         var aFunction = function (variable) {
346           return typeof variable == 'function' ? variable : undefined;
347         };
348
349         var getBuiltIn = function (namespace, method) {
350           return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace])
351             : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
352         };
353
354         var ceil = Math.ceil;
355         var floor = Math.floor;
356
357         // `ToInteger` abstract operation
358         // https://tc39.github.io/ecma262/#sec-tointeger
359         var toInteger = function (argument) {
360           return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
361         };
362
363         var min = Math.min;
364
365         // `ToLength` abstract operation
366         // https://tc39.github.io/ecma262/#sec-tolength
367         var toLength = function (argument) {
368           return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
369         };
370
371         var max = Math.max;
372         var min$1 = Math.min;
373
374         // Helper for a popular repeating case of the spec:
375         // Let integer be ? ToInteger(index).
376         // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
377         var toAbsoluteIndex = function (index, length) {
378           var integer = toInteger(index);
379           return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
380         };
381
382         // `Array.prototype.{ indexOf, includes }` methods implementation
383         var createMethod = function (IS_INCLUDES) {
384           return function ($this, el, fromIndex) {
385             var O = toIndexedObject($this);
386             var length = toLength(O.length);
387             var index = toAbsoluteIndex(fromIndex, length);
388             var value;
389             // Array#includes uses SameValueZero equality algorithm
390             // eslint-disable-next-line no-self-compare
391             if (IS_INCLUDES && el != el) while (length > index) {
392               value = O[index++];
393               // eslint-disable-next-line no-self-compare
394               if (value != value) return true;
395             // Array#indexOf ignores holes, Array#includes - not
396             } else for (;length > index; index++) {
397               if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
398             } return !IS_INCLUDES && -1;
399           };
400         };
401
402         var arrayIncludes = {
403           // `Array.prototype.includes` method
404           // https://tc39.github.io/ecma262/#sec-array.prototype.includes
405           includes: createMethod(true),
406           // `Array.prototype.indexOf` method
407           // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
408           indexOf: createMethod(false)
409         };
410
411         var indexOf = arrayIncludes.indexOf;
412
413
414         var objectKeysInternal = function (object, names) {
415           var O = toIndexedObject(object);
416           var i = 0;
417           var result = [];
418           var key;
419           for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key);
420           // Don't enum bug & hidden keys
421           while (names.length > i) if (has(O, key = names[i++])) {
422             ~indexOf(result, key) || result.push(key);
423           }
424           return result;
425         };
426
427         // IE8- don't enum bug keys
428         var enumBugKeys = [
429           'constructor',
430           'hasOwnProperty',
431           'isPrototypeOf',
432           'propertyIsEnumerable',
433           'toLocaleString',
434           'toString',
435           'valueOf'
436         ];
437
438         var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype');
439
440         // `Object.getOwnPropertyNames` method
441         // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
442         var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
443           return objectKeysInternal(O, hiddenKeys$1);
444         };
445
446         var objectGetOwnPropertyNames = {
447                 f: f$3
448         };
449
450         var f$4 = Object.getOwnPropertySymbols;
451
452         var objectGetOwnPropertySymbols = {
453                 f: f$4
454         };
455
456         // all object keys, includes non-enumerable and symbols
457         var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
458           var keys = objectGetOwnPropertyNames.f(anObject(it));
459           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
460           return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
461         };
462
463         var copyConstructorProperties = function (target, source) {
464           var keys = ownKeys(source);
465           var defineProperty = objectDefineProperty.f;
466           var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
467           for (var i = 0; i < keys.length; i++) {
468             var key = keys[i];
469             if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
470           }
471         };
472
473         var replacement = /#|\.prototype\./;
474
475         var isForced = function (feature, detection) {
476           var value = data[normalize(feature)];
477           return value == POLYFILL ? true
478             : value == NATIVE ? false
479             : typeof detection == 'function' ? fails(detection)
480             : !!detection;
481         };
482
483         var normalize = isForced.normalize = function (string) {
484           return String(string).replace(replacement, '.').toLowerCase();
485         };
486
487         var data = isForced.data = {};
488         var NATIVE = isForced.NATIVE = 'N';
489         var POLYFILL = isForced.POLYFILL = 'P';
490
491         var isForced_1 = isForced;
492
493         var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
494
495
496
497
498
499
500         /*
501           options.target      - name of the target object
502           options.global      - target is the global object
503           options.stat        - export as static methods of target
504           options.proto       - export as prototype methods of target
505           options.real        - real prototype method for the `pure` version
506           options.forced      - export even if the native feature is available
507           options.bind        - bind methods to the target, required for the `pure` version
508           options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
509           options.unsafe      - use the simple assignment of property instead of delete + defineProperty
510           options.sham        - add a flag to not completely full polyfills
511           options.enumerable  - export as enumerable property
512           options.noTargetGet - prevent calling a getter on target
513         */
514         var _export = function (options, source) {
515           var TARGET = options.target;
516           var GLOBAL = options.global;
517           var STATIC = options.stat;
518           var FORCED, target, key, targetProperty, sourceProperty, descriptor;
519           if (GLOBAL) {
520             target = global_1;
521           } else if (STATIC) {
522             target = global_1[TARGET] || setGlobal(TARGET, {});
523           } else {
524             target = (global_1[TARGET] || {}).prototype;
525           }
526           if (target) for (key in source) {
527             sourceProperty = source[key];
528             if (options.noTargetGet) {
529               descriptor = getOwnPropertyDescriptor$1(target, key);
530               targetProperty = descriptor && descriptor.value;
531             } else targetProperty = target[key];
532             FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
533             // contained in target
534             if (!FORCED && targetProperty !== undefined) {
535               if (typeof sourceProperty === typeof targetProperty) continue;
536               copyConstructorProperties(sourceProperty, targetProperty);
537             }
538             // add a flag to not completely full polyfills
539             if (options.sham || (targetProperty && targetProperty.sham)) {
540               createNonEnumerableProperty(sourceProperty, 'sham', true);
541             }
542             // extend global
543             redefine(target, key, sourceProperty, options);
544           }
545         };
546
547         // `Date.now` method
548         // https://tc39.github.io/ecma262/#sec-date.now
549         _export({ target: 'Date', stat: true }, {
550           now: function now() {
551             return new Date().getTime();
552           }
553         });
554
555         var DatePrototype = Date.prototype;
556         var INVALID_DATE = 'Invalid Date';
557         var TO_STRING = 'toString';
558         var nativeDateToString = DatePrototype[TO_STRING];
559         var getTime = DatePrototype.getTime;
560
561         // `Date.prototype.toString` method
562         // https://tc39.github.io/ecma262/#sec-date.prototype.tostring
563         if (new Date(NaN) + '' != INVALID_DATE) {
564           redefine(DatePrototype, TO_STRING, function toString() {
565             var value = getTime.call(this);
566             // eslint-disable-next-line no-self-compare
567             return value === value ? nativeDateToString.call(this) : INVALID_DATE;
568           });
569         }
570
571         var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
572           // Chrome 38 Symbol has incorrect toString conversion
573           // eslint-disable-next-line no-undef
574           return !String(Symbol());
575         });
576
577         var useSymbolAsUid = nativeSymbol
578           // eslint-disable-next-line no-undef
579           && !Symbol.sham
580           // eslint-disable-next-line no-undef
581           && typeof Symbol.iterator == 'symbol';
582
583         // `IsArray` abstract operation
584         // https://tc39.github.io/ecma262/#sec-isarray
585         var isArray = Array.isArray || function isArray(arg) {
586           return classofRaw(arg) == 'Array';
587         };
588
589         // `ToObject` abstract operation
590         // https://tc39.github.io/ecma262/#sec-toobject
591         var toObject = function (argument) {
592           return Object(requireObjectCoercible(argument));
593         };
594
595         // `Object.keys` method
596         // https://tc39.github.io/ecma262/#sec-object.keys
597         var objectKeys = Object.keys || function keys(O) {
598           return objectKeysInternal(O, enumBugKeys);
599         };
600
601         // `Object.defineProperties` method
602         // https://tc39.github.io/ecma262/#sec-object.defineproperties
603         var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
604           anObject(O);
605           var keys = objectKeys(Properties);
606           var length = keys.length;
607           var index = 0;
608           var key;
609           while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
610           return O;
611         };
612
613         var html = getBuiltIn('document', 'documentElement');
614
615         var GT = '>';
616         var LT = '<';
617         var PROTOTYPE = 'prototype';
618         var SCRIPT = 'script';
619         var IE_PROTO = sharedKey('IE_PROTO');
620
621         var EmptyConstructor = function () { /* empty */ };
622
623         var scriptTag = function (content) {
624           return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
625         };
626
627         // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
628         var NullProtoObjectViaActiveX = function (activeXDocument) {
629           activeXDocument.write(scriptTag(''));
630           activeXDocument.close();
631           var temp = activeXDocument.parentWindow.Object;
632           activeXDocument = null; // avoid memory leak
633           return temp;
634         };
635
636         // Create object with fake `null` prototype: use iframe Object with cleared prototype
637         var NullProtoObjectViaIFrame = function () {
638           // Thrash, waste and sodomy: IE GC bug
639           var iframe = documentCreateElement('iframe');
640           var JS = 'java' + SCRIPT + ':';
641           var iframeDocument;
642           iframe.style.display = 'none';
643           html.appendChild(iframe);
644           // https://github.com/zloirock/core-js/issues/475
645           iframe.src = String(JS);
646           iframeDocument = iframe.contentWindow.document;
647           iframeDocument.open();
648           iframeDocument.write(scriptTag('document.F=Object'));
649           iframeDocument.close();
650           return iframeDocument.F;
651         };
652
653         // Check for document.domain and active x support
654         // No need to use active x approach when document.domain is not set
655         // see https://github.com/es-shims/es5-shim/issues/150
656         // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
657         // avoid IE GC bug
658         var activeXDocument;
659         var NullProtoObject = function () {
660           try {
661             /* global ActiveXObject */
662             activeXDocument = document.domain && new ActiveXObject('htmlfile');
663           } catch (error) { /* ignore */ }
664           NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
665           var length = enumBugKeys.length;
666           while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];
667           return NullProtoObject();
668         };
669
670         hiddenKeys[IE_PROTO] = true;
671
672         // `Object.create` method
673         // https://tc39.github.io/ecma262/#sec-object.create
674         var objectCreate = Object.create || function create(O, Properties) {
675           var result;
676           if (O !== null) {
677             EmptyConstructor[PROTOTYPE] = anObject(O);
678             result = new EmptyConstructor();
679             EmptyConstructor[PROTOTYPE] = null;
680             // add "__proto__" for Object.getPrototypeOf polyfill
681             result[IE_PROTO] = O;
682           } else result = NullProtoObject();
683           return Properties === undefined ? result : objectDefineProperties(result, Properties);
684         };
685
686         var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
687
688         var toString$1 = {}.toString;
689
690         var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
691           ? Object.getOwnPropertyNames(window) : [];
692
693         var getWindowNames = function (it) {
694           try {
695             return nativeGetOwnPropertyNames(it);
696           } catch (error) {
697             return windowNames.slice();
698           }
699         };
700
701         // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
702         var f$5 = function getOwnPropertyNames(it) {
703           return windowNames && toString$1.call(it) == '[object Window]'
704             ? getWindowNames(it)
705             : nativeGetOwnPropertyNames(toIndexedObject(it));
706         };
707
708         var objectGetOwnPropertyNamesExternal = {
709                 f: f$5
710         };
711
712         var WellKnownSymbolsStore = shared('wks');
713         var Symbol$1 = global_1.Symbol;
714         var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;
715
716         var wellKnownSymbol = function (name) {
717           if (!has(WellKnownSymbolsStore, name)) {
718             if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name];
719             else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
720           } return WellKnownSymbolsStore[name];
721         };
722
723         var f$6 = wellKnownSymbol;
724
725         var wellKnownSymbolWrapped = {
726                 f: f$6
727         };
728
729         var defineProperty = objectDefineProperty.f;
730
731         var defineWellKnownSymbol = function (NAME) {
732           var Symbol = path.Symbol || (path.Symbol = {});
733           if (!has(Symbol, NAME)) defineProperty(Symbol, NAME, {
734             value: wellKnownSymbolWrapped.f(NAME)
735           });
736         };
737
738         var defineProperty$1 = objectDefineProperty.f;
739
740
741
742         var TO_STRING_TAG = wellKnownSymbol('toStringTag');
743
744         var setToStringTag = function (it, TAG, STATIC) {
745           if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) {
746             defineProperty$1(it, TO_STRING_TAG, { configurable: true, value: TAG });
747           }
748         };
749
750         var aFunction$1 = function (it) {
751           if (typeof it != 'function') {
752             throw TypeError(String(it) + ' is not a function');
753           } return it;
754         };
755
756         // optional / simple context binding
757         var functionBindContext = function (fn, that, length) {
758           aFunction$1(fn);
759           if (that === undefined) return fn;
760           switch (length) {
761             case 0: return function () {
762               return fn.call(that);
763             };
764             case 1: return function (a) {
765               return fn.call(that, a);
766             };
767             case 2: return function (a, b) {
768               return fn.call(that, a, b);
769             };
770             case 3: return function (a, b, c) {
771               return fn.call(that, a, b, c);
772             };
773           }
774           return function (/* ...args */) {
775             return fn.apply(that, arguments);
776           };
777         };
778
779         var SPECIES = wellKnownSymbol('species');
780
781         // `ArraySpeciesCreate` abstract operation
782         // https://tc39.github.io/ecma262/#sec-arrayspeciescreate
783         var arraySpeciesCreate = function (originalArray, length) {
784           var C;
785           if (isArray(originalArray)) {
786             C = originalArray.constructor;
787             // cross-realm fallback
788             if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
789             else if (isObject(C)) {
790               C = C[SPECIES];
791               if (C === null) C = undefined;
792             }
793           } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
794         };
795
796         var push = [].push;
797
798         // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` methods implementation
799         var createMethod$1 = function (TYPE) {
800           var IS_MAP = TYPE == 1;
801           var IS_FILTER = TYPE == 2;
802           var IS_SOME = TYPE == 3;
803           var IS_EVERY = TYPE == 4;
804           var IS_FIND_INDEX = TYPE == 6;
805           var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
806           return function ($this, callbackfn, that, specificCreate) {
807             var O = toObject($this);
808             var self = indexedObject(O);
809             var boundFunction = functionBindContext(callbackfn, that, 3);
810             var length = toLength(self.length);
811             var index = 0;
812             var create = specificCreate || arraySpeciesCreate;
813             var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;
814             var value, result;
815             for (;length > index; index++) if (NO_HOLES || index in self) {
816               value = self[index];
817               result = boundFunction(value, index, O);
818               if (TYPE) {
819                 if (IS_MAP) target[index] = result; // map
820                 else if (result) switch (TYPE) {
821                   case 3: return true;              // some
822                   case 5: return value;             // find
823                   case 6: return index;             // findIndex
824                   case 2: push.call(target, value); // filter
825                 } else if (IS_EVERY) return false;  // every
826               }
827             }
828             return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
829           };
830         };
831
832         var arrayIteration = {
833           // `Array.prototype.forEach` method
834           // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
835           forEach: createMethod$1(0),
836           // `Array.prototype.map` method
837           // https://tc39.github.io/ecma262/#sec-array.prototype.map
838           map: createMethod$1(1),
839           // `Array.prototype.filter` method
840           // https://tc39.github.io/ecma262/#sec-array.prototype.filter
841           filter: createMethod$1(2),
842           // `Array.prototype.some` method
843           // https://tc39.github.io/ecma262/#sec-array.prototype.some
844           some: createMethod$1(3),
845           // `Array.prototype.every` method
846           // https://tc39.github.io/ecma262/#sec-array.prototype.every
847           every: createMethod$1(4),
848           // `Array.prototype.find` method
849           // https://tc39.github.io/ecma262/#sec-array.prototype.find
850           find: createMethod$1(5),
851           // `Array.prototype.findIndex` method
852           // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
853           findIndex: createMethod$1(6)
854         };
855
856         var $forEach = arrayIteration.forEach;
857
858         var HIDDEN = sharedKey('hidden');
859         var SYMBOL = 'Symbol';
860         var PROTOTYPE$1 = 'prototype';
861         var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
862         var setInternalState = internalState.set;
863         var getInternalState = internalState.getterFor(SYMBOL);
864         var ObjectPrototype = Object[PROTOTYPE$1];
865         var $Symbol = global_1.Symbol;
866         var $stringify = getBuiltIn('JSON', 'stringify');
867         var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
868         var nativeDefineProperty$1 = objectDefineProperty.f;
869         var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
870         var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
871         var AllSymbols = shared('symbols');
872         var ObjectPrototypeSymbols = shared('op-symbols');
873         var StringToSymbolRegistry = shared('string-to-symbol-registry');
874         var SymbolToStringRegistry = shared('symbol-to-string-registry');
875         var WellKnownSymbolsStore$1 = shared('wks');
876         var QObject = global_1.QObject;
877         // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
878         var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild;
879
880         // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
881         var setSymbolDescriptor = descriptors && fails(function () {
882           return objectCreate(nativeDefineProperty$1({}, 'a', {
883             get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; }
884           })).a != 7;
885         }) ? function (O, P, Attributes) {
886           var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P);
887           if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];
888           nativeDefineProperty$1(O, P, Attributes);
889           if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {
890             nativeDefineProperty$1(ObjectPrototype, P, ObjectPrototypeDescriptor);
891           }
892         } : nativeDefineProperty$1;
893
894         var wrap = function (tag, description) {
895           var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]);
896           setInternalState(symbol, {
897             type: SYMBOL,
898             tag: tag,
899             description: description
900           });
901           if (!descriptors) symbol.description = description;
902           return symbol;
903         };
904
905         var isSymbol = useSymbolAsUid ? function (it) {
906           return typeof it == 'symbol';
907         } : function (it) {
908           return Object(it) instanceof $Symbol;
909         };
910
911         var $defineProperty = function defineProperty(O, P, Attributes) {
912           if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
913           anObject(O);
914           var key = toPrimitive(P, true);
915           anObject(Attributes);
916           if (has(AllSymbols, key)) {
917             if (!Attributes.enumerable) {
918               if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {}));
919               O[HIDDEN][key] = true;
920             } else {
921               if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
922               Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) });
923             } return setSymbolDescriptor(O, key, Attributes);
924           } return nativeDefineProperty$1(O, key, Attributes);
925         };
926
927         var $defineProperties = function defineProperties(O, Properties) {
928           anObject(O);
929           var properties = toIndexedObject(Properties);
930           var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
931           $forEach(keys, function (key) {
932             if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
933           });
934           return O;
935         };
936
937         var $create = function create(O, Properties) {
938           return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
939         };
940
941         var $propertyIsEnumerable = function propertyIsEnumerable(V) {
942           var P = toPrimitive(V, true);
943           var enumerable = nativePropertyIsEnumerable$1.call(this, P);
944           if (this === ObjectPrototype && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false;
945           return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
946         };
947
948         var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
949           var it = toIndexedObject(O);
950           var key = toPrimitive(P, true);
951           if (it === ObjectPrototype && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return;
952           var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
953           if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) {
954             descriptor.enumerable = true;
955           }
956           return descriptor;
957         };
958
959         var $getOwnPropertyNames = function getOwnPropertyNames(O) {
960           var names = nativeGetOwnPropertyNames$1(toIndexedObject(O));
961           var result = [];
962           $forEach(names, function (key) {
963             if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key);
964           });
965           return result;
966         };
967
968         var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
969           var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;
970           var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
971           var result = [];
972           $forEach(names, function (key) {
973             if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype, key))) {
974               result.push(AllSymbols[key]);
975             }
976           });
977           return result;
978         };
979
980         // `Symbol` constructor
981         // https://tc39.github.io/ecma262/#sec-symbol-constructor
982         if (!nativeSymbol) {
983           $Symbol = function Symbol() {
984             if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
985             var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
986             var tag = uid(description);
987             var setter = function (value) {
988               if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value);
989               if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
990               setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
991             };
992             if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, { configurable: true, set: setter });
993             return wrap(tag, description);
994           };
995
996           redefine($Symbol[PROTOTYPE$1], 'toString', function toString() {
997             return getInternalState(this).tag;
998           });
999
1000           redefine($Symbol, 'withoutSetter', function (description) {
1001             return wrap(uid(description), description);
1002           });
1003
1004           objectPropertyIsEnumerable.f = $propertyIsEnumerable;
1005           objectDefineProperty.f = $defineProperty;
1006           objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
1007           objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
1008           objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;
1009
1010           wellKnownSymbolWrapped.f = function (name) {
1011             return wrap(wellKnownSymbol(name), name);
1012           };
1013
1014           if (descriptors) {
1015             // https://github.com/tc39/proposal-Symbol-description
1016             nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
1017               configurable: true,
1018               get: function description() {
1019                 return getInternalState(this).description;
1020               }
1021             });
1022             {
1023               redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true });
1024             }
1025           }
1026         }
1027
1028         _export({ global: true, wrap: true, forced: !nativeSymbol, sham: !nativeSymbol }, {
1029           Symbol: $Symbol
1030         });
1031
1032         $forEach(objectKeys(WellKnownSymbolsStore$1), function (name) {
1033           defineWellKnownSymbol(name);
1034         });
1035
1036         _export({ target: SYMBOL, stat: true, forced: !nativeSymbol }, {
1037           // `Symbol.for` method
1038           // https://tc39.github.io/ecma262/#sec-symbol.for
1039           'for': function (key) {
1040             var string = String(key);
1041             if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
1042             var symbol = $Symbol(string);
1043             StringToSymbolRegistry[string] = symbol;
1044             SymbolToStringRegistry[symbol] = string;
1045             return symbol;
1046           },
1047           // `Symbol.keyFor` method
1048           // https://tc39.github.io/ecma262/#sec-symbol.keyfor
1049           keyFor: function keyFor(sym) {
1050             if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
1051             if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
1052           },
1053           useSetter: function () { USE_SETTER = true; },
1054           useSimple: function () { USE_SETTER = false; }
1055         });
1056
1057         _export({ target: 'Object', stat: true, forced: !nativeSymbol, sham: !descriptors }, {
1058           // `Object.create` method
1059           // https://tc39.github.io/ecma262/#sec-object.create
1060           create: $create,
1061           // `Object.defineProperty` method
1062           // https://tc39.github.io/ecma262/#sec-object.defineproperty
1063           defineProperty: $defineProperty,
1064           // `Object.defineProperties` method
1065           // https://tc39.github.io/ecma262/#sec-object.defineproperties
1066           defineProperties: $defineProperties,
1067           // `Object.getOwnPropertyDescriptor` method
1068           // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors
1069           getOwnPropertyDescriptor: $getOwnPropertyDescriptor
1070         });
1071
1072         _export({ target: 'Object', stat: true, forced: !nativeSymbol }, {
1073           // `Object.getOwnPropertyNames` method
1074           // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
1075           getOwnPropertyNames: $getOwnPropertyNames,
1076           // `Object.getOwnPropertySymbols` method
1077           // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols
1078           getOwnPropertySymbols: $getOwnPropertySymbols
1079         });
1080
1081         // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
1082         // https://bugs.chromium.org/p/v8/issues/detail?id=3443
1083         _export({ target: 'Object', stat: true, forced: fails(function () { objectGetOwnPropertySymbols.f(1); }) }, {
1084           getOwnPropertySymbols: function getOwnPropertySymbols(it) {
1085             return objectGetOwnPropertySymbols.f(toObject(it));
1086           }
1087         });
1088
1089         // `JSON.stringify` method behavior with symbols
1090         // https://tc39.github.io/ecma262/#sec-json.stringify
1091         if ($stringify) {
1092           var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () {
1093             var symbol = $Symbol();
1094             // MS Edge converts symbol values to JSON as {}
1095             return $stringify([symbol]) != '[null]'
1096               // WebKit converts symbol values to JSON as null
1097               || $stringify({ a: symbol }) != '{}'
1098               // V8 throws on boxed symbols
1099               || $stringify(Object(symbol)) != '{}';
1100           });
1101
1102           _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {
1103             // eslint-disable-next-line no-unused-vars
1104             stringify: function stringify(it, replacer, space) {
1105               var args = [it];
1106               var index = 1;
1107               var $replacer;
1108               while (arguments.length > index) args.push(arguments[index++]);
1109               $replacer = replacer;
1110               if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
1111               if (!isArray(replacer)) replacer = function (key, value) {
1112                 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
1113                 if (!isSymbol(value)) return value;
1114               };
1115               args[1] = replacer;
1116               return $stringify.apply(null, args);
1117             }
1118           });
1119         }
1120
1121         // `Symbol.prototype[@@toPrimitive]` method
1122         // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive
1123         if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
1124           createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
1125         }
1126         // `Symbol.prototype[@@toStringTag]` property
1127         // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag
1128         setToStringTag($Symbol, SYMBOL);
1129
1130         hiddenKeys[HIDDEN] = true;
1131
1132         var defineProperty$2 = objectDefineProperty.f;
1133
1134
1135         var NativeSymbol = global_1.Symbol;
1136
1137         if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
1138           // Safari 12 bug
1139           NativeSymbol().description !== undefined
1140         )) {
1141           var EmptyStringDescriptionStore = {};
1142           // wrap Symbol constructor for correct work with undefined description
1143           var SymbolWrapper = function Symbol() {
1144             var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
1145             var result = this instanceof SymbolWrapper
1146               ? new NativeSymbol(description)
1147               // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
1148               : description === undefined ? NativeSymbol() : NativeSymbol(description);
1149             if (description === '') EmptyStringDescriptionStore[result] = true;
1150             return result;
1151           };
1152           copyConstructorProperties(SymbolWrapper, NativeSymbol);
1153           var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
1154           symbolPrototype.constructor = SymbolWrapper;
1155
1156           var symbolToString = symbolPrototype.toString;
1157           var native = String(NativeSymbol('test')) == 'Symbol(test)';
1158           var regexp = /^Symbol\((.*)\)[^)]+$/;
1159           defineProperty$2(symbolPrototype, 'description', {
1160             configurable: true,
1161             get: function description() {
1162               var symbol = isObject(this) ? this.valueOf() : this;
1163               var string = symbolToString.call(symbol);
1164               if (has(EmptyStringDescriptionStore, symbol)) return '';
1165               var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
1166               return desc === '' ? undefined : desc;
1167             }
1168           });
1169
1170           _export({ global: true, forced: true }, {
1171             Symbol: SymbolWrapper
1172           });
1173         }
1174
1175         // `Symbol.iterator` well-known symbol
1176         // https://tc39.github.io/ecma262/#sec-symbol.iterator
1177         defineWellKnownSymbol('iterator');
1178
1179         var arrayMethodIsStrict = function (METHOD_NAME, argument) {
1180           var method = [][METHOD_NAME];
1181           return !!method && fails(function () {
1182             // eslint-disable-next-line no-useless-call,no-throw-literal
1183             method.call(null, argument || function () { throw 1; }, 1);
1184           });
1185         };
1186
1187         var defineProperty$3 = Object.defineProperty;
1188         var cache = {};
1189
1190         var thrower = function (it) { throw it; };
1191
1192         var arrayMethodUsesToLength = function (METHOD_NAME, options) {
1193           if (has(cache, METHOD_NAME)) return cache[METHOD_NAME];
1194           if (!options) options = {};
1195           var method = [][METHOD_NAME];
1196           var ACCESSORS = has(options, 'ACCESSORS') ? options.ACCESSORS : false;
1197           var argument0 = has(options, 0) ? options[0] : thrower;
1198           var argument1 = has(options, 1) ? options[1] : undefined;
1199
1200           return cache[METHOD_NAME] = !!method && !fails(function () {
1201             if (ACCESSORS && !descriptors) return true;
1202             var O = { length: -1 };
1203
1204             if (ACCESSORS) defineProperty$3(O, 1, { enumerable: true, get: thrower });
1205             else O[1] = 1;
1206
1207             method.call(O, argument0, argument1);
1208           });
1209         };
1210
1211         var $forEach$1 = arrayIteration.forEach;
1212
1213
1214
1215         var STRICT_METHOD = arrayMethodIsStrict('forEach');
1216         var USES_TO_LENGTH = arrayMethodUsesToLength('forEach');
1217
1218         // `Array.prototype.forEach` method implementation
1219         // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
1220         var arrayForEach = (!STRICT_METHOD || !USES_TO_LENGTH) ? function forEach(callbackfn /* , thisArg */) {
1221           return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
1222         } : [].forEach;
1223
1224         // `Array.prototype.forEach` method
1225         // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
1226         _export({ target: 'Array', proto: true, forced: [].forEach != arrayForEach }, {
1227           forEach: arrayForEach
1228         });
1229
1230         var $indexOf = arrayIncludes.indexOf;
1231
1232
1233
1234         var nativeIndexOf = [].indexOf;
1235
1236         var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
1237         var STRICT_METHOD$1 = arrayMethodIsStrict('indexOf');
1238         var USES_TO_LENGTH$1 = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
1239
1240         // `Array.prototype.indexOf` method
1241         // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
1242         _export({ target: 'Array', proto: true, forced: NEGATIVE_ZERO || !STRICT_METHOD$1 || !USES_TO_LENGTH$1 }, {
1243           indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
1244             return NEGATIVE_ZERO
1245               // convert -0 to +0
1246               ? nativeIndexOf.apply(this, arguments) || 0
1247               : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
1248           }
1249         });
1250
1251         // `Array.isArray` method
1252         // https://tc39.github.io/ecma262/#sec-array.isarray
1253         _export({ target: 'Array', stat: true }, {
1254           isArray: isArray
1255         });
1256
1257         var UNSCOPABLES = wellKnownSymbol('unscopables');
1258         var ArrayPrototype = Array.prototype;
1259
1260         // Array.prototype[@@unscopables]
1261         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
1262         if (ArrayPrototype[UNSCOPABLES] == undefined) {
1263           objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, {
1264             configurable: true,
1265             value: objectCreate(null)
1266           });
1267         }
1268
1269         // add a key to Array.prototype[@@unscopables]
1270         var addToUnscopables = function (key) {
1271           ArrayPrototype[UNSCOPABLES][key] = true;
1272         };
1273
1274         var iterators = {};
1275
1276         var correctPrototypeGetter = !fails(function () {
1277           function F() { /* empty */ }
1278           F.prototype.constructor = null;
1279           return Object.getPrototypeOf(new F()) !== F.prototype;
1280         });
1281
1282         var IE_PROTO$1 = sharedKey('IE_PROTO');
1283         var ObjectPrototype$1 = Object.prototype;
1284
1285         // `Object.getPrototypeOf` method
1286         // https://tc39.github.io/ecma262/#sec-object.getprototypeof
1287         var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
1288           O = toObject(O);
1289           if (has(O, IE_PROTO$1)) return O[IE_PROTO$1];
1290           if (typeof O.constructor == 'function' && O instanceof O.constructor) {
1291             return O.constructor.prototype;
1292           } return O instanceof Object ? ObjectPrototype$1 : null;
1293         };
1294
1295         var ITERATOR = wellKnownSymbol('iterator');
1296         var BUGGY_SAFARI_ITERATORS = false;
1297
1298         var returnThis = function () { return this; };
1299
1300         // `%IteratorPrototype%` object
1301         // https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object
1302         var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;
1303
1304         if ([].keys) {
1305           arrayIterator = [].keys();
1306           // Safari 8 has buggy iterators w/o `next`
1307           if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;
1308           else {
1309             PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
1310             if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
1311           }
1312         }
1313
1314         if (IteratorPrototype == undefined) IteratorPrototype = {};
1315
1316         // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
1317         if ( !has(IteratorPrototype, ITERATOR)) {
1318           createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis);
1319         }
1320
1321         var iteratorsCore = {
1322           IteratorPrototype: IteratorPrototype,
1323           BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
1324         };
1325
1326         var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1327
1328
1329
1330
1331
1332         var returnThis$1 = function () { return this; };
1333
1334         var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
1335           var TO_STRING_TAG = NAME + ' Iterator';
1336           IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) });
1337           setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
1338           iterators[TO_STRING_TAG] = returnThis$1;
1339           return IteratorConstructor;
1340         };
1341
1342         var aPossiblePrototype = function (it) {
1343           if (!isObject(it) && it !== null) {
1344             throw TypeError("Can't set " + String(it) + ' as a prototype');
1345           } return it;
1346         };
1347
1348         // `Object.setPrototypeOf` method
1349         // https://tc39.github.io/ecma262/#sec-object.setprototypeof
1350         // Works with __proto__ only. Old v8 can't work with null proto objects.
1351         /* eslint-disable no-proto */
1352         var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1353           var CORRECT_SETTER = false;
1354           var test = {};
1355           var setter;
1356           try {
1357             setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1358             setter.call(test, []);
1359             CORRECT_SETTER = test instanceof Array;
1360           } catch (error) { /* empty */ }
1361           return function setPrototypeOf(O, proto) {
1362             anObject(O);
1363             aPossiblePrototype(proto);
1364             if (CORRECT_SETTER) setter.call(O, proto);
1365             else O.__proto__ = proto;
1366             return O;
1367           };
1368         }() : undefined);
1369
1370         var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
1371         var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
1372         var ITERATOR$1 = wellKnownSymbol('iterator');
1373         var KEYS = 'keys';
1374         var VALUES = 'values';
1375         var ENTRIES = 'entries';
1376
1377         var returnThis$2 = function () { return this; };
1378
1379         var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1380           createIteratorConstructor(IteratorConstructor, NAME, next);
1381
1382           var getIterationMethod = function (KIND) {
1383             if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1384             if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
1385             switch (KIND) {
1386               case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
1387               case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
1388               case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
1389             } return function () { return new IteratorConstructor(this); };
1390           };
1391
1392           var TO_STRING_TAG = NAME + ' Iterator';
1393           var INCORRECT_VALUES_NAME = false;
1394           var IterablePrototype = Iterable.prototype;
1395           var nativeIterator = IterablePrototype[ITERATOR$1]
1396             || IterablePrototype['@@iterator']
1397             || DEFAULT && IterablePrototype[DEFAULT];
1398           var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
1399           var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1400           var CurrentIteratorPrototype, methods, KEY;
1401
1402           // fix native
1403           if (anyNativeIterator) {
1404             CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
1405             if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
1406               if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
1407                 if (objectSetPrototypeOf) {
1408                   objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
1409                 } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') {
1410                   createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$2);
1411                 }
1412               }
1413               // Set @@toStringTag to native iterators
1414               setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
1415             }
1416           }
1417
1418           // fix Array#{values, @@iterator}.name in V8 / FF
1419           if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1420             INCORRECT_VALUES_NAME = true;
1421             defaultIterator = function values() { return nativeIterator.call(this); };
1422           }
1423
1424           // define iterator
1425           if ( IterablePrototype[ITERATOR$1] !== defaultIterator) {
1426             createNonEnumerableProperty(IterablePrototype, ITERATOR$1, defaultIterator);
1427           }
1428           iterators[NAME] = defaultIterator;
1429
1430           // export additional methods
1431           if (DEFAULT) {
1432             methods = {
1433               values: getIterationMethod(VALUES),
1434               keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1435               entries: getIterationMethod(ENTRIES)
1436             };
1437             if (FORCED) for (KEY in methods) {
1438               if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1439                 redefine(IterablePrototype, KEY, methods[KEY]);
1440               }
1441             } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME }, methods);
1442           }
1443
1444           return methods;
1445         };
1446
1447         var ARRAY_ITERATOR = 'Array Iterator';
1448         var setInternalState$1 = internalState.set;
1449         var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR);
1450
1451         // `Array.prototype.entries` method
1452         // https://tc39.github.io/ecma262/#sec-array.prototype.entries
1453         // `Array.prototype.keys` method
1454         // https://tc39.github.io/ecma262/#sec-array.prototype.keys
1455         // `Array.prototype.values` method
1456         // https://tc39.github.io/ecma262/#sec-array.prototype.values
1457         // `Array.prototype[@@iterator]` method
1458         // https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
1459         // `CreateArrayIterator` internal method
1460         // https://tc39.github.io/ecma262/#sec-createarrayiterator
1461         var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
1462           setInternalState$1(this, {
1463             type: ARRAY_ITERATOR,
1464             target: toIndexedObject(iterated), // target
1465             index: 0,                          // next index
1466             kind: kind                         // kind
1467           });
1468         // `%ArrayIteratorPrototype%.next` method
1469         // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
1470         }, function () {
1471           var state = getInternalState$1(this);
1472           var target = state.target;
1473           var kind = state.kind;
1474           var index = state.index++;
1475           if (!target || index >= target.length) {
1476             state.target = undefined;
1477             return { value: undefined, done: true };
1478           }
1479           if (kind == 'keys') return { value: index, done: false };
1480           if (kind == 'values') return { value: target[index], done: false };
1481           return { value: [index, target[index]], done: false };
1482         }, 'values');
1483
1484         // argumentsList[@@iterator] is %ArrayProto_values%
1485         // https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
1486         // https://tc39.github.io/ecma262/#sec-createmappedargumentsobject
1487         iterators.Arguments = iterators.Array;
1488
1489         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
1490         addToUnscopables('keys');
1491         addToUnscopables('values');
1492         addToUnscopables('entries');
1493
1494         var nativeJoin = [].join;
1495
1496         var ES3_STRINGS = indexedObject != Object;
1497         var STRICT_METHOD$2 = arrayMethodIsStrict('join', ',');
1498
1499         // `Array.prototype.join` method
1500         // https://tc39.github.io/ecma262/#sec-array.prototype.join
1501         _export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$2 }, {
1502           join: function join(separator) {
1503             return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
1504           }
1505         });
1506
1507         var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';
1508
1509         var process$1 = global_1.process;
1510         var versions = process$1 && process$1.versions;
1511         var v8 = versions && versions.v8;
1512         var match, version;
1513
1514         if (v8) {
1515           match = v8.split('.');
1516           version = match[0] + match[1];
1517         } else if (engineUserAgent) {
1518           match = engineUserAgent.match(/Edge\/(\d+)/);
1519           if (!match || match[1] >= 74) {
1520             match = engineUserAgent.match(/Chrome\/(\d+)/);
1521             if (match) version = match[1];
1522           }
1523         }
1524
1525         var engineV8Version = version && +version;
1526
1527         var SPECIES$1 = wellKnownSymbol('species');
1528
1529         var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
1530           // We can't use this feature detection in V8 since it causes
1531           // deoptimization and serious performance degradation
1532           // https://github.com/zloirock/core-js/issues/677
1533           return engineV8Version >= 51 || !fails(function () {
1534             var array = [];
1535             var constructor = array.constructor = {};
1536             constructor[SPECIES$1] = function () {
1537               return { foo: 1 };
1538             };
1539             return array[METHOD_NAME](Boolean).foo !== 1;
1540           });
1541         };
1542
1543         var $map = arrayIteration.map;
1544
1545
1546
1547         var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('map');
1548         // FF49- issue
1549         var USES_TO_LENGTH$2 = arrayMethodUsesToLength('map');
1550
1551         // `Array.prototype.map` method
1552         // https://tc39.github.io/ecma262/#sec-array.prototype.map
1553         // with adding support of @@species
1554         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT || !USES_TO_LENGTH$2 }, {
1555           map: function map(callbackfn /* , thisArg */) {
1556             return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
1557           }
1558         });
1559
1560         var createProperty = function (object, key, value) {
1561           var propertyKey = toPrimitive(key);
1562           if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
1563           else object[propertyKey] = value;
1564         };
1565
1566         var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('slice');
1567         var USES_TO_LENGTH$3 = arrayMethodUsesToLength('slice', { ACCESSORS: true, 0: 0, 1: 2 });
1568
1569         var SPECIES$2 = wellKnownSymbol('species');
1570         var nativeSlice = [].slice;
1571         var max$1 = Math.max;
1572
1573         // `Array.prototype.slice` method
1574         // https://tc39.github.io/ecma262/#sec-array.prototype.slice
1575         // fallback for not array-like ES3 strings and DOM objects
1576         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 || !USES_TO_LENGTH$3 }, {
1577           slice: function slice(start, end) {
1578             var O = toIndexedObject(this);
1579             var length = toLength(O.length);
1580             var k = toAbsoluteIndex(start, length);
1581             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
1582             // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
1583             var Constructor, result, n;
1584             if (isArray(O)) {
1585               Constructor = O.constructor;
1586               // cross-realm fallback
1587               if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
1588                 Constructor = undefined;
1589               } else if (isObject(Constructor)) {
1590                 Constructor = Constructor[SPECIES$2];
1591                 if (Constructor === null) Constructor = undefined;
1592               }
1593               if (Constructor === Array || Constructor === undefined) {
1594                 return nativeSlice.call(O, k, fin);
1595               }
1596             }
1597             result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));
1598             for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
1599             result.length = n;
1600             return result;
1601           }
1602         });
1603
1604         var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';
1605
1606         var redefineAll = function (target, src, options) {
1607           for (var key in src) redefine(target, key, src[key], options);
1608           return target;
1609         };
1610
1611         var anInstance = function (it, Constructor, name) {
1612           if (!(it instanceof Constructor)) {
1613             throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
1614           } return it;
1615         };
1616
1617         // `ToIndex` abstract operation
1618         // https://tc39.github.io/ecma262/#sec-toindex
1619         var toIndex = function (it) {
1620           if (it === undefined) return 0;
1621           var number = toInteger(it);
1622           var length = toLength(number);
1623           if (number !== length) throw RangeError('Wrong length or index');
1624           return length;
1625         };
1626
1627         // IEEE754 conversions based on https://github.com/feross/ieee754
1628         // eslint-disable-next-line no-shadow-restricted-names
1629         var Infinity$1 = 1 / 0;
1630         var abs = Math.abs;
1631         var pow = Math.pow;
1632         var floor$1 = Math.floor;
1633         var log = Math.log;
1634         var LN2 = Math.LN2;
1635
1636         var pack = function (number, mantissaLength, bytes) {
1637           var buffer = new Array(bytes);
1638           var exponentLength = bytes * 8 - mantissaLength - 1;
1639           var eMax = (1 << exponentLength) - 1;
1640           var eBias = eMax >> 1;
1641           var rt = mantissaLength === 23 ? pow(2, -24) - pow(2, -77) : 0;
1642           var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
1643           var index = 0;
1644           var exponent, mantissa, c;
1645           number = abs(number);
1646           // eslint-disable-next-line no-self-compare
1647           if (number != number || number === Infinity$1) {
1648             // eslint-disable-next-line no-self-compare
1649             mantissa = number != number ? 1 : 0;
1650             exponent = eMax;
1651           } else {
1652             exponent = floor$1(log(number) / LN2);
1653             if (number * (c = pow(2, -exponent)) < 1) {
1654               exponent--;
1655               c *= 2;
1656             }
1657             if (exponent + eBias >= 1) {
1658               number += rt / c;
1659             } else {
1660               number += rt * pow(2, 1 - eBias);
1661             }
1662             if (number * c >= 2) {
1663               exponent++;
1664               c /= 2;
1665             }
1666             if (exponent + eBias >= eMax) {
1667               mantissa = 0;
1668               exponent = eMax;
1669             } else if (exponent + eBias >= 1) {
1670               mantissa = (number * c - 1) * pow(2, mantissaLength);
1671               exponent = exponent + eBias;
1672             } else {
1673               mantissa = number * pow(2, eBias - 1) * pow(2, mantissaLength);
1674               exponent = 0;
1675             }
1676           }
1677           for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
1678           exponent = exponent << mantissaLength | mantissa;
1679           exponentLength += mantissaLength;
1680           for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
1681           buffer[--index] |= sign * 128;
1682           return buffer;
1683         };
1684
1685         var unpack = function (buffer, mantissaLength) {
1686           var bytes = buffer.length;
1687           var exponentLength = bytes * 8 - mantissaLength - 1;
1688           var eMax = (1 << exponentLength) - 1;
1689           var eBias = eMax >> 1;
1690           var nBits = exponentLength - 7;
1691           var index = bytes - 1;
1692           var sign = buffer[index--];
1693           var exponent = sign & 127;
1694           var mantissa;
1695           sign >>= 7;
1696           for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
1697           mantissa = exponent & (1 << -nBits) - 1;
1698           exponent >>= -nBits;
1699           nBits += mantissaLength;
1700           for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
1701           if (exponent === 0) {
1702             exponent = 1 - eBias;
1703           } else if (exponent === eMax) {
1704             return mantissa ? NaN : sign ? -Infinity$1 : Infinity$1;
1705           } else {
1706             mantissa = mantissa + pow(2, mantissaLength);
1707             exponent = exponent - eBias;
1708           } return (sign ? -1 : 1) * mantissa * pow(2, exponent - mantissaLength);
1709         };
1710
1711         var ieee754 = {
1712           pack: pack,
1713           unpack: unpack
1714         };
1715
1716         // `Array.prototype.fill` method implementation
1717         // https://tc39.github.io/ecma262/#sec-array.prototype.fill
1718         var arrayFill = function fill(value /* , start = 0, end = @length */) {
1719           var O = toObject(this);
1720           var length = toLength(O.length);
1721           var argumentsLength = arguments.length;
1722           var index = toAbsoluteIndex(argumentsLength > 1 ? arguments[1] : undefined, length);
1723           var end = argumentsLength > 2 ? arguments[2] : undefined;
1724           var endPos = end === undefined ? length : toAbsoluteIndex(end, length);
1725           while (endPos > index) O[index++] = value;
1726           return O;
1727         };
1728
1729         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
1730         var defineProperty$4 = objectDefineProperty.f;
1731
1732
1733
1734
1735         var getInternalState$2 = internalState.get;
1736         var setInternalState$2 = internalState.set;
1737         var ARRAY_BUFFER = 'ArrayBuffer';
1738         var DATA_VIEW = 'DataView';
1739         var PROTOTYPE$2 = 'prototype';
1740         var WRONG_LENGTH = 'Wrong length';
1741         var WRONG_INDEX = 'Wrong index';
1742         var NativeArrayBuffer = global_1[ARRAY_BUFFER];
1743         var $ArrayBuffer = NativeArrayBuffer;
1744         var $DataView = global_1[DATA_VIEW];
1745         var $DataViewPrototype = $DataView && $DataView[PROTOTYPE$2];
1746         var ObjectPrototype$2 = Object.prototype;
1747         var RangeError$1 = global_1.RangeError;
1748
1749         var packIEEE754 = ieee754.pack;
1750         var unpackIEEE754 = ieee754.unpack;
1751
1752         var packInt8 = function (number) {
1753           return [number & 0xFF];
1754         };
1755
1756         var packInt16 = function (number) {
1757           return [number & 0xFF, number >> 8 & 0xFF];
1758         };
1759
1760         var packInt32 = function (number) {
1761           return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
1762         };
1763
1764         var unpackInt32 = function (buffer) {
1765           return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
1766         };
1767
1768         var packFloat32 = function (number) {
1769           return packIEEE754(number, 23, 4);
1770         };
1771
1772         var packFloat64 = function (number) {
1773           return packIEEE754(number, 52, 8);
1774         };
1775
1776         var addGetter = function (Constructor, key) {
1777           defineProperty$4(Constructor[PROTOTYPE$2], key, { get: function () { return getInternalState$2(this)[key]; } });
1778         };
1779
1780         var get$1 = function (view, count, index, isLittleEndian) {
1781           var intIndex = toIndex(index);
1782           var store = getInternalState$2(view);
1783           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1784           var bytes = getInternalState$2(store.buffer).bytes;
1785           var start = intIndex + store.byteOffset;
1786           var pack = bytes.slice(start, start + count);
1787           return isLittleEndian ? pack : pack.reverse();
1788         };
1789
1790         var set$1 = function (view, count, index, conversion, value, isLittleEndian) {
1791           var intIndex = toIndex(index);
1792           var store = getInternalState$2(view);
1793           if (intIndex + count > store.byteLength) throw RangeError$1(WRONG_INDEX);
1794           var bytes = getInternalState$2(store.buffer).bytes;
1795           var start = intIndex + store.byteOffset;
1796           var pack = conversion(+value);
1797           for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
1798         };
1799
1800         if (!arrayBufferNative) {
1801           $ArrayBuffer = function ArrayBuffer(length) {
1802             anInstance(this, $ArrayBuffer, ARRAY_BUFFER);
1803             var byteLength = toIndex(length);
1804             setInternalState$2(this, {
1805               bytes: arrayFill.call(new Array(byteLength), 0),
1806               byteLength: byteLength
1807             });
1808             if (!descriptors) this.byteLength = byteLength;
1809           };
1810
1811           $DataView = function DataView(buffer, byteOffset, byteLength) {
1812             anInstance(this, $DataView, DATA_VIEW);
1813             anInstance(buffer, $ArrayBuffer, DATA_VIEW);
1814             var bufferLength = getInternalState$2(buffer).byteLength;
1815             var offset = toInteger(byteOffset);
1816             if (offset < 0 || offset > bufferLength) throw RangeError$1('Wrong offset');
1817             byteLength = byteLength === undefined ? bufferLength - offset : toLength(byteLength);
1818             if (offset + byteLength > bufferLength) throw RangeError$1(WRONG_LENGTH);
1819             setInternalState$2(this, {
1820               buffer: buffer,
1821               byteLength: byteLength,
1822               byteOffset: offset
1823             });
1824             if (!descriptors) {
1825               this.buffer = buffer;
1826               this.byteLength = byteLength;
1827               this.byteOffset = offset;
1828             }
1829           };
1830
1831           if (descriptors) {
1832             addGetter($ArrayBuffer, 'byteLength');
1833             addGetter($DataView, 'buffer');
1834             addGetter($DataView, 'byteLength');
1835             addGetter($DataView, 'byteOffset');
1836           }
1837
1838           redefineAll($DataView[PROTOTYPE$2], {
1839             getInt8: function getInt8(byteOffset) {
1840               return get$1(this, 1, byteOffset)[0] << 24 >> 24;
1841             },
1842             getUint8: function getUint8(byteOffset) {
1843               return get$1(this, 1, byteOffset)[0];
1844             },
1845             getInt16: function getInt16(byteOffset /* , littleEndian */) {
1846               var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
1847               return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
1848             },
1849             getUint16: function getUint16(byteOffset /* , littleEndian */) {
1850               var bytes = get$1(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
1851               return bytes[1] << 8 | bytes[0];
1852             },
1853             getInt32: function getInt32(byteOffset /* , littleEndian */) {
1854               return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
1855             },
1856             getUint32: function getUint32(byteOffset /* , littleEndian */) {
1857               return unpackInt32(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
1858             },
1859             getFloat32: function getFloat32(byteOffset /* , littleEndian */) {
1860               return unpackIEEE754(get$1(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
1861             },
1862             getFloat64: function getFloat64(byteOffset /* , littleEndian */) {
1863               return unpackIEEE754(get$1(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
1864             },
1865             setInt8: function setInt8(byteOffset, value) {
1866               set$1(this, 1, byteOffset, packInt8, value);
1867             },
1868             setUint8: function setUint8(byteOffset, value) {
1869               set$1(this, 1, byteOffset, packInt8, value);
1870             },
1871             setInt16: function setInt16(byteOffset, value /* , littleEndian */) {
1872               set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
1873             },
1874             setUint16: function setUint16(byteOffset, value /* , littleEndian */) {
1875               set$1(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
1876             },
1877             setInt32: function setInt32(byteOffset, value /* , littleEndian */) {
1878               set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
1879             },
1880             setUint32: function setUint32(byteOffset, value /* , littleEndian */) {
1881               set$1(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
1882             },
1883             setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {
1884               set$1(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
1885             },
1886             setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {
1887               set$1(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
1888             }
1889           });
1890         } else {
1891           if (!fails(function () {
1892             NativeArrayBuffer(1);
1893           }) || !fails(function () {
1894             new NativeArrayBuffer(-1); // eslint-disable-line no-new
1895           }) || fails(function () {
1896             new NativeArrayBuffer(); // eslint-disable-line no-new
1897             new NativeArrayBuffer(1.5); // eslint-disable-line no-new
1898             new NativeArrayBuffer(NaN); // eslint-disable-line no-new
1899             return NativeArrayBuffer.name != ARRAY_BUFFER;
1900           })) {
1901             $ArrayBuffer = function ArrayBuffer(length) {
1902               anInstance(this, $ArrayBuffer);
1903               return new NativeArrayBuffer(toIndex(length));
1904             };
1905             var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE$2] = NativeArrayBuffer[PROTOTYPE$2];
1906             for (var keys$1 = getOwnPropertyNames(NativeArrayBuffer), j = 0, key; keys$1.length > j;) {
1907               if (!((key = keys$1[j++]) in $ArrayBuffer)) {
1908                 createNonEnumerableProperty($ArrayBuffer, key, NativeArrayBuffer[key]);
1909               }
1910             }
1911             ArrayBufferPrototype.constructor = $ArrayBuffer;
1912           }
1913
1914           // WebKit bug - the same parent prototype for typed arrays and data view
1915           if (objectSetPrototypeOf && objectGetPrototypeOf($DataViewPrototype) !== ObjectPrototype$2) {
1916             objectSetPrototypeOf($DataViewPrototype, ObjectPrototype$2);
1917           }
1918
1919           // iOS Safari 7.x bug
1920           var testView = new $DataView(new $ArrayBuffer(2));
1921           var nativeSetInt8 = $DataViewPrototype.setInt8;
1922           testView.setInt8(0, 2147483648);
1923           testView.setInt8(1, 2147483649);
1924           if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll($DataViewPrototype, {
1925             setInt8: function setInt8(byteOffset, value) {
1926               nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
1927             },
1928             setUint8: function setUint8(byteOffset, value) {
1929               nativeSetInt8.call(this, byteOffset, value << 24 >> 24);
1930             }
1931           }, { unsafe: true });
1932         }
1933
1934         setToStringTag($ArrayBuffer, ARRAY_BUFFER);
1935         setToStringTag($DataView, DATA_VIEW);
1936
1937         var arrayBuffer = {
1938           ArrayBuffer: $ArrayBuffer,
1939           DataView: $DataView
1940         };
1941
1942         var SPECIES$3 = wellKnownSymbol('species');
1943
1944         var setSpecies = function (CONSTRUCTOR_NAME) {
1945           var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
1946           var defineProperty = objectDefineProperty.f;
1947
1948           if (descriptors && Constructor && !Constructor[SPECIES$3]) {
1949             defineProperty(Constructor, SPECIES$3, {
1950               configurable: true,
1951               get: function () { return this; }
1952             });
1953           }
1954         };
1955
1956         var ARRAY_BUFFER$1 = 'ArrayBuffer';
1957         var ArrayBuffer$1 = arrayBuffer[ARRAY_BUFFER$1];
1958         var NativeArrayBuffer$1 = global_1[ARRAY_BUFFER$1];
1959
1960         // `ArrayBuffer` constructor
1961         // https://tc39.github.io/ecma262/#sec-arraybuffer-constructor
1962         _export({ global: true, forced: NativeArrayBuffer$1 !== ArrayBuffer$1 }, {
1963           ArrayBuffer: ArrayBuffer$1
1964         });
1965
1966         setSpecies(ARRAY_BUFFER$1);
1967
1968         var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
1969         var test = {};
1970
1971         test[TO_STRING_TAG$1] = 'z';
1972
1973         var toStringTagSupport = String(test) === '[object z]';
1974
1975         var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');
1976         // ES3 wrong here
1977         var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
1978
1979         // fallback for IE11 Script Access Denied error
1980         var tryGet = function (it, key) {
1981           try {
1982             return it[key];
1983           } catch (error) { /* empty */ }
1984         };
1985
1986         // getting tag from ES6+ `Object.prototype.toString`
1987         var classof = toStringTagSupport ? classofRaw : function (it) {
1988           var O, tag, result;
1989           return it === undefined ? 'Undefined' : it === null ? 'Null'
1990             // @@toStringTag case
1991             : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag
1992             // builtinTag case
1993             : CORRECT_ARGUMENTS ? classofRaw(O)
1994             // ES3 arguments fallback
1995             : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1996         };
1997
1998         var defineProperty$5 = objectDefineProperty.f;
1999
2000
2001
2002
2003
2004         var Int8Array$1 = global_1.Int8Array;
2005         var Int8ArrayPrototype = Int8Array$1 && Int8Array$1.prototype;
2006         var Uint8ClampedArray = global_1.Uint8ClampedArray;
2007         var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
2008         var TypedArray = Int8Array$1 && objectGetPrototypeOf(Int8Array$1);
2009         var TypedArrayPrototype = Int8ArrayPrototype && objectGetPrototypeOf(Int8ArrayPrototype);
2010         var ObjectPrototype$3 = Object.prototype;
2011         var isPrototypeOf = ObjectPrototype$3.isPrototypeOf;
2012
2013         var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
2014         var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
2015         // Fixing native typed arrays in Opera Presto crashes the browser, see #595
2016         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferNative && !!objectSetPrototypeOf && classof(global_1.opera) !== 'Opera';
2017         var TYPED_ARRAY_TAG_REQIRED = false;
2018         var NAME;
2019
2020         var TypedArrayConstructorsList = {
2021           Int8Array: 1,
2022           Uint8Array: 1,
2023           Uint8ClampedArray: 1,
2024           Int16Array: 2,
2025           Uint16Array: 2,
2026           Int32Array: 4,
2027           Uint32Array: 4,
2028           Float32Array: 4,
2029           Float64Array: 8
2030         };
2031
2032         var isView = function isView(it) {
2033           var klass = classof(it);
2034           return klass === 'DataView' || has(TypedArrayConstructorsList, klass);
2035         };
2036
2037         var isTypedArray = function (it) {
2038           return isObject(it) && has(TypedArrayConstructorsList, classof(it));
2039         };
2040
2041         var aTypedArray = function (it) {
2042           if (isTypedArray(it)) return it;
2043           throw TypeError('Target is not a typed array');
2044         };
2045
2046         var aTypedArrayConstructor = function (C) {
2047           if (objectSetPrototypeOf) {
2048             if (isPrototypeOf.call(TypedArray, C)) return C;
2049           } else for (var ARRAY in TypedArrayConstructorsList) if (has(TypedArrayConstructorsList, NAME)) {
2050             var TypedArrayConstructor = global_1[ARRAY];
2051             if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
2052               return C;
2053             }
2054           } throw TypeError('Target is not a typed array constructor');
2055         };
2056
2057         var exportTypedArrayMethod = function (KEY, property, forced) {
2058           if (!descriptors) return;
2059           if (forced) for (var ARRAY in TypedArrayConstructorsList) {
2060             var TypedArrayConstructor = global_1[ARRAY];
2061             if (TypedArrayConstructor && has(TypedArrayConstructor.prototype, KEY)) {
2062               delete TypedArrayConstructor.prototype[KEY];
2063             }
2064           }
2065           if (!TypedArrayPrototype[KEY] || forced) {
2066             redefine(TypedArrayPrototype, KEY, forced ? property
2067               : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property);
2068           }
2069         };
2070
2071         var exportTypedArrayStaticMethod = function (KEY, property, forced) {
2072           var ARRAY, TypedArrayConstructor;
2073           if (!descriptors) return;
2074           if (objectSetPrototypeOf) {
2075             if (forced) for (ARRAY in TypedArrayConstructorsList) {
2076               TypedArrayConstructor = global_1[ARRAY];
2077               if (TypedArrayConstructor && has(TypedArrayConstructor, KEY)) {
2078                 delete TypedArrayConstructor[KEY];
2079               }
2080             }
2081             if (!TypedArray[KEY] || forced) {
2082               // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
2083               try {
2084                 return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && Int8Array$1[KEY] || property);
2085               } catch (error) { /* empty */ }
2086             } else return;
2087           }
2088           for (ARRAY in TypedArrayConstructorsList) {
2089             TypedArrayConstructor = global_1[ARRAY];
2090             if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
2091               redefine(TypedArrayConstructor, KEY, property);
2092             }
2093           }
2094         };
2095
2096         for (NAME in TypedArrayConstructorsList) {
2097           if (!global_1[NAME]) NATIVE_ARRAY_BUFFER_VIEWS = false;
2098         }
2099
2100         // WebKit bug - typed arrays constructors prototype is Object.prototype
2101         if (!NATIVE_ARRAY_BUFFER_VIEWS || typeof TypedArray != 'function' || TypedArray === Function.prototype) {
2102           // eslint-disable-next-line no-shadow
2103           TypedArray = function TypedArray() {
2104             throw TypeError('Incorrect invocation');
2105           };
2106           if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
2107             if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME], TypedArray);
2108           }
2109         }
2110
2111         if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype$3) {
2112           TypedArrayPrototype = TypedArray.prototype;
2113           if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
2114             if (global_1[NAME]) objectSetPrototypeOf(global_1[NAME].prototype, TypedArrayPrototype);
2115           }
2116         }
2117
2118         // WebKit bug - one more object in Uint8ClampedArray prototype chain
2119         if (NATIVE_ARRAY_BUFFER_VIEWS && objectGetPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
2120           objectSetPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
2121         }
2122
2123         if (descriptors && !has(TypedArrayPrototype, TO_STRING_TAG$3)) {
2124           TYPED_ARRAY_TAG_REQIRED = true;
2125           defineProperty$5(TypedArrayPrototype, TO_STRING_TAG$3, { get: function () {
2126             return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
2127           } });
2128           for (NAME in TypedArrayConstructorsList) if (global_1[NAME]) {
2129             createNonEnumerableProperty(global_1[NAME], TYPED_ARRAY_TAG, NAME);
2130           }
2131         }
2132
2133         var arrayBufferViewCore = {
2134           NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
2135           TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG,
2136           aTypedArray: aTypedArray,
2137           aTypedArrayConstructor: aTypedArrayConstructor,
2138           exportTypedArrayMethod: exportTypedArrayMethod,
2139           exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,
2140           isView: isView,
2141           isTypedArray: isTypedArray,
2142           TypedArray: TypedArray,
2143           TypedArrayPrototype: TypedArrayPrototype
2144         };
2145
2146         var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
2147
2148         // `ArrayBuffer.isView` method
2149         // https://tc39.github.io/ecma262/#sec-arraybuffer.isview
2150         _export({ target: 'ArrayBuffer', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS$1 }, {
2151           isView: arrayBufferViewCore.isView
2152         });
2153
2154         var SPECIES$4 = wellKnownSymbol('species');
2155
2156         // `SpeciesConstructor` abstract operation
2157         // https://tc39.github.io/ecma262/#sec-speciesconstructor
2158         var speciesConstructor = function (O, defaultConstructor) {
2159           var C = anObject(O).constructor;
2160           var S;
2161           return C === undefined || (S = anObject(C)[SPECIES$4]) == undefined ? defaultConstructor : aFunction$1(S);
2162         };
2163
2164         var ArrayBuffer$2 = arrayBuffer.ArrayBuffer;
2165         var DataView$1 = arrayBuffer.DataView;
2166         var nativeArrayBufferSlice = ArrayBuffer$2.prototype.slice;
2167
2168         var INCORRECT_SLICE = fails(function () {
2169           return !new ArrayBuffer$2(2).slice(1, undefined).byteLength;
2170         });
2171
2172         // `ArrayBuffer.prototype.slice` method
2173         // https://tc39.github.io/ecma262/#sec-arraybuffer.prototype.slice
2174         _export({ target: 'ArrayBuffer', proto: true, unsafe: true, forced: INCORRECT_SLICE }, {
2175           slice: function slice(start, end) {
2176             if (nativeArrayBufferSlice !== undefined && end === undefined) {
2177               return nativeArrayBufferSlice.call(anObject(this), start); // FF fix
2178             }
2179             var length = anObject(this).byteLength;
2180             var first = toAbsoluteIndex(start, length);
2181             var fin = toAbsoluteIndex(end === undefined ? length : end, length);
2182             var result = new (speciesConstructor(this, ArrayBuffer$2))(toLength(fin - first));
2183             var viewSource = new DataView$1(this);
2184             var viewTarget = new DataView$1(result);
2185             var index = 0;
2186             while (first < fin) {
2187               viewTarget.setUint8(index++, viewSource.getUint8(first++));
2188             } return result;
2189           }
2190         });
2191
2192         // `DataView` constructor
2193         // https://tc39.github.io/ecma262/#sec-dataview-constructor
2194         _export({ global: true, forced: !arrayBufferNative }, {
2195           DataView: arrayBuffer.DataView
2196         });
2197
2198         var defineProperty$6 = objectDefineProperty.f;
2199
2200         var FunctionPrototype = Function.prototype;
2201         var FunctionPrototypeToString = FunctionPrototype.toString;
2202         var nameRE = /^\s*function ([^ (]*)/;
2203         var NAME$1 = 'name';
2204
2205         // Function instances `.name` property
2206         // https://tc39.github.io/ecma262/#sec-function-instances-name
2207         if (descriptors && !(NAME$1 in FunctionPrototype)) {
2208           defineProperty$6(FunctionPrototype, NAME$1, {
2209             configurable: true,
2210             get: function () {
2211               try {
2212                 return FunctionPrototypeToString.call(this).match(nameRE)[1];
2213               } catch (error) {
2214                 return '';
2215               }
2216             }
2217           });
2218         }
2219
2220         // `Object.create` method
2221         // https://tc39.github.io/ecma262/#sec-object.create
2222         _export({ target: 'Object', stat: true, sham: !descriptors }, {
2223           create: objectCreate
2224         });
2225
2226         var nativeGetOwnPropertyNames$2 = objectGetOwnPropertyNamesExternal.f;
2227
2228         var FAILS_ON_PRIMITIVES = fails(function () { return !Object.getOwnPropertyNames(1); });
2229
2230         // `Object.getOwnPropertyNames` method
2231         // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
2232         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
2233           getOwnPropertyNames: nativeGetOwnPropertyNames$2
2234         });
2235
2236         // `Object.prototype.toString` method implementation
2237         // https://tc39.github.io/ecma262/#sec-object.prototype.tostring
2238         var objectToString = toStringTagSupport ? {}.toString : function toString() {
2239           return '[object ' + classof(this) + ']';
2240         };
2241
2242         // `Object.prototype.toString` method
2243         // https://tc39.github.io/ecma262/#sec-object.prototype.tostring
2244         if (!toStringTagSupport) {
2245           redefine(Object.prototype, 'toString', objectToString, { unsafe: true });
2246         }
2247
2248         var nativePromiseConstructor = global_1.Promise;
2249
2250         var ITERATOR$2 = wellKnownSymbol('iterator');
2251         var ArrayPrototype$1 = Array.prototype;
2252
2253         // check on default Array iterator
2254         var isArrayIteratorMethod = function (it) {
2255           return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$2] === it);
2256         };
2257
2258         var ITERATOR$3 = wellKnownSymbol('iterator');
2259
2260         var getIteratorMethod = function (it) {
2261           if (it != undefined) return it[ITERATOR$3]
2262             || it['@@iterator']
2263             || iterators[classof(it)];
2264         };
2265
2266         var iteratorClose = function (iterator) {
2267           var returnMethod = iterator['return'];
2268           if (returnMethod !== undefined) {
2269             return anObject(returnMethod.call(iterator)).value;
2270           }
2271         };
2272
2273         var Result = function (stopped, result) {
2274           this.stopped = stopped;
2275           this.result = result;
2276         };
2277
2278         var iterate = function (iterable, unboundFunction, options) {
2279           var that = options && options.that;
2280           var AS_ENTRIES = !!(options && options.AS_ENTRIES);
2281           var IS_ITERATOR = !!(options && options.IS_ITERATOR);
2282           var INTERRUPTED = !!(options && options.INTERRUPTED);
2283           var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
2284           var iterator, iterFn, index, length, result, next, step;
2285
2286           var stop = function (condition) {
2287             if (iterator) iteratorClose(iterator);
2288             return new Result(true, condition);
2289           };
2290
2291           var callFn = function (value) {
2292             if (AS_ENTRIES) {
2293               anObject(value);
2294               return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
2295             } return INTERRUPTED ? fn(value, stop) : fn(value);
2296           };
2297
2298           if (IS_ITERATOR) {
2299             iterator = iterable;
2300           } else {
2301             iterFn = getIteratorMethod(iterable);
2302             if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
2303             // optimisation for array iterators
2304             if (isArrayIteratorMethod(iterFn)) {
2305               for (index = 0, length = toLength(iterable.length); length > index; index++) {
2306                 result = callFn(iterable[index]);
2307                 if (result && result instanceof Result) return result;
2308               } return new Result(false);
2309             }
2310             iterator = iterFn.call(iterable);
2311           }
2312
2313           next = iterator.next;
2314           while (!(step = next.call(iterator)).done) {
2315             try {
2316               result = callFn(step.value);
2317             } catch (error) {
2318               iteratorClose(iterator);
2319               throw error;
2320             }
2321             if (typeof result == 'object' && result && result instanceof Result) return result;
2322           } return new Result(false);
2323         };
2324
2325         var ITERATOR$4 = wellKnownSymbol('iterator');
2326         var SAFE_CLOSING = false;
2327
2328         try {
2329           var called = 0;
2330           var iteratorWithReturn = {
2331             next: function () {
2332               return { done: !!called++ };
2333             },
2334             'return': function () {
2335               SAFE_CLOSING = true;
2336             }
2337           };
2338           iteratorWithReturn[ITERATOR$4] = function () {
2339             return this;
2340           };
2341           // eslint-disable-next-line no-throw-literal
2342           Array.from(iteratorWithReturn, function () { throw 2; });
2343         } catch (error) { /* empty */ }
2344
2345         var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
2346           if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2347           var ITERATION_SUPPORT = false;
2348           try {
2349             var object = {};
2350             object[ITERATOR$4] = function () {
2351               return {
2352                 next: function () {
2353                   return { done: ITERATION_SUPPORT = true };
2354                 }
2355               };
2356             };
2357             exec(object);
2358           } catch (error) { /* empty */ }
2359           return ITERATION_SUPPORT;
2360         };
2361
2362         var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);
2363
2364         var engineIsNode = classofRaw(global_1.process) == 'process';
2365
2366         var location$1 = global_1.location;
2367         var set$2 = global_1.setImmediate;
2368         var clear = global_1.clearImmediate;
2369         var process$2 = global_1.process;
2370         var MessageChannel = global_1.MessageChannel;
2371         var Dispatch = global_1.Dispatch;
2372         var counter = 0;
2373         var queue = {};
2374         var ONREADYSTATECHANGE = 'onreadystatechange';
2375         var defer, channel, port;
2376
2377         var run = function (id) {
2378           // eslint-disable-next-line no-prototype-builtins
2379           if (queue.hasOwnProperty(id)) {
2380             var fn = queue[id];
2381             delete queue[id];
2382             fn();
2383           }
2384         };
2385
2386         var runner = function (id) {
2387           return function () {
2388             run(id);
2389           };
2390         };
2391
2392         var listener = function (event) {
2393           run(event.data);
2394         };
2395
2396         var post = function (id) {
2397           // old engines have not location.origin
2398           global_1.postMessage(id + '', location$1.protocol + '//' + location$1.host);
2399         };
2400
2401         // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
2402         if (!set$2 || !clear) {
2403           set$2 = function setImmediate(fn) {
2404             var args = [];
2405             var i = 1;
2406             while (arguments.length > i) args.push(arguments[i++]);
2407             queue[++counter] = function () {
2408               // eslint-disable-next-line no-new-func
2409               (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
2410             };
2411             defer(counter);
2412             return counter;
2413           };
2414           clear = function clearImmediate(id) {
2415             delete queue[id];
2416           };
2417           // Node.js 0.8-
2418           if (engineIsNode) {
2419             defer = function (id) {
2420               process$2.nextTick(runner(id));
2421             };
2422           // Sphere (JS game engine) Dispatch API
2423           } else if (Dispatch && Dispatch.now) {
2424             defer = function (id) {
2425               Dispatch.now(runner(id));
2426             };
2427           // Browsers with MessageChannel, includes WebWorkers
2428           // except iOS - https://github.com/zloirock/core-js/issues/624
2429           } else if (MessageChannel && !engineIsIos) {
2430             channel = new MessageChannel();
2431             port = channel.port2;
2432             channel.port1.onmessage = listener;
2433             defer = functionBindContext(port.postMessage, port, 1);
2434           // Browsers with postMessage, skip WebWorkers
2435           // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
2436           } else if (
2437             global_1.addEventListener &&
2438             typeof postMessage == 'function' &&
2439             !global_1.importScripts &&
2440             location$1 && location$1.protocol !== 'file:' &&
2441             !fails(post)
2442           ) {
2443             defer = post;
2444             global_1.addEventListener('message', listener, false);
2445           // IE8-
2446           } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
2447             defer = function (id) {
2448               html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
2449                 html.removeChild(this);
2450                 run(id);
2451               };
2452             };
2453           // Rest old browsers
2454           } else {
2455             defer = function (id) {
2456               setTimeout(runner(id), 0);
2457             };
2458           }
2459         }
2460
2461         var task = {
2462           set: set$2,
2463           clear: clear
2464         };
2465
2466         var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
2467         var macrotask = task.set;
2468
2469
2470
2471         var MutationObserver = global_1.MutationObserver || global_1.WebKitMutationObserver;
2472         var document$2 = global_1.document;
2473         var process$3 = global_1.process;
2474         var Promise$1 = global_1.Promise;
2475         // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
2476         var queueMicrotaskDescriptor = getOwnPropertyDescriptor$2(global_1, 'queueMicrotask');
2477         var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
2478
2479         var flush, head, last, notify, toggle, node, promise, then;
2480
2481         // modern engines have queueMicrotask method
2482         if (!queueMicrotask) {
2483           flush = function () {
2484             var parent, fn;
2485             if (engineIsNode && (parent = process$3.domain)) parent.exit();
2486             while (head) {
2487               fn = head.fn;
2488               head = head.next;
2489               try {
2490                 fn();
2491               } catch (error) {
2492                 if (head) notify();
2493                 else last = undefined;
2494                 throw error;
2495               }
2496             } last = undefined;
2497             if (parent) parent.enter();
2498           };
2499
2500           // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
2501           if (!engineIsIos && !engineIsNode && MutationObserver && document$2) {
2502             toggle = true;
2503             node = document$2.createTextNode('');
2504             new MutationObserver(flush).observe(node, { characterData: true });
2505             notify = function () {
2506               node.data = toggle = !toggle;
2507             };
2508           // environments with maybe non-completely correct, but existent Promise
2509           } else if (Promise$1 && Promise$1.resolve) {
2510             // Promise.resolve without an argument throws an error in LG WebOS 2
2511             promise = Promise$1.resolve(undefined);
2512             then = promise.then;
2513             notify = function () {
2514               then.call(promise, flush);
2515             };
2516           // Node.js without promises
2517           } else if (engineIsNode) {
2518             notify = function () {
2519               process$3.nextTick(flush);
2520             };
2521           // for other environments - macrotask based on:
2522           // - setImmediate
2523           // - MessageChannel
2524           // - window.postMessag
2525           // - onreadystatechange
2526           // - setTimeout
2527           } else {
2528             notify = function () {
2529               // strange IE + webpack dev server bug - use .call(global)
2530               macrotask.call(global_1, flush);
2531             };
2532           }
2533         }
2534
2535         var microtask = queueMicrotask || function (fn) {
2536           var task = { fn: fn, next: undefined };
2537           if (last) last.next = task;
2538           if (!head) {
2539             head = task;
2540             notify();
2541           } last = task;
2542         };
2543
2544         var PromiseCapability = function (C) {
2545           var resolve, reject;
2546           this.promise = new C(function ($$resolve, $$reject) {
2547             if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
2548             resolve = $$resolve;
2549             reject = $$reject;
2550           });
2551           this.resolve = aFunction$1(resolve);
2552           this.reject = aFunction$1(reject);
2553         };
2554
2555         // 25.4.1.5 NewPromiseCapability(C)
2556         var f$7 = function (C) {
2557           return new PromiseCapability(C);
2558         };
2559
2560         var newPromiseCapability = {
2561                 f: f$7
2562         };
2563
2564         var promiseResolve = function (C, x) {
2565           anObject(C);
2566           if (isObject(x) && x.constructor === C) return x;
2567           var promiseCapability = newPromiseCapability.f(C);
2568           var resolve = promiseCapability.resolve;
2569           resolve(x);
2570           return promiseCapability.promise;
2571         };
2572
2573         var hostReportErrors = function (a, b) {
2574           var console = global_1.console;
2575           if (console && console.error) {
2576             arguments.length === 1 ? console.error(a) : console.error(a, b);
2577           }
2578         };
2579
2580         var perform = function (exec) {
2581           try {
2582             return { error: false, value: exec() };
2583           } catch (error) {
2584             return { error: true, value: error };
2585           }
2586         };
2587
2588         var task$1 = task.set;
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600         var SPECIES$5 = wellKnownSymbol('species');
2601         var PROMISE = 'Promise';
2602         var getInternalState$3 = internalState.get;
2603         var setInternalState$3 = internalState.set;
2604         var getInternalPromiseState = internalState.getterFor(PROMISE);
2605         var PromiseConstructor = nativePromiseConstructor;
2606         var TypeError$1 = global_1.TypeError;
2607         var document$3 = global_1.document;
2608         var process$4 = global_1.process;
2609         var $fetch = getBuiltIn('fetch');
2610         var newPromiseCapability$1 = newPromiseCapability.f;
2611         var newGenericPromiseCapability = newPromiseCapability$1;
2612         var DISPATCH_EVENT = !!(document$3 && document$3.createEvent && global_1.dispatchEvent);
2613         var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
2614         var UNHANDLED_REJECTION = 'unhandledrejection';
2615         var REJECTION_HANDLED = 'rejectionhandled';
2616         var PENDING = 0;
2617         var FULFILLED = 1;
2618         var REJECTED = 2;
2619         var HANDLED = 1;
2620         var UNHANDLED = 2;
2621         var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
2622
2623         var FORCED = isForced_1(PROMISE, function () {
2624           var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
2625           if (!GLOBAL_CORE_JS_PROMISE) {
2626             // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
2627             // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
2628             // We can't detect it synchronously, so just check versions
2629             if (engineV8Version === 66) return true;
2630             // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
2631             if (!engineIsNode && !NATIVE_REJECTION_EVENT) return true;
2632           }
2633           // We can't use @@species feature detection in V8 since it causes
2634           // deoptimization and performance degradation
2635           // https://github.com/zloirock/core-js/issues/679
2636           if (engineV8Version >= 51 && /native code/.test(PromiseConstructor)) return false;
2637           // Detect correctness of subclassing with @@species support
2638           var promise = PromiseConstructor.resolve(1);
2639           var FakePromise = function (exec) {
2640             exec(function () { /* empty */ }, function () { /* empty */ });
2641           };
2642           var constructor = promise.constructor = {};
2643           constructor[SPECIES$5] = FakePromise;
2644           return !(promise.then(function () { /* empty */ }) instanceof FakePromise);
2645         });
2646
2647         var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) {
2648           PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
2649         });
2650
2651         // helpers
2652         var isThenable = function (it) {
2653           var then;
2654           return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
2655         };
2656
2657         var notify$1 = function (state, isReject) {
2658           if (state.notified) return;
2659           state.notified = true;
2660           var chain = state.reactions;
2661           microtask(function () {
2662             var value = state.value;
2663             var ok = state.state == FULFILLED;
2664             var index = 0;
2665             // variable length - can't use forEach
2666             while (chain.length > index) {
2667               var reaction = chain[index++];
2668               var handler = ok ? reaction.ok : reaction.fail;
2669               var resolve = reaction.resolve;
2670               var reject = reaction.reject;
2671               var domain = reaction.domain;
2672               var result, then, exited;
2673               try {
2674                 if (handler) {
2675                   if (!ok) {
2676                     if (state.rejection === UNHANDLED) onHandleUnhandled(state);
2677                     state.rejection = HANDLED;
2678                   }
2679                   if (handler === true) result = value;
2680                   else {
2681                     if (domain) domain.enter();
2682                     result = handler(value); // can throw
2683                     if (domain) {
2684                       domain.exit();
2685                       exited = true;
2686                     }
2687                   }
2688                   if (result === reaction.promise) {
2689                     reject(TypeError$1('Promise-chain cycle'));
2690                   } else if (then = isThenable(result)) {
2691                     then.call(result, resolve, reject);
2692                   } else resolve(result);
2693                 } else reject(value);
2694               } catch (error) {
2695                 if (domain && !exited) domain.exit();
2696                 reject(error);
2697               }
2698             }
2699             state.reactions = [];
2700             state.notified = false;
2701             if (isReject && !state.rejection) onUnhandled(state);
2702           });
2703         };
2704
2705         var dispatchEvent = function (name, promise, reason) {
2706           var event, handler;
2707           if (DISPATCH_EVENT) {
2708             event = document$3.createEvent('Event');
2709             event.promise = promise;
2710             event.reason = reason;
2711             event.initEvent(name, false, true);
2712             global_1.dispatchEvent(event);
2713           } else event = { promise: promise, reason: reason };
2714           if (!NATIVE_REJECTION_EVENT && (handler = global_1['on' + name])) handler(event);
2715           else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
2716         };
2717
2718         var onUnhandled = function (state) {
2719           task$1.call(global_1, function () {
2720             var promise = state.facade;
2721             var value = state.value;
2722             var IS_UNHANDLED = isUnhandled(state);
2723             var result;
2724             if (IS_UNHANDLED) {
2725               result = perform(function () {
2726                 if (engineIsNode) {
2727                   process$4.emit('unhandledRejection', value, promise);
2728                 } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
2729               });
2730               // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
2731               state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;
2732               if (result.error) throw result.value;
2733             }
2734           });
2735         };
2736
2737         var isUnhandled = function (state) {
2738           return state.rejection !== HANDLED && !state.parent;
2739         };
2740
2741         var onHandleUnhandled = function (state) {
2742           task$1.call(global_1, function () {
2743             var promise = state.facade;
2744             if (engineIsNode) {
2745               process$4.emit('rejectionHandled', promise);
2746             } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
2747           });
2748         };
2749
2750         var bind = function (fn, state, unwrap) {
2751           return function (value) {
2752             fn(state, value, unwrap);
2753           };
2754         };
2755
2756         var internalReject = function (state, value, unwrap) {
2757           if (state.done) return;
2758           state.done = true;
2759           if (unwrap) state = unwrap;
2760           state.value = value;
2761           state.state = REJECTED;
2762           notify$1(state, true);
2763         };
2764
2765         var internalResolve = function (state, value, unwrap) {
2766           if (state.done) return;
2767           state.done = true;
2768           if (unwrap) state = unwrap;
2769           try {
2770             if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
2771             var then = isThenable(value);
2772             if (then) {
2773               microtask(function () {
2774                 var wrapper = { done: false };
2775                 try {
2776                   then.call(value,
2777                     bind(internalResolve, wrapper, state),
2778                     bind(internalReject, wrapper, state)
2779                   );
2780                 } catch (error) {
2781                   internalReject(wrapper, error, state);
2782                 }
2783               });
2784             } else {
2785               state.value = value;
2786               state.state = FULFILLED;
2787               notify$1(state, false);
2788             }
2789           } catch (error) {
2790             internalReject({ done: false }, error, state);
2791           }
2792         };
2793
2794         // constructor polyfill
2795         if (FORCED) {
2796           // 25.4.3.1 Promise(executor)
2797           PromiseConstructor = function Promise(executor) {
2798             anInstance(this, PromiseConstructor, PROMISE);
2799             aFunction$1(executor);
2800             Internal.call(this);
2801             var state = getInternalState$3(this);
2802             try {
2803               executor(bind(internalResolve, state), bind(internalReject, state));
2804             } catch (error) {
2805               internalReject(state, error);
2806             }
2807           };
2808           // eslint-disable-next-line no-unused-vars
2809           Internal = function Promise(executor) {
2810             setInternalState$3(this, {
2811               type: PROMISE,
2812               done: false,
2813               notified: false,
2814               parent: false,
2815               reactions: [],
2816               rejection: false,
2817               state: PENDING,
2818               value: undefined
2819             });
2820           };
2821           Internal.prototype = redefineAll(PromiseConstructor.prototype, {
2822             // `Promise.prototype.then` method
2823             // https://tc39.github.io/ecma262/#sec-promise.prototype.then
2824             then: function then(onFulfilled, onRejected) {
2825               var state = getInternalPromiseState(this);
2826               var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
2827               reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
2828               reaction.fail = typeof onRejected == 'function' && onRejected;
2829               reaction.domain = engineIsNode ? process$4.domain : undefined;
2830               state.parent = true;
2831               state.reactions.push(reaction);
2832               if (state.state != PENDING) notify$1(state, false);
2833               return reaction.promise;
2834             },
2835             // `Promise.prototype.catch` method
2836             // https://tc39.github.io/ecma262/#sec-promise.prototype.catch
2837             'catch': function (onRejected) {
2838               return this.then(undefined, onRejected);
2839             }
2840           });
2841           OwnPromiseCapability = function () {
2842             var promise = new Internal();
2843             var state = getInternalState$3(promise);
2844             this.promise = promise;
2845             this.resolve = bind(internalResolve, state);
2846             this.reject = bind(internalReject, state);
2847           };
2848           newPromiseCapability.f = newPromiseCapability$1 = function (C) {
2849             return C === PromiseConstructor || C === PromiseWrapper
2850               ? new OwnPromiseCapability(C)
2851               : newGenericPromiseCapability(C);
2852           };
2853
2854           if ( typeof nativePromiseConstructor == 'function') {
2855             nativeThen = nativePromiseConstructor.prototype.then;
2856
2857             // wrap native Promise#then for native async functions
2858             redefine(nativePromiseConstructor.prototype, 'then', function then(onFulfilled, onRejected) {
2859               var that = this;
2860               return new PromiseConstructor(function (resolve, reject) {
2861                 nativeThen.call(that, resolve, reject);
2862               }).then(onFulfilled, onRejected);
2863             // https://github.com/zloirock/core-js/issues/640
2864             }, { unsafe: true });
2865
2866             // wrap fetch result
2867             if (typeof $fetch == 'function') _export({ global: true, enumerable: true, forced: true }, {
2868               // eslint-disable-next-line no-unused-vars
2869               fetch: function fetch(input /* , init */) {
2870                 return promiseResolve(PromiseConstructor, $fetch.apply(global_1, arguments));
2871               }
2872             });
2873           }
2874         }
2875
2876         _export({ global: true, wrap: true, forced: FORCED }, {
2877           Promise: PromiseConstructor
2878         });
2879
2880         setToStringTag(PromiseConstructor, PROMISE, false);
2881         setSpecies(PROMISE);
2882
2883         PromiseWrapper = getBuiltIn(PROMISE);
2884
2885         // statics
2886         _export({ target: PROMISE, stat: true, forced: FORCED }, {
2887           // `Promise.reject` method
2888           // https://tc39.github.io/ecma262/#sec-promise.reject
2889           reject: function reject(r) {
2890             var capability = newPromiseCapability$1(this);
2891             capability.reject.call(undefined, r);
2892             return capability.promise;
2893           }
2894         });
2895
2896         _export({ target: PROMISE, stat: true, forced:  FORCED }, {
2897           // `Promise.resolve` method
2898           // https://tc39.github.io/ecma262/#sec-promise.resolve
2899           resolve: function resolve(x) {
2900             return promiseResolve( this, x);
2901           }
2902         });
2903
2904         _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION }, {
2905           // `Promise.all` method
2906           // https://tc39.github.io/ecma262/#sec-promise.all
2907           all: function all(iterable) {
2908             var C = this;
2909             var capability = newPromiseCapability$1(C);
2910             var resolve = capability.resolve;
2911             var reject = capability.reject;
2912             var result = perform(function () {
2913               var $promiseResolve = aFunction$1(C.resolve);
2914               var values = [];
2915               var counter = 0;
2916               var remaining = 1;
2917               iterate(iterable, function (promise) {
2918                 var index = counter++;
2919                 var alreadyCalled = false;
2920                 values.push(undefined);
2921                 remaining++;
2922                 $promiseResolve.call(C, promise).then(function (value) {
2923                   if (alreadyCalled) return;
2924                   alreadyCalled = true;
2925                   values[index] = value;
2926                   --remaining || resolve(values);
2927                 }, reject);
2928               });
2929               --remaining || resolve(values);
2930             });
2931             if (result.error) reject(result.value);
2932             return capability.promise;
2933           },
2934           // `Promise.race` method
2935           // https://tc39.github.io/ecma262/#sec-promise.race
2936           race: function race(iterable) {
2937             var C = this;
2938             var capability = newPromiseCapability$1(C);
2939             var reject = capability.reject;
2940             var result = perform(function () {
2941               var $promiseResolve = aFunction$1(C.resolve);
2942               iterate(iterable, function (promise) {
2943                 $promiseResolve.call(C, promise).then(capability.resolve, reject);
2944               });
2945             });
2946             if (result.error) reject(result.value);
2947             return capability.promise;
2948           }
2949         });
2950
2951         // `RegExp.prototype.flags` getter implementation
2952         // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
2953         var regexpFlags = function () {
2954           var that = anObject(this);
2955           var result = '';
2956           if (that.global) result += 'g';
2957           if (that.ignoreCase) result += 'i';
2958           if (that.multiline) result += 'm';
2959           if (that.dotAll) result += 's';
2960           if (that.unicode) result += 'u';
2961           if (that.sticky) result += 'y';
2962           return result;
2963         };
2964
2965         // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
2966         // so we use an intermediate function.
2967         function RE(s, f) {
2968           return RegExp(s, f);
2969         }
2970
2971         var UNSUPPORTED_Y = fails(function () {
2972           // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError
2973           var re = RE('a', 'y');
2974           re.lastIndex = 2;
2975           return re.exec('abcd') != null;
2976         });
2977
2978         var BROKEN_CARET = fails(function () {
2979           // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
2980           var re = RE('^r', 'gy');
2981           re.lastIndex = 2;
2982           return re.exec('str') != null;
2983         });
2984
2985         var regexpStickyHelpers = {
2986                 UNSUPPORTED_Y: UNSUPPORTED_Y,
2987                 BROKEN_CARET: BROKEN_CARET
2988         };
2989
2990         var nativeExec = RegExp.prototype.exec;
2991         // This always refers to the native implementation, because the
2992         // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
2993         // which loads this file before patching the method.
2994         var nativeReplace = String.prototype.replace;
2995
2996         var patchedExec = nativeExec;
2997
2998         var UPDATES_LAST_INDEX_WRONG = (function () {
2999           var re1 = /a/;
3000           var re2 = /b*/g;
3001           nativeExec.call(re1, 'a');
3002           nativeExec.call(re2, 'a');
3003           return re1.lastIndex !== 0 || re2.lastIndex !== 0;
3004         })();
3005
3006         var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET;
3007
3008         // nonparticipating capturing group, copied from es5-shim's String#split patch.
3009         var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
3010
3011         var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1;
3012
3013         if (PATCH) {
3014           patchedExec = function exec(str) {
3015             var re = this;
3016             var lastIndex, reCopy, match, i;
3017             var sticky = UNSUPPORTED_Y$1 && re.sticky;
3018             var flags = regexpFlags.call(re);
3019             var source = re.source;
3020             var charsAdded = 0;
3021             var strCopy = str;
3022
3023             if (sticky) {
3024               flags = flags.replace('y', '');
3025               if (flags.indexOf('g') === -1) {
3026                 flags += 'g';
3027               }
3028
3029               strCopy = String(str).slice(re.lastIndex);
3030               // Support anchored sticky behavior.
3031               if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
3032                 source = '(?: ' + source + ')';
3033                 strCopy = ' ' + strCopy;
3034                 charsAdded++;
3035               }
3036               // ^(? + rx + ) is needed, in combination with some str slicing, to
3037               // simulate the 'y' flag.
3038               reCopy = new RegExp('^(?:' + source + ')', flags);
3039             }
3040
3041             if (NPCG_INCLUDED) {
3042               reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
3043             }
3044             if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
3045
3046             match = nativeExec.call(sticky ? reCopy : re, strCopy);
3047
3048             if (sticky) {
3049               if (match) {
3050                 match.input = match.input.slice(charsAdded);
3051                 match[0] = match[0].slice(charsAdded);
3052                 match.index = re.lastIndex;
3053                 re.lastIndex += match[0].length;
3054               } else re.lastIndex = 0;
3055             } else if (UPDATES_LAST_INDEX_WRONG && match) {
3056               re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
3057             }
3058             if (NPCG_INCLUDED && match && match.length > 1) {
3059               // Fix browsers whose `exec` methods don't consistently return `undefined`
3060               // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
3061               nativeReplace.call(match[0], reCopy, function () {
3062                 for (i = 1; i < arguments.length - 2; i++) {
3063                   if (arguments[i] === undefined) match[i] = undefined;
3064                 }
3065               });
3066             }
3067
3068             return match;
3069           };
3070         }
3071
3072         var regexpExec = patchedExec;
3073
3074         _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {
3075           exec: regexpExec
3076         });
3077
3078         var TO_STRING$1 = 'toString';
3079         var RegExpPrototype = RegExp.prototype;
3080         var nativeToString = RegExpPrototype[TO_STRING$1];
3081
3082         var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
3083         // FF44- RegExp#toString has a wrong name
3084         var INCORRECT_NAME = nativeToString.name != TO_STRING$1;
3085
3086         // `RegExp.prototype.toString` method
3087         // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring
3088         if (NOT_GENERIC || INCORRECT_NAME) {
3089           redefine(RegExp.prototype, TO_STRING$1, function toString() {
3090             var R = anObject(this);
3091             var p = String(R.source);
3092             var rf = R.flags;
3093             var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf);
3094             return '/' + p + '/' + f;
3095           }, { unsafe: true });
3096         }
3097
3098         // `String.prototype.{ codePointAt, at }` methods implementation
3099         var createMethod$2 = function (CONVERT_TO_STRING) {
3100           return function ($this, pos) {
3101             var S = String(requireObjectCoercible($this));
3102             var position = toInteger(pos);
3103             var size = S.length;
3104             var first, second;
3105             if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
3106             first = S.charCodeAt(position);
3107             return first < 0xD800 || first > 0xDBFF || position + 1 === size
3108               || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
3109                 ? CONVERT_TO_STRING ? S.charAt(position) : first
3110                 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
3111           };
3112         };
3113
3114         var stringMultibyte = {
3115           // `String.prototype.codePointAt` method
3116           // https://tc39.github.io/ecma262/#sec-string.prototype.codepointat
3117           codeAt: createMethod$2(false),
3118           // `String.prototype.at` method
3119           // https://github.com/mathiasbynens/String.prototype.at
3120           charAt: createMethod$2(true)
3121         };
3122
3123         var charAt = stringMultibyte.charAt;
3124
3125
3126
3127         var STRING_ITERATOR = 'String Iterator';
3128         var setInternalState$4 = internalState.set;
3129         var getInternalState$4 = internalState.getterFor(STRING_ITERATOR);
3130
3131         // `String.prototype[@@iterator]` method
3132         // https://tc39.github.io/ecma262/#sec-string.prototype-@@iterator
3133         defineIterator(String, 'String', function (iterated) {
3134           setInternalState$4(this, {
3135             type: STRING_ITERATOR,
3136             string: String(iterated),
3137             index: 0
3138           });
3139         // `%StringIteratorPrototype%.next` method
3140         // https://tc39.github.io/ecma262/#sec-%stringiteratorprototype%.next
3141         }, function next() {
3142           var state = getInternalState$4(this);
3143           var string = state.string;
3144           var index = state.index;
3145           var point;
3146           if (index >= string.length) return { value: undefined, done: true };
3147           point = charAt(string, index);
3148           state.index += point.length;
3149           return { value: point, done: false };
3150         });
3151
3152         // TODO: Remove from `core-js@4` since it's moved to entry points
3153
3154
3155
3156
3157
3158
3159
3160         var SPECIES$6 = wellKnownSymbol('species');
3161
3162         var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
3163           // #replace needs built-in support for named groups.
3164           // #match works fine because it just return the exec results, even if it has
3165           // a "grops" property.
3166           var re = /./;
3167           re.exec = function () {
3168             var result = [];
3169             result.groups = { a: '7' };
3170             return result;
3171           };
3172           return ''.replace(re, '$<a>') !== '7';
3173         });
3174
3175         // IE <= 11 replaces $0 with the whole match, as if it was $&
3176         // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
3177         var REPLACE_KEEPS_$0 = (function () {
3178           return 'a'.replace(/./, '$0') === '$0';
3179         })();
3180
3181         var REPLACE = wellKnownSymbol('replace');
3182         // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
3183         var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
3184           if (/./[REPLACE]) {
3185             return /./[REPLACE]('a', '$0') === '';
3186           }
3187           return false;
3188         })();
3189
3190         // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
3191         // Weex JS has frozen built-in prototypes, so use try / catch wrapper
3192         var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
3193           var re = /(?:)/;
3194           var originalExec = re.exec;
3195           re.exec = function () { return originalExec.apply(this, arguments); };
3196           var result = 'ab'.split(re);
3197           return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
3198         });
3199
3200         var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
3201           var SYMBOL = wellKnownSymbol(KEY);
3202
3203           var DELEGATES_TO_SYMBOL = !fails(function () {
3204             // String methods call symbol-named RegEp methods
3205             var O = {};
3206             O[SYMBOL] = function () { return 7; };
3207             return ''[KEY](O) != 7;
3208           });
3209
3210           var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
3211             // Symbol-named RegExp methods call .exec
3212             var execCalled = false;
3213             var re = /a/;
3214
3215             if (KEY === 'split') {
3216               // We can't use real regex here since it causes deoptimization
3217               // and serious performance degradation in V8
3218               // https://github.com/zloirock/core-js/issues/306
3219               re = {};
3220               // RegExp[@@split] doesn't call the regex's exec method, but first creates
3221               // a new one. We need to return the patched regex when creating the new one.
3222               re.constructor = {};
3223               re.constructor[SPECIES$6] = function () { return re; };
3224               re.flags = '';
3225               re[SYMBOL] = /./[SYMBOL];
3226             }
3227
3228             re.exec = function () { execCalled = true; return null; };
3229
3230             re[SYMBOL]('');
3231             return !execCalled;
3232           });
3233
3234           if (
3235             !DELEGATES_TO_SYMBOL ||
3236             !DELEGATES_TO_EXEC ||
3237             (KEY === 'replace' && !(
3238               REPLACE_SUPPORTS_NAMED_GROUPS &&
3239               REPLACE_KEEPS_$0 &&
3240               !REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
3241             )) ||
3242             (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
3243           ) {
3244             var nativeRegExpMethod = /./[SYMBOL];
3245             var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
3246               if (regexp.exec === regexpExec) {
3247                 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
3248                   // The native String method already delegates to @@method (this
3249                   // polyfilled function), leasing to infinite recursion.
3250                   // We avoid it by directly calling the native @@method method.
3251                   return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
3252                 }
3253                 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
3254               }
3255               return { done: false };
3256             }, {
3257               REPLACE_KEEPS_$0: REPLACE_KEEPS_$0,
3258               REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
3259             });
3260             var stringMethod = methods[0];
3261             var regexMethod = methods[1];
3262
3263             redefine(String.prototype, KEY, stringMethod);
3264             redefine(RegExp.prototype, SYMBOL, length == 2
3265               // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
3266               // 21.2.5.11 RegExp.prototype[@@split](string, limit)
3267               ? function (string, arg) { return regexMethod.call(string, this, arg); }
3268               // 21.2.5.6 RegExp.prototype[@@match](string)
3269               // 21.2.5.9 RegExp.prototype[@@search](string)
3270               : function (string) { return regexMethod.call(string, this); }
3271             );
3272           }
3273
3274           if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
3275         };
3276
3277         var charAt$1 = stringMultibyte.charAt;
3278
3279         // `AdvanceStringIndex` abstract operation
3280         // https://tc39.github.io/ecma262/#sec-advancestringindex
3281         var advanceStringIndex = function (S, index, unicode) {
3282           return index + (unicode ? charAt$1(S, index).length : 1);
3283         };
3284
3285         // `RegExpExec` abstract operation
3286         // https://tc39.github.io/ecma262/#sec-regexpexec
3287         var regexpExecAbstract = function (R, S) {
3288           var exec = R.exec;
3289           if (typeof exec === 'function') {
3290             var result = exec.call(R, S);
3291             if (typeof result !== 'object') {
3292               throw TypeError('RegExp exec method returned something other than an Object or null');
3293             }
3294             return result;
3295           }
3296
3297           if (classofRaw(R) !== 'RegExp') {
3298             throw TypeError('RegExp#exec called on incompatible receiver');
3299           }
3300
3301           return regexpExec.call(R, S);
3302         };
3303
3304         var max$2 = Math.max;
3305         var min$2 = Math.min;
3306         var floor$2 = Math.floor;
3307         var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d\d?|<[^>]*>)/g;
3308         var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d\d?)/g;
3309
3310         var maybeToString = function (it) {
3311           return it === undefined ? it : String(it);
3312         };
3313
3314         // @@replace logic
3315         fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative, reason) {
3316           var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE;
3317           var REPLACE_KEEPS_$0 = reason.REPLACE_KEEPS_$0;
3318           var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
3319
3320           return [
3321             // `String.prototype.replace` method
3322             // https://tc39.github.io/ecma262/#sec-string.prototype.replace
3323             function replace(searchValue, replaceValue) {
3324               var O = requireObjectCoercible(this);
3325               var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
3326               return replacer !== undefined
3327                 ? replacer.call(searchValue, O, replaceValue)
3328                 : nativeReplace.call(String(O), searchValue, replaceValue);
3329             },
3330             // `RegExp.prototype[@@replace]` method
3331             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
3332             function (regexp, replaceValue) {
3333               if (
3334                 (!REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && REPLACE_KEEPS_$0) ||
3335                 (typeof replaceValue === 'string' && replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1)
3336               ) {
3337                 var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
3338                 if (res.done) return res.value;
3339               }
3340
3341               var rx = anObject(regexp);
3342               var S = String(this);
3343
3344               var functionalReplace = typeof replaceValue === 'function';
3345               if (!functionalReplace) replaceValue = String(replaceValue);
3346
3347               var global = rx.global;
3348               if (global) {
3349                 var fullUnicode = rx.unicode;
3350                 rx.lastIndex = 0;
3351               }
3352               var results = [];
3353               while (true) {
3354                 var result = regexpExecAbstract(rx, S);
3355                 if (result === null) break;
3356
3357                 results.push(result);
3358                 if (!global) break;
3359
3360                 var matchStr = String(result[0]);
3361                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
3362               }
3363
3364               var accumulatedResult = '';
3365               var nextSourcePosition = 0;
3366               for (var i = 0; i < results.length; i++) {
3367                 result = results[i];
3368
3369                 var matched = String(result[0]);
3370                 var position = max$2(min$2(toInteger(result.index), S.length), 0);
3371                 var captures = [];
3372                 // NOTE: This is equivalent to
3373                 //   captures = result.slice(1).map(maybeToString)
3374                 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
3375                 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
3376                 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
3377                 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
3378                 var namedCaptures = result.groups;
3379                 if (functionalReplace) {
3380                   var replacerArgs = [matched].concat(captures, position, S);
3381                   if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
3382                   var replacement = String(replaceValue.apply(undefined, replacerArgs));
3383                 } else {
3384                   replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
3385                 }
3386                 if (position >= nextSourcePosition) {
3387                   accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
3388                   nextSourcePosition = position + matched.length;
3389                 }
3390               }
3391               return accumulatedResult + S.slice(nextSourcePosition);
3392             }
3393           ];
3394
3395           // https://tc39.github.io/ecma262/#sec-getsubstitution
3396           function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
3397             var tailPos = position + matched.length;
3398             var m = captures.length;
3399             var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
3400             if (namedCaptures !== undefined) {
3401               namedCaptures = toObject(namedCaptures);
3402               symbols = SUBSTITUTION_SYMBOLS;
3403             }
3404             return nativeReplace.call(replacement, symbols, function (match, ch) {
3405               var capture;
3406               switch (ch.charAt(0)) {
3407                 case '$': return '$';
3408                 case '&': return matched;
3409                 case '`': return str.slice(0, position);
3410                 case "'": return str.slice(tailPos);
3411                 case '<':
3412                   capture = namedCaptures[ch.slice(1, -1)];
3413                   break;
3414                 default: // \d\d?
3415                   var n = +ch;
3416                   if (n === 0) return match;
3417                   if (n > m) {
3418                     var f = floor$2(n / 10);
3419                     if (f === 0) return match;
3420                     if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
3421                     return match;
3422                   }
3423                   capture = captures[n - 1];
3424               }
3425               return capture === undefined ? '' : capture;
3426             });
3427           }
3428         });
3429
3430         var MATCH = wellKnownSymbol('match');
3431
3432         // `IsRegExp` abstract operation
3433         // https://tc39.github.io/ecma262/#sec-isregexp
3434         var isRegexp = function (it) {
3435           var isRegExp;
3436           return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
3437         };
3438
3439         var arrayPush = [].push;
3440         var min$3 = Math.min;
3441         var MAX_UINT32 = 0xFFFFFFFF;
3442
3443         // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError
3444         var SUPPORTS_Y = !fails(function () { return !RegExp(MAX_UINT32, 'y'); });
3445
3446         // @@split logic
3447         fixRegexpWellKnownSymbolLogic('split', 2, function (SPLIT, nativeSplit, maybeCallNative) {
3448           var internalSplit;
3449           if (
3450             'abbc'.split(/(b)*/)[1] == 'c' ||
3451             'test'.split(/(?:)/, -1).length != 4 ||
3452             'ab'.split(/(?:ab)*/).length != 2 ||
3453             '.'.split(/(.?)(.?)/).length != 4 ||
3454             '.'.split(/()()/).length > 1 ||
3455             ''.split(/.?/).length
3456           ) {
3457             // based on es5-shim implementation, need to rework it
3458             internalSplit = function (separator, limit) {
3459               var string = String(requireObjectCoercible(this));
3460               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
3461               if (lim === 0) return [];
3462               if (separator === undefined) return [string];
3463               // If `separator` is not a regex, use native split
3464               if (!isRegexp(separator)) {
3465                 return nativeSplit.call(string, separator, lim);
3466               }
3467               var output = [];
3468               var flags = (separator.ignoreCase ? 'i' : '') +
3469                           (separator.multiline ? 'm' : '') +
3470                           (separator.unicode ? 'u' : '') +
3471                           (separator.sticky ? 'y' : '');
3472               var lastLastIndex = 0;
3473               // Make `global` and avoid `lastIndex` issues by working with a copy
3474               var separatorCopy = new RegExp(separator.source, flags + 'g');
3475               var match, lastIndex, lastLength;
3476               while (match = regexpExec.call(separatorCopy, string)) {
3477                 lastIndex = separatorCopy.lastIndex;
3478                 if (lastIndex > lastLastIndex) {
3479                   output.push(string.slice(lastLastIndex, match.index));
3480                   if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
3481                   lastLength = match[0].length;
3482                   lastLastIndex = lastIndex;
3483                   if (output.length >= lim) break;
3484                 }
3485                 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
3486               }
3487               if (lastLastIndex === string.length) {
3488                 if (lastLength || !separatorCopy.test('')) output.push('');
3489               } else output.push(string.slice(lastLastIndex));
3490               return output.length > lim ? output.slice(0, lim) : output;
3491             };
3492           // Chakra, V8
3493           } else if ('0'.split(undefined, 0).length) {
3494             internalSplit = function (separator, limit) {
3495               return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
3496             };
3497           } else internalSplit = nativeSplit;
3498
3499           return [
3500             // `String.prototype.split` method
3501             // https://tc39.github.io/ecma262/#sec-string.prototype.split
3502             function split(separator, limit) {
3503               var O = requireObjectCoercible(this);
3504               var splitter = separator == undefined ? undefined : separator[SPLIT];
3505               return splitter !== undefined
3506                 ? splitter.call(separator, O, limit)
3507                 : internalSplit.call(String(O), separator, limit);
3508             },
3509             // `RegExp.prototype[@@split]` method
3510             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split
3511             //
3512             // NOTE: This cannot be properly polyfilled in engines that don't support
3513             // the 'y' flag.
3514             function (regexp, limit) {
3515               var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== nativeSplit);
3516               if (res.done) return res.value;
3517
3518               var rx = anObject(regexp);
3519               var S = String(this);
3520               var C = speciesConstructor(rx, RegExp);
3521
3522               var unicodeMatching = rx.unicode;
3523               var flags = (rx.ignoreCase ? 'i' : '') +
3524                           (rx.multiline ? 'm' : '') +
3525                           (rx.unicode ? 'u' : '') +
3526                           (SUPPORTS_Y ? 'y' : 'g');
3527
3528               // ^(? + rx + ) is needed, in combination with some S slicing, to
3529               // simulate the 'y' flag.
3530               var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags);
3531               var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
3532               if (lim === 0) return [];
3533               if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
3534               var p = 0;
3535               var q = 0;
3536               var A = [];
3537               while (q < S.length) {
3538                 splitter.lastIndex = SUPPORTS_Y ? q : 0;
3539                 var z = regexpExecAbstract(splitter, SUPPORTS_Y ? S : S.slice(q));
3540                 var e;
3541                 if (
3542                   z === null ||
3543                   (e = min$3(toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p
3544                 ) {
3545                   q = advanceStringIndex(S, q, unicodeMatching);
3546                 } else {
3547                   A.push(S.slice(p, q));
3548                   if (A.length === lim) return A;
3549                   for (var i = 1; i <= z.length - 1; i++) {
3550                     A.push(z[i]);
3551                     if (A.length === lim) return A;
3552                   }
3553                   q = p = e;
3554                 }
3555               }
3556               A.push(S.slice(p));
3557               return A;
3558             }
3559           ];
3560         }, !SUPPORTS_Y);
3561
3562         // a string of all valid unicode whitespaces
3563         // eslint-disable-next-line max-len
3564         var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
3565
3566         var whitespace = '[' + whitespaces + ']';
3567         var ltrim = RegExp('^' + whitespace + whitespace + '*');
3568         var rtrim = RegExp(whitespace + whitespace + '*$');
3569
3570         // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
3571         var createMethod$3 = function (TYPE) {
3572           return function ($this) {
3573             var string = String(requireObjectCoercible($this));
3574             if (TYPE & 1) string = string.replace(ltrim, '');
3575             if (TYPE & 2) string = string.replace(rtrim, '');
3576             return string;
3577           };
3578         };
3579
3580         var stringTrim = {
3581           // `String.prototype.{ trimLeft, trimStart }` methods
3582           // https://tc39.github.io/ecma262/#sec-string.prototype.trimstart
3583           start: createMethod$3(1),
3584           // `String.prototype.{ trimRight, trimEnd }` methods
3585           // https://tc39.github.io/ecma262/#sec-string.prototype.trimend
3586           end: createMethod$3(2),
3587           // `String.prototype.trim` method
3588           // https://tc39.github.io/ecma262/#sec-string.prototype.trim
3589           trim: createMethod$3(3)
3590         };
3591
3592         var non = '\u200B\u0085\u180E';
3593
3594         // check that a method works with the correct list
3595         // of whitespaces and has a correct name
3596         var stringTrimForced = function (METHOD_NAME) {
3597           return fails(function () {
3598             return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
3599           });
3600         };
3601
3602         var $trim = stringTrim.trim;
3603
3604
3605         // `String.prototype.trim` method
3606         // https://tc39.github.io/ecma262/#sec-string.prototype.trim
3607         _export({ target: 'String', proto: true, forced: stringTrimForced('trim') }, {
3608           trim: function trim() {
3609             return $trim(this);
3610           }
3611         });
3612
3613         /* eslint-disable no-new */
3614
3615
3616
3617         var NATIVE_ARRAY_BUFFER_VIEWS$2 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3618
3619         var ArrayBuffer$3 = global_1.ArrayBuffer;
3620         var Int8Array$2 = global_1.Int8Array;
3621
3622         var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS$2 || !fails(function () {
3623           Int8Array$2(1);
3624         }) || !fails(function () {
3625           new Int8Array$2(-1);
3626         }) || !checkCorrectnessOfIteration(function (iterable) {
3627           new Int8Array$2();
3628           new Int8Array$2(null);
3629           new Int8Array$2(1.5);
3630           new Int8Array$2(iterable);
3631         }, true) || fails(function () {
3632           // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
3633           return new Int8Array$2(new ArrayBuffer$3(2), 1, undefined).length !== 1;
3634         });
3635
3636         var toPositiveInteger = function (it) {
3637           var result = toInteger(it);
3638           if (result < 0) throw RangeError("The argument can't be less than 0");
3639           return result;
3640         };
3641
3642         var toOffset = function (it, BYTES) {
3643           var offset = toPositiveInteger(it);
3644           if (offset % BYTES) throw RangeError('Wrong offset');
3645           return offset;
3646         };
3647
3648         var aTypedArrayConstructor$1 = arrayBufferViewCore.aTypedArrayConstructor;
3649
3650         var typedArrayFrom = function from(source /* , mapfn, thisArg */) {
3651           var O = toObject(source);
3652           var argumentsLength = arguments.length;
3653           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
3654           var mapping = mapfn !== undefined;
3655           var iteratorMethod = getIteratorMethod(O);
3656           var i, length, result, step, iterator, next;
3657           if (iteratorMethod != undefined && !isArrayIteratorMethod(iteratorMethod)) {
3658             iterator = iteratorMethod.call(O);
3659             next = iterator.next;
3660             O = [];
3661             while (!(step = next.call(iterator)).done) {
3662               O.push(step.value);
3663             }
3664           }
3665           if (mapping && argumentsLength > 2) {
3666             mapfn = functionBindContext(mapfn, arguments[2], 2);
3667           }
3668           length = toLength(O.length);
3669           result = new (aTypedArrayConstructor$1(this))(length);
3670           for (i = 0; length > i; i++) {
3671             result[i] = mapping ? mapfn(O[i], i) : O[i];
3672           }
3673           return result;
3674         };
3675
3676         // makes subclassing work correct for wrapped built-ins
3677         var inheritIfRequired = function ($this, dummy, Wrapper) {
3678           var NewTarget, NewTargetPrototype;
3679           if (
3680             // it can work only with native `setPrototypeOf`
3681             objectSetPrototypeOf &&
3682             // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
3683             typeof (NewTarget = dummy.constructor) == 'function' &&
3684             NewTarget !== Wrapper &&
3685             isObject(NewTargetPrototype = NewTarget.prototype) &&
3686             NewTargetPrototype !== Wrapper.prototype
3687           ) objectSetPrototypeOf($this, NewTargetPrototype);
3688           return $this;
3689         };
3690
3691         var typedArrayConstructor = createCommonjsModule(function (module) {
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710         var getOwnPropertyNames = objectGetOwnPropertyNames.f;
3711
3712         var forEach = arrayIteration.forEach;
3713
3714
3715
3716
3717
3718
3719         var getInternalState = internalState.get;
3720         var setInternalState = internalState.set;
3721         var nativeDefineProperty = objectDefineProperty.f;
3722         var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
3723         var round = Math.round;
3724         var RangeError = global_1.RangeError;
3725         var ArrayBuffer = arrayBuffer.ArrayBuffer;
3726         var DataView = arrayBuffer.DataView;
3727         var NATIVE_ARRAY_BUFFER_VIEWS = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3728         var TYPED_ARRAY_TAG = arrayBufferViewCore.TYPED_ARRAY_TAG;
3729         var TypedArray = arrayBufferViewCore.TypedArray;
3730         var TypedArrayPrototype = arrayBufferViewCore.TypedArrayPrototype;
3731         var aTypedArrayConstructor = arrayBufferViewCore.aTypedArrayConstructor;
3732         var isTypedArray = arrayBufferViewCore.isTypedArray;
3733         var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
3734         var WRONG_LENGTH = 'Wrong length';
3735
3736         var fromList = function (C, list) {
3737           var index = 0;
3738           var length = list.length;
3739           var result = new (aTypedArrayConstructor(C))(length);
3740           while (length > index) result[index] = list[index++];
3741           return result;
3742         };
3743
3744         var addGetter = function (it, key) {
3745           nativeDefineProperty(it, key, { get: function () {
3746             return getInternalState(this)[key];
3747           } });
3748         };
3749
3750         var isArrayBuffer = function (it) {
3751           var klass;
3752           return it instanceof ArrayBuffer || (klass = classof(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
3753         };
3754
3755         var isTypedArrayIndex = function (target, key) {
3756           return isTypedArray(target)
3757             && typeof key != 'symbol'
3758             && key in target
3759             && String(+key) == String(key);
3760         };
3761
3762         var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
3763           return isTypedArrayIndex(target, key = toPrimitive(key, true))
3764             ? createPropertyDescriptor(2, target[key])
3765             : nativeGetOwnPropertyDescriptor(target, key);
3766         };
3767
3768         var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
3769           if (isTypedArrayIndex(target, key = toPrimitive(key, true))
3770             && isObject(descriptor)
3771             && has(descriptor, 'value')
3772             && !has(descriptor, 'get')
3773             && !has(descriptor, 'set')
3774             // TODO: add validation descriptor w/o calling accessors
3775             && !descriptor.configurable
3776             && (!has(descriptor, 'writable') || descriptor.writable)
3777             && (!has(descriptor, 'enumerable') || descriptor.enumerable)
3778           ) {
3779             target[key] = descriptor.value;
3780             return target;
3781           } return nativeDefineProperty(target, key, descriptor);
3782         };
3783
3784         if (descriptors) {
3785           if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3786             objectGetOwnPropertyDescriptor.f = wrappedGetOwnPropertyDescriptor;
3787             objectDefineProperty.f = wrappedDefineProperty;
3788             addGetter(TypedArrayPrototype, 'buffer');
3789             addGetter(TypedArrayPrototype, 'byteOffset');
3790             addGetter(TypedArrayPrototype, 'byteLength');
3791             addGetter(TypedArrayPrototype, 'length');
3792           }
3793
3794           _export({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {
3795             getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
3796             defineProperty: wrappedDefineProperty
3797           });
3798
3799           module.exports = function (TYPE, wrapper, CLAMPED) {
3800             var BYTES = TYPE.match(/\d+$/)[0] / 8;
3801             var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
3802             var GETTER = 'get' + TYPE;
3803             var SETTER = 'set' + TYPE;
3804             var NativeTypedArrayConstructor = global_1[CONSTRUCTOR_NAME];
3805             var TypedArrayConstructor = NativeTypedArrayConstructor;
3806             var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
3807             var exported = {};
3808
3809             var getter = function (that, index) {
3810               var data = getInternalState(that);
3811               return data.view[GETTER](index * BYTES + data.byteOffset, true);
3812             };
3813
3814             var setter = function (that, index, value) {
3815               var data = getInternalState(that);
3816               if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
3817               data.view[SETTER](index * BYTES + data.byteOffset, value, true);
3818             };
3819
3820             var addElement = function (that, index) {
3821               nativeDefineProperty(that, index, {
3822                 get: function () {
3823                   return getter(this, index);
3824                 },
3825                 set: function (value) {
3826                   return setter(this, index, value);
3827                 },
3828                 enumerable: true
3829               });
3830             };
3831
3832             if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3833               TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
3834                 anInstance(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
3835                 var index = 0;
3836                 var byteOffset = 0;
3837                 var buffer, byteLength, length;
3838                 if (!isObject(data)) {
3839                   length = toIndex(data);
3840                   byteLength = length * BYTES;
3841                   buffer = new ArrayBuffer(byteLength);
3842                 } else if (isArrayBuffer(data)) {
3843                   buffer = data;
3844                   byteOffset = toOffset(offset, BYTES);
3845                   var $len = data.byteLength;
3846                   if ($length === undefined) {
3847                     if ($len % BYTES) throw RangeError(WRONG_LENGTH);
3848                     byteLength = $len - byteOffset;
3849                     if (byteLength < 0) throw RangeError(WRONG_LENGTH);
3850                   } else {
3851                     byteLength = toLength($length) * BYTES;
3852                     if (byteLength + byteOffset > $len) throw RangeError(WRONG_LENGTH);
3853                   }
3854                   length = byteLength / BYTES;
3855                 } else if (isTypedArray(data)) {
3856                   return fromList(TypedArrayConstructor, data);
3857                 } else {
3858                   return typedArrayFrom.call(TypedArrayConstructor, data);
3859                 }
3860                 setInternalState(that, {
3861                   buffer: buffer,
3862                   byteOffset: byteOffset,
3863                   byteLength: byteLength,
3864                   length: length,
3865                   view: new DataView(buffer)
3866                 });
3867                 while (index < length) addElement(that, index++);
3868               });
3869
3870               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3871               TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = objectCreate(TypedArrayPrototype);
3872             } else if (typedArrayConstructorsRequireWrappers) {
3873               TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
3874                 anInstance(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
3875                 return inheritIfRequired(function () {
3876                   if (!isObject(data)) return new NativeTypedArrayConstructor(toIndex(data));
3877                   if (isArrayBuffer(data)) return $length !== undefined
3878                     ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES), $length)
3879                     : typedArrayOffset !== undefined
3880                       ? new NativeTypedArrayConstructor(data, toOffset(typedArrayOffset, BYTES))
3881                       : new NativeTypedArrayConstructor(data);
3882                   if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
3883                   return typedArrayFrom.call(TypedArrayConstructor, data);
3884                 }(), dummy, TypedArrayConstructor);
3885               });
3886
3887               if (objectSetPrototypeOf) objectSetPrototypeOf(TypedArrayConstructor, TypedArray);
3888               forEach(getOwnPropertyNames(NativeTypedArrayConstructor), function (key) {
3889                 if (!(key in TypedArrayConstructor)) {
3890                   createNonEnumerableProperty(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
3891                 }
3892               });
3893               TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
3894             }
3895
3896             if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
3897               createNonEnumerableProperty(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
3898             }
3899
3900             if (TYPED_ARRAY_TAG) {
3901               createNonEnumerableProperty(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
3902             }
3903
3904             exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
3905
3906             _export({
3907               global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS
3908             }, exported);
3909
3910             if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
3911               createNonEnumerableProperty(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
3912             }
3913
3914             if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
3915               createNonEnumerableProperty(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
3916             }
3917
3918             setSpecies(CONSTRUCTOR_NAME);
3919           };
3920         } else module.exports = function () { /* empty */ };
3921         });
3922
3923         // `Uint8Array` constructor
3924         // https://tc39.github.io/ecma262/#sec-typedarray-objects
3925         typedArrayConstructor('Uint8', function (init) {
3926           return function Uint8Array(data, byteOffset, length) {
3927             return init(this, data, byteOffset, length);
3928           };
3929         });
3930
3931         var min$4 = Math.min;
3932
3933         // `Array.prototype.copyWithin` method implementation
3934         // https://tc39.github.io/ecma262/#sec-array.prototype.copywithin
3935         var arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {
3936           var O = toObject(this);
3937           var len = toLength(O.length);
3938           var to = toAbsoluteIndex(target, len);
3939           var from = toAbsoluteIndex(start, len);
3940           var end = arguments.length > 2 ? arguments[2] : undefined;
3941           var count = min$4((end === undefined ? len : toAbsoluteIndex(end, len)) - from, len - to);
3942           var inc = 1;
3943           if (from < to && to < from + count) {
3944             inc = -1;
3945             from += count - 1;
3946             to += count - 1;
3947           }
3948           while (count-- > 0) {
3949             if (from in O) O[to] = O[from];
3950             else delete O[to];
3951             to += inc;
3952             from += inc;
3953           } return O;
3954         };
3955
3956         var aTypedArray$1 = arrayBufferViewCore.aTypedArray;
3957         var exportTypedArrayMethod$1 = arrayBufferViewCore.exportTypedArrayMethod;
3958
3959         // `%TypedArray%.prototype.copyWithin` method
3960         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.copywithin
3961         exportTypedArrayMethod$1('copyWithin', function copyWithin(target, start /* , end */) {
3962           return arrayCopyWithin.call(aTypedArray$1(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
3963         });
3964
3965         var $every = arrayIteration.every;
3966
3967         var aTypedArray$2 = arrayBufferViewCore.aTypedArray;
3968         var exportTypedArrayMethod$2 = arrayBufferViewCore.exportTypedArrayMethod;
3969
3970         // `%TypedArray%.prototype.every` method
3971         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.every
3972         exportTypedArrayMethod$2('every', function every(callbackfn /* , thisArg */) {
3973           return $every(aTypedArray$2(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3974         });
3975
3976         var aTypedArray$3 = arrayBufferViewCore.aTypedArray;
3977         var exportTypedArrayMethod$3 = arrayBufferViewCore.exportTypedArrayMethod;
3978
3979         // `%TypedArray%.prototype.fill` method
3980         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.fill
3981         // eslint-disable-next-line no-unused-vars
3982         exportTypedArrayMethod$3('fill', function fill(value /* , start, end */) {
3983           return arrayFill.apply(aTypedArray$3(this), arguments);
3984         });
3985
3986         var $filter = arrayIteration.filter;
3987
3988
3989         var aTypedArray$4 = arrayBufferViewCore.aTypedArray;
3990         var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
3991         var exportTypedArrayMethod$4 = arrayBufferViewCore.exportTypedArrayMethod;
3992
3993         // `%TypedArray%.prototype.filter` method
3994         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.filter
3995         exportTypedArrayMethod$4('filter', function filter(callbackfn /* , thisArg */) {
3996           var list = $filter(aTypedArray$4(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3997           var C = speciesConstructor(this, this.constructor);
3998           var index = 0;
3999           var length = list.length;
4000           var result = new (aTypedArrayConstructor$2(C))(length);
4001           while (length > index) result[index] = list[index++];
4002           return result;
4003         });
4004
4005         var $find = arrayIteration.find;
4006
4007         var aTypedArray$5 = arrayBufferViewCore.aTypedArray;
4008         var exportTypedArrayMethod$5 = arrayBufferViewCore.exportTypedArrayMethod;
4009
4010         // `%TypedArray%.prototype.find` method
4011         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.find
4012         exportTypedArrayMethod$5('find', function find(predicate /* , thisArg */) {
4013           return $find(aTypedArray$5(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4014         });
4015
4016         var $findIndex = arrayIteration.findIndex;
4017
4018         var aTypedArray$6 = arrayBufferViewCore.aTypedArray;
4019         var exportTypedArrayMethod$6 = arrayBufferViewCore.exportTypedArrayMethod;
4020
4021         // `%TypedArray%.prototype.findIndex` method
4022         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.findindex
4023         exportTypedArrayMethod$6('findIndex', function findIndex(predicate /* , thisArg */) {
4024           return $findIndex(aTypedArray$6(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4025         });
4026
4027         var $forEach$2 = arrayIteration.forEach;
4028
4029         var aTypedArray$7 = arrayBufferViewCore.aTypedArray;
4030         var exportTypedArrayMethod$7 = arrayBufferViewCore.exportTypedArrayMethod;
4031
4032         // `%TypedArray%.prototype.forEach` method
4033         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.foreach
4034         exportTypedArrayMethod$7('forEach', function forEach(callbackfn /* , thisArg */) {
4035           $forEach$2(aTypedArray$7(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4036         });
4037
4038         var $includes = arrayIncludes.includes;
4039
4040         var aTypedArray$8 = arrayBufferViewCore.aTypedArray;
4041         var exportTypedArrayMethod$8 = arrayBufferViewCore.exportTypedArrayMethod;
4042
4043         // `%TypedArray%.prototype.includes` method
4044         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.includes
4045         exportTypedArrayMethod$8('includes', function includes(searchElement /* , fromIndex */) {
4046           return $includes(aTypedArray$8(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4047         });
4048
4049         var $indexOf$1 = arrayIncludes.indexOf;
4050
4051         var aTypedArray$9 = arrayBufferViewCore.aTypedArray;
4052         var exportTypedArrayMethod$9 = arrayBufferViewCore.exportTypedArrayMethod;
4053
4054         // `%TypedArray%.prototype.indexOf` method
4055         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.indexof
4056         exportTypedArrayMethod$9('indexOf', function indexOf(searchElement /* , fromIndex */) {
4057           return $indexOf$1(aTypedArray$9(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4058         });
4059
4060         var ITERATOR$5 = wellKnownSymbol('iterator');
4061         var Uint8Array$1 = global_1.Uint8Array;
4062         var arrayValues = es_array_iterator.values;
4063         var arrayKeys = es_array_iterator.keys;
4064         var arrayEntries = es_array_iterator.entries;
4065         var aTypedArray$a = arrayBufferViewCore.aTypedArray;
4066         var exportTypedArrayMethod$a = arrayBufferViewCore.exportTypedArrayMethod;
4067         var nativeTypedArrayIterator = Uint8Array$1 && Uint8Array$1.prototype[ITERATOR$5];
4068
4069         var CORRECT_ITER_NAME = !!nativeTypedArrayIterator
4070           && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);
4071
4072         var typedArrayValues = function values() {
4073           return arrayValues.call(aTypedArray$a(this));
4074         };
4075
4076         // `%TypedArray%.prototype.entries` method
4077         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.entries
4078         exportTypedArrayMethod$a('entries', function entries() {
4079           return arrayEntries.call(aTypedArray$a(this));
4080         });
4081         // `%TypedArray%.prototype.keys` method
4082         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.keys
4083         exportTypedArrayMethod$a('keys', function keys() {
4084           return arrayKeys.call(aTypedArray$a(this));
4085         });
4086         // `%TypedArray%.prototype.values` method
4087         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.values
4088         exportTypedArrayMethod$a('values', typedArrayValues, !CORRECT_ITER_NAME);
4089         // `%TypedArray%.prototype[@@iterator]` method
4090         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype-@@iterator
4091         exportTypedArrayMethod$a(ITERATOR$5, typedArrayValues, !CORRECT_ITER_NAME);
4092
4093         var aTypedArray$b = arrayBufferViewCore.aTypedArray;
4094         var exportTypedArrayMethod$b = arrayBufferViewCore.exportTypedArrayMethod;
4095         var $join = [].join;
4096
4097         // `%TypedArray%.prototype.join` method
4098         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join
4099         // eslint-disable-next-line no-unused-vars
4100         exportTypedArrayMethod$b('join', function join(separator) {
4101           return $join.apply(aTypedArray$b(this), arguments);
4102         });
4103
4104         var min$5 = Math.min;
4105         var nativeLastIndexOf = [].lastIndexOf;
4106         var NEGATIVE_ZERO$1 = !!nativeLastIndexOf && 1 / [1].lastIndexOf(1, -0) < 0;
4107         var STRICT_METHOD$3 = arrayMethodIsStrict('lastIndexOf');
4108         // For preventing possible almost infinite loop in non-standard implementations, test the forward version of the method
4109         var USES_TO_LENGTH$4 = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
4110         var FORCED$1 = NEGATIVE_ZERO$1 || !STRICT_METHOD$3 || !USES_TO_LENGTH$4;
4111
4112         // `Array.prototype.lastIndexOf` method implementation
4113         // https://tc39.github.io/ecma262/#sec-array.prototype.lastindexof
4114         var arrayLastIndexOf = FORCED$1 ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {
4115           // convert -0 to +0
4116           if (NEGATIVE_ZERO$1) return nativeLastIndexOf.apply(this, arguments) || 0;
4117           var O = toIndexedObject(this);
4118           var length = toLength(O.length);
4119           var index = length - 1;
4120           if (arguments.length > 1) index = min$5(index, toInteger(arguments[1]));
4121           if (index < 0) index = length + index;
4122           for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;
4123           return -1;
4124         } : nativeLastIndexOf;
4125
4126         var aTypedArray$c = arrayBufferViewCore.aTypedArray;
4127         var exportTypedArrayMethod$c = arrayBufferViewCore.exportTypedArrayMethod;
4128
4129         // `%TypedArray%.prototype.lastIndexOf` method
4130         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.lastindexof
4131         // eslint-disable-next-line no-unused-vars
4132         exportTypedArrayMethod$c('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {
4133           return arrayLastIndexOf.apply(aTypedArray$c(this), arguments);
4134         });
4135
4136         var $map$1 = arrayIteration.map;
4137
4138
4139         var aTypedArray$d = arrayBufferViewCore.aTypedArray;
4140         var aTypedArrayConstructor$3 = arrayBufferViewCore.aTypedArrayConstructor;
4141         var exportTypedArrayMethod$d = arrayBufferViewCore.exportTypedArrayMethod;
4142
4143         // `%TypedArray%.prototype.map` method
4144         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.map
4145         exportTypedArrayMethod$d('map', function map(mapfn /* , thisArg */) {
4146           return $map$1(aTypedArray$d(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
4147             return new (aTypedArrayConstructor$3(speciesConstructor(O, O.constructor)))(length);
4148           });
4149         });
4150
4151         // `Array.prototype.{ reduce, reduceRight }` methods implementation
4152         var createMethod$4 = function (IS_RIGHT) {
4153           return function (that, callbackfn, argumentsLength, memo) {
4154             aFunction$1(callbackfn);
4155             var O = toObject(that);
4156             var self = indexedObject(O);
4157             var length = toLength(O.length);
4158             var index = IS_RIGHT ? length - 1 : 0;
4159             var i = IS_RIGHT ? -1 : 1;
4160             if (argumentsLength < 2) while (true) {
4161               if (index in self) {
4162                 memo = self[index];
4163                 index += i;
4164                 break;
4165               }
4166               index += i;
4167               if (IS_RIGHT ? index < 0 : length <= index) {
4168                 throw TypeError('Reduce of empty array with no initial value');
4169               }
4170             }
4171             for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
4172               memo = callbackfn(memo, self[index], index, O);
4173             }
4174             return memo;
4175           };
4176         };
4177
4178         var arrayReduce = {
4179           // `Array.prototype.reduce` method
4180           // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
4181           left: createMethod$4(false),
4182           // `Array.prototype.reduceRight` method
4183           // https://tc39.github.io/ecma262/#sec-array.prototype.reduceright
4184           right: createMethod$4(true)
4185         };
4186
4187         var $reduce = arrayReduce.left;
4188
4189         var aTypedArray$e = arrayBufferViewCore.aTypedArray;
4190         var exportTypedArrayMethod$e = arrayBufferViewCore.exportTypedArrayMethod;
4191
4192         // `%TypedArray%.prototype.reduce` method
4193         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduce
4194         exportTypedArrayMethod$e('reduce', function reduce(callbackfn /* , initialValue */) {
4195           return $reduce(aTypedArray$e(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4196         });
4197
4198         var $reduceRight = arrayReduce.right;
4199
4200         var aTypedArray$f = arrayBufferViewCore.aTypedArray;
4201         var exportTypedArrayMethod$f = arrayBufferViewCore.exportTypedArrayMethod;
4202
4203         // `%TypedArray%.prototype.reduceRicht` method
4204         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reduceright
4205         exportTypedArrayMethod$f('reduceRight', function reduceRight(callbackfn /* , initialValue */) {
4206           return $reduceRight(aTypedArray$f(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4207         });
4208
4209         var aTypedArray$g = arrayBufferViewCore.aTypedArray;
4210         var exportTypedArrayMethod$g = arrayBufferViewCore.exportTypedArrayMethod;
4211         var floor$3 = Math.floor;
4212
4213         // `%TypedArray%.prototype.reverse` method
4214         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.reverse
4215         exportTypedArrayMethod$g('reverse', function reverse() {
4216           var that = this;
4217           var length = aTypedArray$g(that).length;
4218           var middle = floor$3(length / 2);
4219           var index = 0;
4220           var value;
4221           while (index < middle) {
4222             value = that[index];
4223             that[index++] = that[--length];
4224             that[length] = value;
4225           } return that;
4226         });
4227
4228         var aTypedArray$h = arrayBufferViewCore.aTypedArray;
4229         var exportTypedArrayMethod$h = arrayBufferViewCore.exportTypedArrayMethod;
4230
4231         var FORCED$2 = fails(function () {
4232           // eslint-disable-next-line no-undef
4233           new Int8Array(1).set({});
4234         });
4235
4236         // `%TypedArray%.prototype.set` method
4237         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.set
4238         exportTypedArrayMethod$h('set', function set(arrayLike /* , offset */) {
4239           aTypedArray$h(this);
4240           var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
4241           var length = this.length;
4242           var src = toObject(arrayLike);
4243           var len = toLength(src.length);
4244           var index = 0;
4245           if (len + offset > length) throw RangeError('Wrong length');
4246           while (index < len) this[offset + index] = src[index++];
4247         }, FORCED$2);
4248
4249         var aTypedArray$i = arrayBufferViewCore.aTypedArray;
4250         var aTypedArrayConstructor$4 = arrayBufferViewCore.aTypedArrayConstructor;
4251         var exportTypedArrayMethod$i = arrayBufferViewCore.exportTypedArrayMethod;
4252         var $slice = [].slice;
4253
4254         var FORCED$3 = fails(function () {
4255           // eslint-disable-next-line no-undef
4256           new Int8Array(1).slice();
4257         });
4258
4259         // `%TypedArray%.prototype.slice` method
4260         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.slice
4261         exportTypedArrayMethod$i('slice', function slice(start, end) {
4262           var list = $slice.call(aTypedArray$i(this), start, end);
4263           var C = speciesConstructor(this, this.constructor);
4264           var index = 0;
4265           var length = list.length;
4266           var result = new (aTypedArrayConstructor$4(C))(length);
4267           while (length > index) result[index] = list[index++];
4268           return result;
4269         }, FORCED$3);
4270
4271         var $some = arrayIteration.some;
4272
4273         var aTypedArray$j = arrayBufferViewCore.aTypedArray;
4274         var exportTypedArrayMethod$j = arrayBufferViewCore.exportTypedArrayMethod;
4275
4276         // `%TypedArray%.prototype.some` method
4277         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.some
4278         exportTypedArrayMethod$j('some', function some(callbackfn /* , thisArg */) {
4279           return $some(aTypedArray$j(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4280         });
4281
4282         var aTypedArray$k = arrayBufferViewCore.aTypedArray;
4283         var exportTypedArrayMethod$k = arrayBufferViewCore.exportTypedArrayMethod;
4284         var $sort = [].sort;
4285
4286         // `%TypedArray%.prototype.sort` method
4287         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort
4288         exportTypedArrayMethod$k('sort', function sort(comparefn) {
4289           return $sort.call(aTypedArray$k(this), comparefn);
4290         });
4291
4292         var aTypedArray$l = arrayBufferViewCore.aTypedArray;
4293         var exportTypedArrayMethod$l = arrayBufferViewCore.exportTypedArrayMethod;
4294
4295         // `%TypedArray%.prototype.subarray` method
4296         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.subarray
4297         exportTypedArrayMethod$l('subarray', function subarray(begin, end) {
4298           var O = aTypedArray$l(this);
4299           var length = O.length;
4300           var beginIndex = toAbsoluteIndex(begin, length);
4301           return new (speciesConstructor(O, O.constructor))(
4302             O.buffer,
4303             O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,
4304             toLength((end === undefined ? length : toAbsoluteIndex(end, length)) - beginIndex)
4305           );
4306         });
4307
4308         var Int8Array$3 = global_1.Int8Array;
4309         var aTypedArray$m = arrayBufferViewCore.aTypedArray;
4310         var exportTypedArrayMethod$m = arrayBufferViewCore.exportTypedArrayMethod;
4311         var $toLocaleString = [].toLocaleString;
4312         var $slice$1 = [].slice;
4313
4314         // iOS Safari 6.x fails here
4315         var TO_LOCALE_STRING_BUG = !!Int8Array$3 && fails(function () {
4316           $toLocaleString.call(new Int8Array$3(1));
4317         });
4318
4319         var FORCED$4 = fails(function () {
4320           return [1, 2].toLocaleString() != new Int8Array$3([1, 2]).toLocaleString();
4321         }) || !fails(function () {
4322           Int8Array$3.prototype.toLocaleString.call([1, 2]);
4323         });
4324
4325         // `%TypedArray%.prototype.toLocaleString` method
4326         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring
4327         exportTypedArrayMethod$m('toLocaleString', function toLocaleString() {
4328           return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice$1.call(aTypedArray$m(this)) : aTypedArray$m(this), arguments);
4329         }, FORCED$4);
4330
4331         var exportTypedArrayMethod$n = arrayBufferViewCore.exportTypedArrayMethod;
4332
4333
4334
4335         var Uint8Array$2 = global_1.Uint8Array;
4336         var Uint8ArrayPrototype = Uint8Array$2 && Uint8Array$2.prototype || {};
4337         var arrayToString = [].toString;
4338         var arrayJoin = [].join;
4339
4340         if (fails(function () { arrayToString.call({}); })) {
4341           arrayToString = function toString() {
4342             return arrayJoin.call(this);
4343           };
4344         }
4345
4346         var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;
4347
4348         // `%TypedArray%.prototype.toString` method
4349         // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tostring
4350         exportTypedArrayMethod$n('toString', arrayToString, IS_NOT_ARRAY_METHOD);
4351
4352         // iterable DOM collections
4353         // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
4354         var domIterables = {
4355           CSSRuleList: 0,
4356           CSSStyleDeclaration: 0,
4357           CSSValueList: 0,
4358           ClientRectList: 0,
4359           DOMRectList: 0,
4360           DOMStringList: 0,
4361           DOMTokenList: 1,
4362           DataTransferItemList: 0,
4363           FileList: 0,
4364           HTMLAllCollection: 0,
4365           HTMLCollection: 0,
4366           HTMLFormElement: 0,
4367           HTMLSelectElement: 0,
4368           MediaList: 0,
4369           MimeTypeArray: 0,
4370           NamedNodeMap: 0,
4371           NodeList: 1,
4372           PaintRequestList: 0,
4373           Plugin: 0,
4374           PluginArray: 0,
4375           SVGLengthList: 0,
4376           SVGNumberList: 0,
4377           SVGPathSegList: 0,
4378           SVGPointList: 0,
4379           SVGStringList: 0,
4380           SVGTransformList: 0,
4381           SourceBufferList: 0,
4382           StyleSheetList: 0,
4383           TextTrackCueList: 0,
4384           TextTrackList: 0,
4385           TouchList: 0
4386         };
4387
4388         for (var COLLECTION_NAME in domIterables) {
4389           var Collection = global_1[COLLECTION_NAME];
4390           var CollectionPrototype = Collection && Collection.prototype;
4391           // some Chrome versions have non-configurable methods on DOMTokenList
4392           if (CollectionPrototype && CollectionPrototype.forEach !== arrayForEach) try {
4393             createNonEnumerableProperty(CollectionPrototype, 'forEach', arrayForEach);
4394           } catch (error) {
4395             CollectionPrototype.forEach = arrayForEach;
4396           }
4397         }
4398
4399         var ITERATOR$6 = wellKnownSymbol('iterator');
4400         var TO_STRING_TAG$4 = wellKnownSymbol('toStringTag');
4401         var ArrayValues = es_array_iterator.values;
4402
4403         for (var COLLECTION_NAME$1 in domIterables) {
4404           var Collection$1 = global_1[COLLECTION_NAME$1];
4405           var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
4406           if (CollectionPrototype$1) {
4407             // some Chrome versions have non-configurable methods on DOMTokenList
4408             if (CollectionPrototype$1[ITERATOR$6] !== ArrayValues) try {
4409               createNonEnumerableProperty(CollectionPrototype$1, ITERATOR$6, ArrayValues);
4410             } catch (error) {
4411               CollectionPrototype$1[ITERATOR$6] = ArrayValues;
4412             }
4413             if (!CollectionPrototype$1[TO_STRING_TAG$4]) {
4414               createNonEnumerableProperty(CollectionPrototype$1, TO_STRING_TAG$4, COLLECTION_NAME$1);
4415             }
4416             if (domIterables[COLLECTION_NAME$1]) for (var METHOD_NAME in es_array_iterator) {
4417               // some Chrome versions have non-configurable methods on DOMTokenList
4418               if (CollectionPrototype$1[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
4419                 createNonEnumerableProperty(CollectionPrototype$1, METHOD_NAME, es_array_iterator[METHOD_NAME]);
4420               } catch (error) {
4421                 CollectionPrototype$1[METHOD_NAME] = es_array_iterator[METHOD_NAME];
4422               }
4423             }
4424           }
4425         }
4426
4427         var slice = [].slice;
4428         var MSIE = /MSIE .\./.test(engineUserAgent); // <- dirty ie9- check
4429
4430         var wrap$1 = function (scheduler) {
4431           return function (handler, timeout /* , ...arguments */) {
4432             var boundArgs = arguments.length > 2;
4433             var args = boundArgs ? slice.call(arguments, 2) : undefined;
4434             return scheduler(boundArgs ? function () {
4435               // eslint-disable-next-line no-new-func
4436               (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
4437             } : handler, timeout);
4438           };
4439         };
4440
4441         // ie9- setTimeout & setInterval additional parameters fix
4442         // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
4443         _export({ global: true, bind: true, forced: MSIE }, {
4444           // `setTimeout` method
4445           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
4446           setTimeout: wrap$1(global_1.setTimeout),
4447           // `setInterval` method
4448           // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
4449           setInterval: wrap$1(global_1.setInterval)
4450         });
4451
4452         var ITERATOR$7 = wellKnownSymbol('iterator');
4453
4454         var nativeUrl = !fails(function () {
4455           var url = new URL('b?a=1&b=2&c=3', 'http://a');
4456           var searchParams = url.searchParams;
4457           var result = '';
4458           url.pathname = 'c%20d';
4459           searchParams.forEach(function (value, key) {
4460             searchParams['delete']('b');
4461             result += key + value;
4462           });
4463           return (isPure && !url.toJSON)
4464             || !searchParams.sort
4465             || url.href !== 'http://a/c%20d?a=1&c=3'
4466             || searchParams.get('c') !== '3'
4467             || String(new URLSearchParams('?a=1')) !== 'a=1'
4468             || !searchParams[ITERATOR$7]
4469             // throws in Edge
4470             || new URL('https://a@b').username !== 'a'
4471             || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
4472             // not punycoded in Edge
4473             || new URL('http://тест').host !== 'xn--e1aybc'
4474             // not escaped in Chrome 62-
4475             || new URL('http://a#б').hash !== '#%D0%B1'
4476             // fails in Chrome 66-
4477             || result !== 'a1c3'
4478             // throws in Safari
4479             || new URL('http://x', undefined).host !== 'x';
4480         });
4481
4482         var nativeAssign = Object.assign;
4483         var defineProperty$7 = Object.defineProperty;
4484
4485         // `Object.assign` method
4486         // https://tc39.github.io/ecma262/#sec-object.assign
4487         var objectAssign = !nativeAssign || fails(function () {
4488           // should have correct order of operations (Edge bug)
4489           if (descriptors && nativeAssign({ b: 1 }, nativeAssign(defineProperty$7({}, 'a', {
4490             enumerable: true,
4491             get: function () {
4492               defineProperty$7(this, 'b', {
4493                 value: 3,
4494                 enumerable: false
4495               });
4496             }
4497           }), { b: 2 })).b !== 1) return true;
4498           // should work with symbols and should have deterministic property order (V8 bug)
4499           var A = {};
4500           var B = {};
4501           // eslint-disable-next-line no-undef
4502           var symbol = Symbol();
4503           var alphabet = 'abcdefghijklmnopqrst';
4504           A[symbol] = 7;
4505           alphabet.split('').forEach(function (chr) { B[chr] = chr; });
4506           return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
4507         }) ? function assign(target, source) { // eslint-disable-line no-unused-vars
4508           var T = toObject(target);
4509           var argumentsLength = arguments.length;
4510           var index = 1;
4511           var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
4512           var propertyIsEnumerable = objectPropertyIsEnumerable.f;
4513           while (argumentsLength > index) {
4514             var S = indexedObject(arguments[index++]);
4515             var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
4516             var length = keys.length;
4517             var j = 0;
4518             var key;
4519             while (length > j) {
4520               key = keys[j++];
4521               if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
4522             }
4523           } return T;
4524         } : nativeAssign;
4525
4526         // call something on iterator step with safe closing on error
4527         var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
4528           try {
4529             return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
4530           // 7.4.6 IteratorClose(iterator, completion)
4531           } catch (error) {
4532             iteratorClose(iterator);
4533             throw error;
4534           }
4535         };
4536
4537         // `Array.from` method implementation
4538         // https://tc39.github.io/ecma262/#sec-array.from
4539         var arrayFrom = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
4540           var O = toObject(arrayLike);
4541           var C = typeof this == 'function' ? this : Array;
4542           var argumentsLength = arguments.length;
4543           var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
4544           var mapping = mapfn !== undefined;
4545           var iteratorMethod = getIteratorMethod(O);
4546           var index = 0;
4547           var length, result, step, iterator, next, value;
4548           if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
4549           // if the target is not iterable or it's an array with the default iterator - use a simple case
4550           if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
4551             iterator = iteratorMethod.call(O);
4552             next = iterator.next;
4553             result = new C();
4554             for (;!(step = next.call(iterator)).done; index++) {
4555               value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
4556               createProperty(result, index, value);
4557             }
4558           } else {
4559             length = toLength(O.length);
4560             result = new C(length);
4561             for (;length > index; index++) {
4562               value = mapping ? mapfn(O[index], index) : O[index];
4563               createProperty(result, index, value);
4564             }
4565           }
4566           result.length = index;
4567           return result;
4568         };
4569
4570         // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
4571         var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
4572         var base = 36;
4573         var tMin = 1;
4574         var tMax = 26;
4575         var skew = 38;
4576         var damp = 700;
4577         var initialBias = 72;
4578         var initialN = 128; // 0x80
4579         var delimiter = '-'; // '\x2D'
4580         var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
4581         var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
4582         var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
4583         var baseMinusTMin = base - tMin;
4584         var floor$4 = Math.floor;
4585         var stringFromCharCode = String.fromCharCode;
4586
4587         /**
4588          * Creates an array containing the numeric code points of each Unicode
4589          * character in the string. While JavaScript uses UCS-2 internally,
4590          * this function will convert a pair of surrogate halves (each of which
4591          * UCS-2 exposes as separate characters) into a single code point,
4592          * matching UTF-16.
4593          */
4594         var ucs2decode = function (string) {
4595           var output = [];
4596           var counter = 0;
4597           var length = string.length;
4598           while (counter < length) {
4599             var value = string.charCodeAt(counter++);
4600             if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4601               // It's a high surrogate, and there is a next character.
4602               var extra = string.charCodeAt(counter++);
4603               if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
4604                 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4605               } else {
4606                 // It's an unmatched surrogate; only append this code unit, in case the
4607                 // next code unit is the high surrogate of a surrogate pair.
4608                 output.push(value);
4609                 counter--;
4610               }
4611             } else {
4612               output.push(value);
4613             }
4614           }
4615           return output;
4616         };
4617
4618         /**
4619          * Converts a digit/integer into a basic code point.
4620          */
4621         var digitToBasic = function (digit) {
4622           //  0..25 map to ASCII a..z or A..Z
4623           // 26..35 map to ASCII 0..9
4624           return digit + 22 + 75 * (digit < 26);
4625         };
4626
4627         /**
4628          * Bias adaptation function as per section 3.4 of RFC 3492.
4629          * https://tools.ietf.org/html/rfc3492#section-3.4
4630          */
4631         var adapt = function (delta, numPoints, firstTime) {
4632           var k = 0;
4633           delta = firstTime ? floor$4(delta / damp) : delta >> 1;
4634           delta += floor$4(delta / numPoints);
4635           for (; delta > baseMinusTMin * tMax >> 1; k += base) {
4636             delta = floor$4(delta / baseMinusTMin);
4637           }
4638           return floor$4(k + (baseMinusTMin + 1) * delta / (delta + skew));
4639         };
4640
4641         /**
4642          * Converts a string of Unicode symbols (e.g. a domain name label) to a
4643          * Punycode string of ASCII-only symbols.
4644          */
4645         // eslint-disable-next-line  max-statements
4646         var encode = function (input) {
4647           var output = [];
4648
4649           // Convert the input in UCS-2 to an array of Unicode code points.
4650           input = ucs2decode(input);
4651
4652           // Cache the length.
4653           var inputLength = input.length;
4654
4655           // Initialize the state.
4656           var n = initialN;
4657           var delta = 0;
4658           var bias = initialBias;
4659           var i, currentValue;
4660
4661           // Handle the basic code points.
4662           for (i = 0; i < input.length; i++) {
4663             currentValue = input[i];
4664             if (currentValue < 0x80) {
4665               output.push(stringFromCharCode(currentValue));
4666             }
4667           }
4668
4669           var basicLength = output.length; // number of basic code points.
4670           var handledCPCount = basicLength; // number of code points that have been handled;
4671
4672           // Finish the basic string with a delimiter unless it's empty.
4673           if (basicLength) {
4674             output.push(delimiter);
4675           }
4676
4677           // Main encoding loop:
4678           while (handledCPCount < inputLength) {
4679             // All non-basic code points < n have been handled already. Find the next larger one:
4680             var m = maxInt;
4681             for (i = 0; i < input.length; i++) {
4682               currentValue = input[i];
4683               if (currentValue >= n && currentValue < m) {
4684                 m = currentValue;
4685               }
4686             }
4687
4688             // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
4689             var handledCPCountPlusOne = handledCPCount + 1;
4690             if (m - n > floor$4((maxInt - delta) / handledCPCountPlusOne)) {
4691               throw RangeError(OVERFLOW_ERROR);
4692             }
4693
4694             delta += (m - n) * handledCPCountPlusOne;
4695             n = m;
4696
4697             for (i = 0; i < input.length; i++) {
4698               currentValue = input[i];
4699               if (currentValue < n && ++delta > maxInt) {
4700                 throw RangeError(OVERFLOW_ERROR);
4701               }
4702               if (currentValue == n) {
4703                 // Represent delta as a generalized variable-length integer.
4704                 var q = delta;
4705                 for (var k = base; /* no condition */; k += base) {
4706                   var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
4707                   if (q < t) break;
4708                   var qMinusT = q - t;
4709                   var baseMinusT = base - t;
4710                   output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
4711                   q = floor$4(qMinusT / baseMinusT);
4712                 }
4713
4714                 output.push(stringFromCharCode(digitToBasic(q)));
4715                 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
4716                 delta = 0;
4717                 ++handledCPCount;
4718               }
4719             }
4720
4721             ++delta;
4722             ++n;
4723           }
4724           return output.join('');
4725         };
4726
4727         var stringPunycodeToAscii = function (input) {
4728           var encoded = [];
4729           var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
4730           var i, label;
4731           for (i = 0; i < labels.length; i++) {
4732             label = labels[i];
4733             encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
4734           }
4735           return encoded.join('.');
4736         };
4737
4738         var getIterator = function (it) {
4739           var iteratorMethod = getIteratorMethod(it);
4740           if (typeof iteratorMethod != 'function') {
4741             throw TypeError(String(it) + ' is not iterable');
4742           } return anObject(iteratorMethod.call(it));
4743         };
4744
4745         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767         var $fetch$1 = getBuiltIn('fetch');
4768         var Headers = getBuiltIn('Headers');
4769         var ITERATOR$8 = wellKnownSymbol('iterator');
4770         var URL_SEARCH_PARAMS = 'URLSearchParams';
4771         var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
4772         var setInternalState$5 = internalState.set;
4773         var getInternalParamsState = internalState.getterFor(URL_SEARCH_PARAMS);
4774         var getInternalIteratorState = internalState.getterFor(URL_SEARCH_PARAMS_ITERATOR);
4775
4776         var plus = /\+/g;
4777         var sequences = Array(4);
4778
4779         var percentSequence = function (bytes) {
4780           return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
4781         };
4782
4783         var percentDecode = function (sequence) {
4784           try {
4785             return decodeURIComponent(sequence);
4786           } catch (error) {
4787             return sequence;
4788           }
4789         };
4790
4791         var deserialize = function (it) {
4792           var result = it.replace(plus, ' ');
4793           var bytes = 4;
4794           try {
4795             return decodeURIComponent(result);
4796           } catch (error) {
4797             while (bytes) {
4798               result = result.replace(percentSequence(bytes--), percentDecode);
4799             }
4800             return result;
4801           }
4802         };
4803
4804         var find = /[!'()~]|%20/g;
4805
4806         var replace = {
4807           '!': '%21',
4808           "'": '%27',
4809           '(': '%28',
4810           ')': '%29',
4811           '~': '%7E',
4812           '%20': '+'
4813         };
4814
4815         var replacer = function (match) {
4816           return replace[match];
4817         };
4818
4819         var serialize = function (it) {
4820           return encodeURIComponent(it).replace(find, replacer);
4821         };
4822
4823         var parseSearchParams = function (result, query) {
4824           if (query) {
4825             var attributes = query.split('&');
4826             var index = 0;
4827             var attribute, entry;
4828             while (index < attributes.length) {
4829               attribute = attributes[index++];
4830               if (attribute.length) {
4831                 entry = attribute.split('=');
4832                 result.push({
4833                   key: deserialize(entry.shift()),
4834                   value: deserialize(entry.join('='))
4835                 });
4836               }
4837             }
4838           }
4839         };
4840
4841         var updateSearchParams = function (query) {
4842           this.entries.length = 0;
4843           parseSearchParams(this.entries, query);
4844         };
4845
4846         var validateArgumentsLength = function (passed, required) {
4847           if (passed < required) throw TypeError('Not enough arguments');
4848         };
4849
4850         var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
4851           setInternalState$5(this, {
4852             type: URL_SEARCH_PARAMS_ITERATOR,
4853             iterator: getIterator(getInternalParamsState(params).entries),
4854             kind: kind
4855           });
4856         }, 'Iterator', function next() {
4857           var state = getInternalIteratorState(this);
4858           var kind = state.kind;
4859           var step = state.iterator.next();
4860           var entry = step.value;
4861           if (!step.done) {
4862             step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
4863           } return step;
4864         });
4865
4866         // `URLSearchParams` constructor
4867         // https://url.spec.whatwg.org/#interface-urlsearchparams
4868         var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
4869           anInstance(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
4870           var init = arguments.length > 0 ? arguments[0] : undefined;
4871           var that = this;
4872           var entries = [];
4873           var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
4874
4875           setInternalState$5(that, {
4876             type: URL_SEARCH_PARAMS,
4877             entries: entries,
4878             updateURL: function () { /* empty */ },
4879             updateSearchParams: updateSearchParams
4880           });
4881
4882           if (init !== undefined) {
4883             if (isObject(init)) {
4884               iteratorMethod = getIteratorMethod(init);
4885               if (typeof iteratorMethod === 'function') {
4886                 iterator = iteratorMethod.call(init);
4887                 next = iterator.next;
4888                 while (!(step = next.call(iterator)).done) {
4889                   entryIterator = getIterator(anObject(step.value));
4890                   entryNext = entryIterator.next;
4891                   if (
4892                     (first = entryNext.call(entryIterator)).done ||
4893                     (second = entryNext.call(entryIterator)).done ||
4894                     !entryNext.call(entryIterator).done
4895                   ) throw TypeError('Expected sequence with length 2');
4896                   entries.push({ key: first.value + '', value: second.value + '' });
4897                 }
4898               } else for (key in init) if (has(init, key)) entries.push({ key: key, value: init[key] + '' });
4899             } else {
4900               parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
4901             }
4902           }
4903         };
4904
4905         var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
4906
4907         redefineAll(URLSearchParamsPrototype, {
4908           // `URLSearchParams.prototype.append` method
4909           // https://url.spec.whatwg.org/#dom-urlsearchparams-append
4910           append: function append(name, value) {
4911             validateArgumentsLength(arguments.length, 2);
4912             var state = getInternalParamsState(this);
4913             state.entries.push({ key: name + '', value: value + '' });
4914             state.updateURL();
4915           },
4916           // `URLSearchParams.prototype.delete` method
4917           // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
4918           'delete': function (name) {
4919             validateArgumentsLength(arguments.length, 1);
4920             var state = getInternalParamsState(this);
4921             var entries = state.entries;
4922             var key = name + '';
4923             var index = 0;
4924             while (index < entries.length) {
4925               if (entries[index].key === key) entries.splice(index, 1);
4926               else index++;
4927             }
4928             state.updateURL();
4929           },
4930           // `URLSearchParams.prototype.get` method
4931           // https://url.spec.whatwg.org/#dom-urlsearchparams-get
4932           get: function get(name) {
4933             validateArgumentsLength(arguments.length, 1);
4934             var entries = getInternalParamsState(this).entries;
4935             var key = name + '';
4936             var index = 0;
4937             for (; index < entries.length; index++) {
4938               if (entries[index].key === key) return entries[index].value;
4939             }
4940             return null;
4941           },
4942           // `URLSearchParams.prototype.getAll` method
4943           // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
4944           getAll: function getAll(name) {
4945             validateArgumentsLength(arguments.length, 1);
4946             var entries = getInternalParamsState(this).entries;
4947             var key = name + '';
4948             var result = [];
4949             var index = 0;
4950             for (; index < entries.length; index++) {
4951               if (entries[index].key === key) result.push(entries[index].value);
4952             }
4953             return result;
4954           },
4955           // `URLSearchParams.prototype.has` method
4956           // https://url.spec.whatwg.org/#dom-urlsearchparams-has
4957           has: function has(name) {
4958             validateArgumentsLength(arguments.length, 1);
4959             var entries = getInternalParamsState(this).entries;
4960             var key = name + '';
4961             var index = 0;
4962             while (index < entries.length) {
4963               if (entries[index++].key === key) return true;
4964             }
4965             return false;
4966           },
4967           // `URLSearchParams.prototype.set` method
4968           // https://url.spec.whatwg.org/#dom-urlsearchparams-set
4969           set: function set(name, value) {
4970             validateArgumentsLength(arguments.length, 1);
4971             var state = getInternalParamsState(this);
4972             var entries = state.entries;
4973             var found = false;
4974             var key = name + '';
4975             var val = value + '';
4976             var index = 0;
4977             var entry;
4978             for (; index < entries.length; index++) {
4979               entry = entries[index];
4980               if (entry.key === key) {
4981                 if (found) entries.splice(index--, 1);
4982                 else {
4983                   found = true;
4984                   entry.value = val;
4985                 }
4986               }
4987             }
4988             if (!found) entries.push({ key: key, value: val });
4989             state.updateURL();
4990           },
4991           // `URLSearchParams.prototype.sort` method
4992           // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
4993           sort: function sort() {
4994             var state = getInternalParamsState(this);
4995             var entries = state.entries;
4996             // Array#sort is not stable in some engines
4997             var slice = entries.slice();
4998             var entry, entriesIndex, sliceIndex;
4999             entries.length = 0;
5000             for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
5001               entry = slice[sliceIndex];
5002               for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
5003                 if (entries[entriesIndex].key > entry.key) {
5004                   entries.splice(entriesIndex, 0, entry);
5005                   break;
5006                 }
5007               }
5008               if (entriesIndex === sliceIndex) entries.push(entry);
5009             }
5010             state.updateURL();
5011           },
5012           // `URLSearchParams.prototype.forEach` method
5013           forEach: function forEach(callback /* , thisArg */) {
5014             var entries = getInternalParamsState(this).entries;
5015             var boundFunction = functionBindContext(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
5016             var index = 0;
5017             var entry;
5018             while (index < entries.length) {
5019               entry = entries[index++];
5020               boundFunction(entry.value, entry.key, this);
5021             }
5022           },
5023           // `URLSearchParams.prototype.keys` method
5024           keys: function keys() {
5025             return new URLSearchParamsIterator(this, 'keys');
5026           },
5027           // `URLSearchParams.prototype.values` method
5028           values: function values() {
5029             return new URLSearchParamsIterator(this, 'values');
5030           },
5031           // `URLSearchParams.prototype.entries` method
5032           entries: function entries() {
5033             return new URLSearchParamsIterator(this, 'entries');
5034           }
5035         }, { enumerable: true });
5036
5037         // `URLSearchParams.prototype[@@iterator]` method
5038         redefine(URLSearchParamsPrototype, ITERATOR$8, URLSearchParamsPrototype.entries);
5039
5040         // `URLSearchParams.prototype.toString` method
5041         // https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
5042         redefine(URLSearchParamsPrototype, 'toString', function toString() {
5043           var entries = getInternalParamsState(this).entries;
5044           var result = [];
5045           var index = 0;
5046           var entry;
5047           while (index < entries.length) {
5048             entry = entries[index++];
5049             result.push(serialize(entry.key) + '=' + serialize(entry.value));
5050           } return result.join('&');
5051         }, { enumerable: true });
5052
5053         setToStringTag(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
5054
5055         _export({ global: true, forced: !nativeUrl }, {
5056           URLSearchParams: URLSearchParamsConstructor
5057         });
5058
5059         // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
5060         // https://github.com/zloirock/core-js/issues/674
5061         if (!nativeUrl && typeof $fetch$1 == 'function' && typeof Headers == 'function') {
5062           _export({ global: true, enumerable: true, forced: true }, {
5063             fetch: function fetch(input /* , init */) {
5064               var args = [input];
5065               var init, body, headers;
5066               if (arguments.length > 1) {
5067                 init = arguments[1];
5068                 if (isObject(init)) {
5069                   body = init.body;
5070                   if (classof(body) === URL_SEARCH_PARAMS) {
5071                     headers = init.headers ? new Headers(init.headers) : new Headers();
5072                     if (!headers.has('content-type')) {
5073                       headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
5074                     }
5075                     init = objectCreate(init, {
5076                       body: createPropertyDescriptor(0, String(body)),
5077                       headers: createPropertyDescriptor(0, headers)
5078                     });
5079                   }
5080                 }
5081                 args.push(init);
5082               } return $fetch$1.apply(this, args);
5083             }
5084           });
5085         }
5086
5087         var web_urlSearchParams = {
5088           URLSearchParams: URLSearchParamsConstructor,
5089           getState: getInternalParamsState
5090         };
5091
5092         // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104         var codeAt = stringMultibyte.codeAt;
5105
5106
5107
5108
5109
5110         var NativeURL = global_1.URL;
5111         var URLSearchParams$1 = web_urlSearchParams.URLSearchParams;
5112         var getInternalSearchParamsState = web_urlSearchParams.getState;
5113         var setInternalState$6 = internalState.set;
5114         var getInternalURLState = internalState.getterFor('URL');
5115         var floor$5 = Math.floor;
5116         var pow$1 = Math.pow;
5117
5118         var INVALID_AUTHORITY = 'Invalid authority';
5119         var INVALID_SCHEME = 'Invalid scheme';
5120         var INVALID_HOST = 'Invalid host';
5121         var INVALID_PORT = 'Invalid port';
5122
5123         var ALPHA = /[A-Za-z]/;
5124         var ALPHANUMERIC = /[\d+-.A-Za-z]/;
5125         var DIGIT = /\d/;
5126         var HEX_START = /^(0x|0X)/;
5127         var OCT = /^[0-7]+$/;
5128         var DEC = /^\d+$/;
5129         var HEX = /^[\dA-Fa-f]+$/;
5130         // eslint-disable-next-line no-control-regex
5131         var FORBIDDEN_HOST_CODE_POINT = /[\u0000\u0009\u000A\u000D #%/:?@[\\]]/;
5132         // eslint-disable-next-line no-control-regex
5133         var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\u0000\u0009\u000A\u000D #/:?@[\\]]/;
5134         // eslint-disable-next-line no-control-regex
5135         var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
5136         // eslint-disable-next-line no-control-regex
5137         var TAB_AND_NEW_LINE = /[\u0009\u000A\u000D]/g;
5138         var EOF;
5139
5140         var parseHost = function (url, input) {
5141           var result, codePoints, index;
5142           if (input.charAt(0) == '[') {
5143             if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
5144             result = parseIPv6(input.slice(1, -1));
5145             if (!result) return INVALID_HOST;
5146             url.host = result;
5147           // opaque host
5148           } else if (!isSpecial(url)) {
5149             if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
5150             result = '';
5151             codePoints = arrayFrom(input);
5152             for (index = 0; index < codePoints.length; index++) {
5153               result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
5154             }
5155             url.host = result;
5156           } else {
5157             input = stringPunycodeToAscii(input);
5158             if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
5159             result = parseIPv4(input);
5160             if (result === null) return INVALID_HOST;
5161             url.host = result;
5162           }
5163         };
5164
5165         var parseIPv4 = function (input) {
5166           var parts = input.split('.');
5167           var partsLength, numbers, index, part, radix, number, ipv4;
5168           if (parts.length && parts[parts.length - 1] == '') {
5169             parts.pop();
5170           }
5171           partsLength = parts.length;
5172           if (partsLength > 4) return input;
5173           numbers = [];
5174           for (index = 0; index < partsLength; index++) {
5175             part = parts[index];
5176             if (part == '') return input;
5177             radix = 10;
5178             if (part.length > 1 && part.charAt(0) == '0') {
5179               radix = HEX_START.test(part) ? 16 : 8;
5180               part = part.slice(radix == 8 ? 1 : 2);
5181             }
5182             if (part === '') {
5183               number = 0;
5184             } else {
5185               if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
5186               number = parseInt(part, radix);
5187             }
5188             numbers.push(number);
5189           }
5190           for (index = 0; index < partsLength; index++) {
5191             number = numbers[index];
5192             if (index == partsLength - 1) {
5193               if (number >= pow$1(256, 5 - partsLength)) return null;
5194             } else if (number > 255) return null;
5195           }
5196           ipv4 = numbers.pop();
5197           for (index = 0; index < numbers.length; index++) {
5198             ipv4 += numbers[index] * pow$1(256, 3 - index);
5199           }
5200           return ipv4;
5201         };
5202
5203         // eslint-disable-next-line max-statements
5204         var parseIPv6 = function (input) {
5205           var address = [0, 0, 0, 0, 0, 0, 0, 0];
5206           var pieceIndex = 0;
5207           var compress = null;
5208           var pointer = 0;
5209           var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
5210
5211           var char = function () {
5212             return input.charAt(pointer);
5213           };
5214
5215           if (char() == ':') {
5216             if (input.charAt(1) != ':') return;
5217             pointer += 2;
5218             pieceIndex++;
5219             compress = pieceIndex;
5220           }
5221           while (char()) {
5222             if (pieceIndex == 8) return;
5223             if (char() == ':') {
5224               if (compress !== null) return;
5225               pointer++;
5226               pieceIndex++;
5227               compress = pieceIndex;
5228               continue;
5229             }
5230             value = length = 0;
5231             while (length < 4 && HEX.test(char())) {
5232               value = value * 16 + parseInt(char(), 16);
5233               pointer++;
5234               length++;
5235             }
5236             if (char() == '.') {
5237               if (length == 0) return;
5238               pointer -= length;
5239               if (pieceIndex > 6) return;
5240               numbersSeen = 0;
5241               while (char()) {
5242                 ipv4Piece = null;
5243                 if (numbersSeen > 0) {
5244                   if (char() == '.' && numbersSeen < 4) pointer++;
5245                   else return;
5246                 }
5247                 if (!DIGIT.test(char())) return;
5248                 while (DIGIT.test(char())) {
5249                   number = parseInt(char(), 10);
5250                   if (ipv4Piece === null) ipv4Piece = number;
5251                   else if (ipv4Piece == 0) return;
5252                   else ipv4Piece = ipv4Piece * 10 + number;
5253                   if (ipv4Piece > 255) return;
5254                   pointer++;
5255                 }
5256                 address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
5257                 numbersSeen++;
5258                 if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
5259               }
5260               if (numbersSeen != 4) return;
5261               break;
5262             } else if (char() == ':') {
5263               pointer++;
5264               if (!char()) return;
5265             } else if (char()) return;
5266             address[pieceIndex++] = value;
5267           }
5268           if (compress !== null) {
5269             swaps = pieceIndex - compress;
5270             pieceIndex = 7;
5271             while (pieceIndex != 0 && swaps > 0) {
5272               swap = address[pieceIndex];
5273               address[pieceIndex--] = address[compress + swaps - 1];
5274               address[compress + --swaps] = swap;
5275             }
5276           } else if (pieceIndex != 8) return;
5277           return address;
5278         };
5279
5280         var findLongestZeroSequence = function (ipv6) {
5281           var maxIndex = null;
5282           var maxLength = 1;
5283           var currStart = null;
5284           var currLength = 0;
5285           var index = 0;
5286           for (; index < 8; index++) {
5287             if (ipv6[index] !== 0) {
5288               if (currLength > maxLength) {
5289                 maxIndex = currStart;
5290                 maxLength = currLength;
5291               }
5292               currStart = null;
5293               currLength = 0;
5294             } else {
5295               if (currStart === null) currStart = index;
5296               ++currLength;
5297             }
5298           }
5299           if (currLength > maxLength) {
5300             maxIndex = currStart;
5301             maxLength = currLength;
5302           }
5303           return maxIndex;
5304         };
5305
5306         var serializeHost = function (host) {
5307           var result, index, compress, ignore0;
5308           // ipv4
5309           if (typeof host == 'number') {
5310             result = [];
5311             for (index = 0; index < 4; index++) {
5312               result.unshift(host % 256);
5313               host = floor$5(host / 256);
5314             } return result.join('.');
5315           // ipv6
5316           } else if (typeof host == 'object') {
5317             result = '';
5318             compress = findLongestZeroSequence(host);
5319             for (index = 0; index < 8; index++) {
5320               if (ignore0 && host[index] === 0) continue;
5321               if (ignore0) ignore0 = false;
5322               if (compress === index) {
5323                 result += index ? ':' : '::';
5324                 ignore0 = true;
5325               } else {
5326                 result += host[index].toString(16);
5327                 if (index < 7) result += ':';
5328               }
5329             }
5330             return '[' + result + ']';
5331           } return host;
5332         };
5333
5334         var C0ControlPercentEncodeSet = {};
5335         var fragmentPercentEncodeSet = objectAssign({}, C0ControlPercentEncodeSet, {
5336           ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
5337         });
5338         var pathPercentEncodeSet = objectAssign({}, fragmentPercentEncodeSet, {
5339           '#': 1, '?': 1, '{': 1, '}': 1
5340         });
5341         var userinfoPercentEncodeSet = objectAssign({}, pathPercentEncodeSet, {
5342           '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
5343         });
5344
5345         var percentEncode = function (char, set) {
5346           var code = codeAt(char, 0);
5347           return code > 0x20 && code < 0x7F && !has(set, char) ? char : encodeURIComponent(char);
5348         };
5349
5350         var specialSchemes = {
5351           ftp: 21,
5352           file: null,
5353           http: 80,
5354           https: 443,
5355           ws: 80,
5356           wss: 443
5357         };
5358
5359         var isSpecial = function (url) {
5360           return has(specialSchemes, url.scheme);
5361         };
5362
5363         var includesCredentials = function (url) {
5364           return url.username != '' || url.password != '';
5365         };
5366
5367         var cannotHaveUsernamePasswordPort = function (url) {
5368           return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
5369         };
5370
5371         var isWindowsDriveLetter = function (string, normalized) {
5372           var second;
5373           return string.length == 2 && ALPHA.test(string.charAt(0))
5374             && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
5375         };
5376
5377         var startsWithWindowsDriveLetter = function (string) {
5378           var third;
5379           return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
5380             string.length == 2 ||
5381             ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
5382           );
5383         };
5384
5385         var shortenURLsPath = function (url) {
5386           var path = url.path;
5387           var pathSize = path.length;
5388           if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
5389             path.pop();
5390           }
5391         };
5392
5393         var isSingleDot = function (segment) {
5394           return segment === '.' || segment.toLowerCase() === '%2e';
5395         };
5396
5397         var isDoubleDot = function (segment) {
5398           segment = segment.toLowerCase();
5399           return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
5400         };
5401
5402         // States:
5403         var SCHEME_START = {};
5404         var SCHEME = {};
5405         var NO_SCHEME = {};
5406         var SPECIAL_RELATIVE_OR_AUTHORITY = {};
5407         var PATH_OR_AUTHORITY = {};
5408         var RELATIVE = {};
5409         var RELATIVE_SLASH = {};
5410         var SPECIAL_AUTHORITY_SLASHES = {};
5411         var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
5412         var AUTHORITY = {};
5413         var HOST = {};
5414         var HOSTNAME = {};
5415         var PORT = {};
5416         var FILE = {};
5417         var FILE_SLASH = {};
5418         var FILE_HOST = {};
5419         var PATH_START = {};
5420         var PATH = {};
5421         var CANNOT_BE_A_BASE_URL_PATH = {};
5422         var QUERY = {};
5423         var FRAGMENT = {};
5424
5425         // eslint-disable-next-line max-statements
5426         var parseURL = function (url, input, stateOverride, base) {
5427           var state = stateOverride || SCHEME_START;
5428           var pointer = 0;
5429           var buffer = '';
5430           var seenAt = false;
5431           var seenBracket = false;
5432           var seenPasswordToken = false;
5433           var codePoints, char, bufferCodePoints, failure;
5434
5435           if (!stateOverride) {
5436             url.scheme = '';
5437             url.username = '';
5438             url.password = '';
5439             url.host = null;
5440             url.port = null;
5441             url.path = [];
5442             url.query = null;
5443             url.fragment = null;
5444             url.cannotBeABaseURL = false;
5445             input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
5446           }
5447
5448           input = input.replace(TAB_AND_NEW_LINE, '');
5449
5450           codePoints = arrayFrom(input);
5451
5452           while (pointer <= codePoints.length) {
5453             char = codePoints[pointer];
5454             switch (state) {
5455               case SCHEME_START:
5456                 if (char && ALPHA.test(char)) {
5457                   buffer += char.toLowerCase();
5458                   state = SCHEME;
5459                 } else if (!stateOverride) {
5460                   state = NO_SCHEME;
5461                   continue;
5462                 } else return INVALID_SCHEME;
5463                 break;
5464
5465               case SCHEME:
5466                 if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
5467                   buffer += char.toLowerCase();
5468                 } else if (char == ':') {
5469                   if (stateOverride && (
5470                     (isSpecial(url) != has(specialSchemes, buffer)) ||
5471                     (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
5472                     (url.scheme == 'file' && !url.host)
5473                   )) return;
5474                   url.scheme = buffer;
5475                   if (stateOverride) {
5476                     if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
5477                     return;
5478                   }
5479                   buffer = '';
5480                   if (url.scheme == 'file') {
5481                     state = FILE;
5482                   } else if (isSpecial(url) && base && base.scheme == url.scheme) {
5483                     state = SPECIAL_RELATIVE_OR_AUTHORITY;
5484                   } else if (isSpecial(url)) {
5485                     state = SPECIAL_AUTHORITY_SLASHES;
5486                   } else if (codePoints[pointer + 1] == '/') {
5487                     state = PATH_OR_AUTHORITY;
5488                     pointer++;
5489                   } else {
5490                     url.cannotBeABaseURL = true;
5491                     url.path.push('');
5492                     state = CANNOT_BE_A_BASE_URL_PATH;
5493                   }
5494                 } else if (!stateOverride) {
5495                   buffer = '';
5496                   state = NO_SCHEME;
5497                   pointer = 0;
5498                   continue;
5499                 } else return INVALID_SCHEME;
5500                 break;
5501
5502               case NO_SCHEME:
5503                 if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
5504                 if (base.cannotBeABaseURL && char == '#') {
5505                   url.scheme = base.scheme;
5506                   url.path = base.path.slice();
5507                   url.query = base.query;
5508                   url.fragment = '';
5509                   url.cannotBeABaseURL = true;
5510                   state = FRAGMENT;
5511                   break;
5512                 }
5513                 state = base.scheme == 'file' ? FILE : RELATIVE;
5514                 continue;
5515
5516               case SPECIAL_RELATIVE_OR_AUTHORITY:
5517                 if (char == '/' && codePoints[pointer + 1] == '/') {
5518                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5519                   pointer++;
5520                 } else {
5521                   state = RELATIVE;
5522                   continue;
5523                 } break;
5524
5525               case PATH_OR_AUTHORITY:
5526                 if (char == '/') {
5527                   state = AUTHORITY;
5528                   break;
5529                 } else {
5530                   state = PATH;
5531                   continue;
5532                 }
5533
5534               case RELATIVE:
5535                 url.scheme = base.scheme;
5536                 if (char == EOF) {
5537                   url.username = base.username;
5538                   url.password = base.password;
5539                   url.host = base.host;
5540                   url.port = base.port;
5541                   url.path = base.path.slice();
5542                   url.query = base.query;
5543                 } else if (char == '/' || (char == '\\' && isSpecial(url))) {
5544                   state = RELATIVE_SLASH;
5545                 } else if (char == '?') {
5546                   url.username = base.username;
5547                   url.password = base.password;
5548                   url.host = base.host;
5549                   url.port = base.port;
5550                   url.path = base.path.slice();
5551                   url.query = '';
5552                   state = QUERY;
5553                 } else if (char == '#') {
5554                   url.username = base.username;
5555                   url.password = base.password;
5556                   url.host = base.host;
5557                   url.port = base.port;
5558                   url.path = base.path.slice();
5559                   url.query = base.query;
5560                   url.fragment = '';
5561                   state = FRAGMENT;
5562                 } else {
5563                   url.username = base.username;
5564                   url.password = base.password;
5565                   url.host = base.host;
5566                   url.port = base.port;
5567                   url.path = base.path.slice();
5568                   url.path.pop();
5569                   state = PATH;
5570                   continue;
5571                 } break;
5572
5573               case RELATIVE_SLASH:
5574                 if (isSpecial(url) && (char == '/' || char == '\\')) {
5575                   state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5576                 } else if (char == '/') {
5577                   state = AUTHORITY;
5578                 } else {
5579                   url.username = base.username;
5580                   url.password = base.password;
5581                   url.host = base.host;
5582                   url.port = base.port;
5583                   state = PATH;
5584                   continue;
5585                 } break;
5586
5587               case SPECIAL_AUTHORITY_SLASHES:
5588                 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5589                 if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
5590                 pointer++;
5591                 break;
5592
5593               case SPECIAL_AUTHORITY_IGNORE_SLASHES:
5594                 if (char != '/' && char != '\\') {
5595                   state = AUTHORITY;
5596                   continue;
5597                 } break;
5598
5599               case AUTHORITY:
5600                 if (char == '@') {
5601                   if (seenAt) buffer = '%40' + buffer;
5602                   seenAt = true;
5603                   bufferCodePoints = arrayFrom(buffer);
5604                   for (var i = 0; i < bufferCodePoints.length; i++) {
5605                     var codePoint = bufferCodePoints[i];
5606                     if (codePoint == ':' && !seenPasswordToken) {
5607                       seenPasswordToken = true;
5608                       continue;
5609                     }
5610                     var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
5611                     if (seenPasswordToken) url.password += encodedCodePoints;
5612                     else url.username += encodedCodePoints;
5613                   }
5614                   buffer = '';
5615                 } else if (
5616                   char == EOF || char == '/' || char == '?' || char == '#' ||
5617                   (char == '\\' && isSpecial(url))
5618                 ) {
5619                   if (seenAt && buffer == '') return INVALID_AUTHORITY;
5620                   pointer -= arrayFrom(buffer).length + 1;
5621                   buffer = '';
5622                   state = HOST;
5623                 } else buffer += char;
5624                 break;
5625
5626               case HOST:
5627               case HOSTNAME:
5628                 if (stateOverride && url.scheme == 'file') {
5629                   state = FILE_HOST;
5630                   continue;
5631                 } else if (char == ':' && !seenBracket) {
5632                   if (buffer == '') return INVALID_HOST;
5633                   failure = parseHost(url, buffer);
5634                   if (failure) return failure;
5635                   buffer = '';
5636                   state = PORT;
5637                   if (stateOverride == HOSTNAME) return;
5638                 } else if (
5639                   char == EOF || char == '/' || char == '?' || char == '#' ||
5640                   (char == '\\' && isSpecial(url))
5641                 ) {
5642                   if (isSpecial(url) && buffer == '') return INVALID_HOST;
5643                   if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
5644                   failure = parseHost(url, buffer);
5645                   if (failure) return failure;
5646                   buffer = '';
5647                   state = PATH_START;
5648                   if (stateOverride) return;
5649                   continue;
5650                 } else {
5651                   if (char == '[') seenBracket = true;
5652                   else if (char == ']') seenBracket = false;
5653                   buffer += char;
5654                 } break;
5655
5656               case PORT:
5657                 if (DIGIT.test(char)) {
5658                   buffer += char;
5659                 } else if (
5660                   char == EOF || char == '/' || char == '?' || char == '#' ||
5661                   (char == '\\' && isSpecial(url)) ||
5662                   stateOverride
5663                 ) {
5664                   if (buffer != '') {
5665                     var port = parseInt(buffer, 10);
5666                     if (port > 0xFFFF) return INVALID_PORT;
5667                     url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
5668                     buffer = '';
5669                   }
5670                   if (stateOverride) return;
5671                   state = PATH_START;
5672                   continue;
5673                 } else return INVALID_PORT;
5674                 break;
5675
5676               case FILE:
5677                 url.scheme = 'file';
5678                 if (char == '/' || char == '\\') state = FILE_SLASH;
5679                 else if (base && base.scheme == 'file') {
5680                   if (char == EOF) {
5681                     url.host = base.host;
5682                     url.path = base.path.slice();
5683                     url.query = base.query;
5684                   } else if (char == '?') {
5685                     url.host = base.host;
5686                     url.path = base.path.slice();
5687                     url.query = '';
5688                     state = QUERY;
5689                   } else if (char == '#') {
5690                     url.host = base.host;
5691                     url.path = base.path.slice();
5692                     url.query = base.query;
5693                     url.fragment = '';
5694                     state = FRAGMENT;
5695                   } else {
5696                     if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5697                       url.host = base.host;
5698                       url.path = base.path.slice();
5699                       shortenURLsPath(url);
5700                     }
5701                     state = PATH;
5702                     continue;
5703                   }
5704                 } else {
5705                   state = PATH;
5706                   continue;
5707                 } break;
5708
5709               case FILE_SLASH:
5710                 if (char == '/' || char == '\\') {
5711                   state = FILE_HOST;
5712                   break;
5713                 }
5714                 if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5715                   if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
5716                   else url.host = base.host;
5717                 }
5718                 state = PATH;
5719                 continue;
5720
5721               case FILE_HOST:
5722                 if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
5723                   if (!stateOverride && isWindowsDriveLetter(buffer)) {
5724                     state = PATH;
5725                   } else if (buffer == '') {
5726                     url.host = '';
5727                     if (stateOverride) return;
5728                     state = PATH_START;
5729                   } else {
5730                     failure = parseHost(url, buffer);
5731                     if (failure) return failure;
5732                     if (url.host == 'localhost') url.host = '';
5733                     if (stateOverride) return;
5734                     buffer = '';
5735                     state = PATH_START;
5736                   } continue;
5737                 } else buffer += char;
5738                 break;
5739
5740               case PATH_START:
5741                 if (isSpecial(url)) {
5742                   state = PATH;
5743                   if (char != '/' && char != '\\') continue;
5744                 } else if (!stateOverride && char == '?') {
5745                   url.query = '';
5746                   state = QUERY;
5747                 } else if (!stateOverride && char == '#') {
5748                   url.fragment = '';
5749                   state = FRAGMENT;
5750                 } else if (char != EOF) {
5751                   state = PATH;
5752                   if (char != '/') continue;
5753                 } break;
5754
5755               case PATH:
5756                 if (
5757                   char == EOF || char == '/' ||
5758                   (char == '\\' && isSpecial(url)) ||
5759                   (!stateOverride && (char == '?' || char == '#'))
5760                 ) {
5761                   if (isDoubleDot(buffer)) {
5762                     shortenURLsPath(url);
5763                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5764                       url.path.push('');
5765                     }
5766                   } else if (isSingleDot(buffer)) {
5767                     if (char != '/' && !(char == '\\' && isSpecial(url))) {
5768                       url.path.push('');
5769                     }
5770                   } else {
5771                     if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
5772                       if (url.host) url.host = '';
5773                       buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
5774                     }
5775                     url.path.push(buffer);
5776                   }
5777                   buffer = '';
5778                   if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
5779                     while (url.path.length > 1 && url.path[0] === '') {
5780                       url.path.shift();
5781                     }
5782                   }
5783                   if (char == '?') {
5784                     url.query = '';
5785                     state = QUERY;
5786                   } else if (char == '#') {
5787                     url.fragment = '';
5788                     state = FRAGMENT;
5789                   }
5790                 } else {
5791                   buffer += percentEncode(char, pathPercentEncodeSet);
5792                 } break;
5793
5794               case CANNOT_BE_A_BASE_URL_PATH:
5795                 if (char == '?') {
5796                   url.query = '';
5797                   state = QUERY;
5798                 } else if (char == '#') {
5799                   url.fragment = '';
5800                   state = FRAGMENT;
5801                 } else if (char != EOF) {
5802                   url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
5803                 } break;
5804
5805               case QUERY:
5806                 if (!stateOverride && char == '#') {
5807                   url.fragment = '';
5808                   state = FRAGMENT;
5809                 } else if (char != EOF) {
5810                   if (char == "'" && isSpecial(url)) url.query += '%27';
5811                   else if (char == '#') url.query += '%23';
5812                   else url.query += percentEncode(char, C0ControlPercentEncodeSet);
5813                 } break;
5814
5815               case FRAGMENT:
5816                 if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
5817                 break;
5818             }
5819
5820             pointer++;
5821           }
5822         };
5823
5824         // `URL` constructor
5825         // https://url.spec.whatwg.org/#url-class
5826         var URLConstructor = function URL(url /* , base */) {
5827           var that = anInstance(this, URLConstructor, 'URL');
5828           var base = arguments.length > 1 ? arguments[1] : undefined;
5829           var urlString = String(url);
5830           var state = setInternalState$6(that, { type: 'URL' });
5831           var baseState, failure;
5832           if (base !== undefined) {
5833             if (base instanceof URLConstructor) baseState = getInternalURLState(base);
5834             else {
5835               failure = parseURL(baseState = {}, String(base));
5836               if (failure) throw TypeError(failure);
5837             }
5838           }
5839           failure = parseURL(state, urlString, null, baseState);
5840           if (failure) throw TypeError(failure);
5841           var searchParams = state.searchParams = new URLSearchParams$1();
5842           var searchParamsState = getInternalSearchParamsState(searchParams);
5843           searchParamsState.updateSearchParams(state.query);
5844           searchParamsState.updateURL = function () {
5845             state.query = String(searchParams) || null;
5846           };
5847           if (!descriptors) {
5848             that.href = serializeURL.call(that);
5849             that.origin = getOrigin.call(that);
5850             that.protocol = getProtocol.call(that);
5851             that.username = getUsername.call(that);
5852             that.password = getPassword.call(that);
5853             that.host = getHost.call(that);
5854             that.hostname = getHostname.call(that);
5855             that.port = getPort.call(that);
5856             that.pathname = getPathname.call(that);
5857             that.search = getSearch.call(that);
5858             that.searchParams = getSearchParams.call(that);
5859             that.hash = getHash.call(that);
5860           }
5861         };
5862
5863         var URLPrototype = URLConstructor.prototype;
5864
5865         var serializeURL = function () {
5866           var url = getInternalURLState(this);
5867           var scheme = url.scheme;
5868           var username = url.username;
5869           var password = url.password;
5870           var host = url.host;
5871           var port = url.port;
5872           var path = url.path;
5873           var query = url.query;
5874           var fragment = url.fragment;
5875           var output = scheme + ':';
5876           if (host !== null) {
5877             output += '//';
5878             if (includesCredentials(url)) {
5879               output += username + (password ? ':' + password : '') + '@';
5880             }
5881             output += serializeHost(host);
5882             if (port !== null) output += ':' + port;
5883           } else if (scheme == 'file') output += '//';
5884           output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5885           if (query !== null) output += '?' + query;
5886           if (fragment !== null) output += '#' + fragment;
5887           return output;
5888         };
5889
5890         var getOrigin = function () {
5891           var url = getInternalURLState(this);
5892           var scheme = url.scheme;
5893           var port = url.port;
5894           if (scheme == 'blob') try {
5895             return new URL(scheme.path[0]).origin;
5896           } catch (error) {
5897             return 'null';
5898           }
5899           if (scheme == 'file' || !isSpecial(url)) return 'null';
5900           return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
5901         };
5902
5903         var getProtocol = function () {
5904           return getInternalURLState(this).scheme + ':';
5905         };
5906
5907         var getUsername = function () {
5908           return getInternalURLState(this).username;
5909         };
5910
5911         var getPassword = function () {
5912           return getInternalURLState(this).password;
5913         };
5914
5915         var getHost = function () {
5916           var url = getInternalURLState(this);
5917           var host = url.host;
5918           var port = url.port;
5919           return host === null ? ''
5920             : port === null ? serializeHost(host)
5921             : serializeHost(host) + ':' + port;
5922         };
5923
5924         var getHostname = function () {
5925           var host = getInternalURLState(this).host;
5926           return host === null ? '' : serializeHost(host);
5927         };
5928
5929         var getPort = function () {
5930           var port = getInternalURLState(this).port;
5931           return port === null ? '' : String(port);
5932         };
5933
5934         var getPathname = function () {
5935           var url = getInternalURLState(this);
5936           var path = url.path;
5937           return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
5938         };
5939
5940         var getSearch = function () {
5941           var query = getInternalURLState(this).query;
5942           return query ? '?' + query : '';
5943         };
5944
5945         var getSearchParams = function () {
5946           return getInternalURLState(this).searchParams;
5947         };
5948
5949         var getHash = function () {
5950           var fragment = getInternalURLState(this).fragment;
5951           return fragment ? '#' + fragment : '';
5952         };
5953
5954         var accessorDescriptor = function (getter, setter) {
5955           return { get: getter, set: setter, configurable: true, enumerable: true };
5956         };
5957
5958         if (descriptors) {
5959           objectDefineProperties(URLPrototype, {
5960             // `URL.prototype.href` accessors pair
5961             // https://url.spec.whatwg.org/#dom-url-href
5962             href: accessorDescriptor(serializeURL, function (href) {
5963               var url = getInternalURLState(this);
5964               var urlString = String(href);
5965               var failure = parseURL(url, urlString);
5966               if (failure) throw TypeError(failure);
5967               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
5968             }),
5969             // `URL.prototype.origin` getter
5970             // https://url.spec.whatwg.org/#dom-url-origin
5971             origin: accessorDescriptor(getOrigin),
5972             // `URL.prototype.protocol` accessors pair
5973             // https://url.spec.whatwg.org/#dom-url-protocol
5974             protocol: accessorDescriptor(getProtocol, function (protocol) {
5975               var url = getInternalURLState(this);
5976               parseURL(url, String(protocol) + ':', SCHEME_START);
5977             }),
5978             // `URL.prototype.username` accessors pair
5979             // https://url.spec.whatwg.org/#dom-url-username
5980             username: accessorDescriptor(getUsername, function (username) {
5981               var url = getInternalURLState(this);
5982               var codePoints = arrayFrom(String(username));
5983               if (cannotHaveUsernamePasswordPort(url)) return;
5984               url.username = '';
5985               for (var i = 0; i < codePoints.length; i++) {
5986                 url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5987               }
5988             }),
5989             // `URL.prototype.password` accessors pair
5990             // https://url.spec.whatwg.org/#dom-url-password
5991             password: accessorDescriptor(getPassword, function (password) {
5992               var url = getInternalURLState(this);
5993               var codePoints = arrayFrom(String(password));
5994               if (cannotHaveUsernamePasswordPort(url)) return;
5995               url.password = '';
5996               for (var i = 0; i < codePoints.length; i++) {
5997                 url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
5998               }
5999             }),
6000             // `URL.prototype.host` accessors pair
6001             // https://url.spec.whatwg.org/#dom-url-host
6002             host: accessorDescriptor(getHost, function (host) {
6003               var url = getInternalURLState(this);
6004               if (url.cannotBeABaseURL) return;
6005               parseURL(url, String(host), HOST);
6006             }),
6007             // `URL.prototype.hostname` accessors pair
6008             // https://url.spec.whatwg.org/#dom-url-hostname
6009             hostname: accessorDescriptor(getHostname, function (hostname) {
6010               var url = getInternalURLState(this);
6011               if (url.cannotBeABaseURL) return;
6012               parseURL(url, String(hostname), HOSTNAME);
6013             }),
6014             // `URL.prototype.port` accessors pair
6015             // https://url.spec.whatwg.org/#dom-url-port
6016             port: accessorDescriptor(getPort, function (port) {
6017               var url = getInternalURLState(this);
6018               if (cannotHaveUsernamePasswordPort(url)) return;
6019               port = String(port);
6020               if (port == '') url.port = null;
6021               else parseURL(url, port, PORT);
6022             }),
6023             // `URL.prototype.pathname` accessors pair
6024             // https://url.spec.whatwg.org/#dom-url-pathname
6025             pathname: accessorDescriptor(getPathname, function (pathname) {
6026               var url = getInternalURLState(this);
6027               if (url.cannotBeABaseURL) return;
6028               url.path = [];
6029               parseURL(url, pathname + '', PATH_START);
6030             }),
6031             // `URL.prototype.search` accessors pair
6032             // https://url.spec.whatwg.org/#dom-url-search
6033             search: accessorDescriptor(getSearch, function (search) {
6034               var url = getInternalURLState(this);
6035               search = String(search);
6036               if (search == '') {
6037                 url.query = null;
6038               } else {
6039                 if ('?' == search.charAt(0)) search = search.slice(1);
6040                 url.query = '';
6041                 parseURL(url, search, QUERY);
6042               }
6043               getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
6044             }),
6045             // `URL.prototype.searchParams` getter
6046             // https://url.spec.whatwg.org/#dom-url-searchparams
6047             searchParams: accessorDescriptor(getSearchParams),
6048             // `URL.prototype.hash` accessors pair
6049             // https://url.spec.whatwg.org/#dom-url-hash
6050             hash: accessorDescriptor(getHash, function (hash) {
6051               var url = getInternalURLState(this);
6052               hash = String(hash);
6053               if (hash == '') {
6054                 url.fragment = null;
6055                 return;
6056               }
6057               if ('#' == hash.charAt(0)) hash = hash.slice(1);
6058               url.fragment = '';
6059               parseURL(url, hash, FRAGMENT);
6060             })
6061           });
6062         }
6063
6064         // `URL.prototype.toJSON` method
6065         // https://url.spec.whatwg.org/#dom-url-tojson
6066         redefine(URLPrototype, 'toJSON', function toJSON() {
6067           return serializeURL.call(this);
6068         }, { enumerable: true });
6069
6070         // `URL.prototype.toString` method
6071         // https://url.spec.whatwg.org/#URL-stringification-behavior
6072         redefine(URLPrototype, 'toString', function toString() {
6073           return serializeURL.call(this);
6074         }, { enumerable: true });
6075
6076         if (NativeURL) {
6077           var nativeCreateObjectURL = NativeURL.createObjectURL;
6078           var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
6079           // `URL.createObjectURL` method
6080           // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
6081           // eslint-disable-next-line no-unused-vars
6082           if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
6083             return nativeCreateObjectURL.apply(NativeURL, arguments);
6084           });
6085           // `URL.revokeObjectURL` method
6086           // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
6087           // eslint-disable-next-line no-unused-vars
6088           if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
6089             return nativeRevokeObjectURL.apply(NativeURL, arguments);
6090           });
6091         }
6092
6093         setToStringTag(URLConstructor, 'URL');
6094
6095         _export({ global: true, forced: !nativeUrl, sham: !descriptors }, {
6096           URL: URLConstructor
6097         });
6098
6099         function _typeof(obj) {
6100           "@babel/helpers - typeof";
6101
6102           if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
6103             _typeof = function (obj) {
6104               return typeof obj;
6105             };
6106           } else {
6107             _typeof = function (obj) {
6108               return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
6109             };
6110           }
6111
6112           return _typeof(obj);
6113         }
6114
6115         function _classCallCheck(instance, Constructor) {
6116           if (!(instance instanceof Constructor)) {
6117             throw new TypeError("Cannot call a class as a function");
6118           }
6119         }
6120
6121         function _defineProperties(target, props) {
6122           for (var i = 0; i < props.length; i++) {
6123             var descriptor = props[i];
6124             descriptor.enumerable = descriptor.enumerable || false;
6125             descriptor.configurable = true;
6126             if ("value" in descriptor) descriptor.writable = true;
6127             Object.defineProperty(target, descriptor.key, descriptor);
6128           }
6129         }
6130
6131         function _createClass(Constructor, protoProps, staticProps) {
6132           if (protoProps) _defineProperties(Constructor.prototype, protoProps);
6133           if (staticProps) _defineProperties(Constructor, staticProps);
6134           return Constructor;
6135         }
6136
6137         function _defineProperty(obj, key, value) {
6138           if (key in obj) {
6139             Object.defineProperty(obj, key, {
6140               value: value,
6141               enumerable: true,
6142               configurable: true,
6143               writable: true
6144             });
6145           } else {
6146             obj[key] = value;
6147           }
6148
6149           return obj;
6150         }
6151
6152         function _slicedToArray(arr, i) {
6153           return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
6154         }
6155
6156         function _toConsumableArray(arr) {
6157           return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
6158         }
6159
6160         function _arrayWithoutHoles(arr) {
6161           if (Array.isArray(arr)) return _arrayLikeToArray(arr);
6162         }
6163
6164         function _arrayWithHoles(arr) {
6165           if (Array.isArray(arr)) return arr;
6166         }
6167
6168         function _iterableToArray(iter) {
6169           if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
6170         }
6171
6172         function _iterableToArrayLimit(arr, i) {
6173           if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
6174           var _arr = [];
6175           var _n = true;
6176           var _d = false;
6177           var _e = undefined;
6178
6179           try {
6180             for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
6181               _arr.push(_s.value);
6182
6183               if (i && _arr.length === i) break;
6184             }
6185           } catch (err) {
6186             _d = true;
6187             _e = err;
6188           } finally {
6189             try {
6190               if (!_n && _i["return"] != null) _i["return"]();
6191             } finally {
6192               if (_d) throw _e;
6193             }
6194           }
6195
6196           return _arr;
6197         }
6198
6199         function _unsupportedIterableToArray(o, minLen) {
6200           if (!o) return;
6201           if (typeof o === "string") return _arrayLikeToArray(o, minLen);
6202           var n = Object.prototype.toString.call(o).slice(8, -1);
6203           if (n === "Object" && o.constructor) n = o.constructor.name;
6204           if (n === "Map" || n === "Set") return Array.from(o);
6205           if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
6206         }
6207
6208         function _arrayLikeToArray(arr, len) {
6209           if (len == null || len > arr.length) len = arr.length;
6210
6211           for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
6212
6213           return arr2;
6214         }
6215
6216         function _nonIterableSpread() {
6217           throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
6218         }
6219
6220         function _nonIterableRest() {
6221           throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
6222         }
6223
6224         function _createForOfIteratorHelper(o, allowArrayLike) {
6225           var it;
6226
6227           if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
6228             if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
6229               if (it) o = it;
6230               var i = 0;
6231
6232               var F = function () {};
6233
6234               return {
6235                 s: F,
6236                 n: function () {
6237                   if (i >= o.length) return {
6238                     done: true
6239                   };
6240                   return {
6241                     done: false,
6242                     value: o[i++]
6243                   };
6244                 },
6245                 e: function (e) {
6246                   throw e;
6247                 },
6248                 f: F
6249               };
6250             }
6251
6252             throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
6253           }
6254
6255           var normalCompletion = true,
6256               didErr = false,
6257               err;
6258           return {
6259             s: function () {
6260               it = o[Symbol.iterator]();
6261             },
6262             n: function () {
6263               var step = it.next();
6264               normalCompletion = step.done;
6265               return step;
6266             },
6267             e: function (e) {
6268               didErr = true;
6269               err = e;
6270             },
6271             f: function () {
6272               try {
6273                 if (!normalCompletion && it.return != null) it.return();
6274               } finally {
6275                 if (didErr) throw err;
6276               }
6277             }
6278           };
6279         }
6280
6281         var global$1 = typeof globalThis !== 'undefined' && globalThis || typeof self !== 'undefined' && self || typeof global$1 !== 'undefined' && global$1;
6282         var support = {
6283           searchParams: 'URLSearchParams' in global$1,
6284           iterable: 'Symbol' in global$1 && 'iterator' in Symbol,
6285           blob: 'FileReader' in global$1 && 'Blob' in global$1 && function () {
6286             try {
6287               new Blob();
6288               return true;
6289             } catch (e) {
6290               return false;
6291             }
6292           }(),
6293           formData: 'FormData' in global$1,
6294           arrayBuffer: 'ArrayBuffer' in global$1
6295         };
6296
6297         function isDataView(obj) {
6298           return obj && DataView.prototype.isPrototypeOf(obj);
6299         }
6300
6301         if (support.arrayBuffer) {
6302           var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
6303
6304           var isArrayBufferView = ArrayBuffer.isView || function (obj) {
6305             return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
6306           };
6307         }
6308
6309         function normalizeName(name) {
6310           if (typeof name !== 'string') {
6311             name = String(name);
6312           }
6313
6314           if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
6315             throw new TypeError('Invalid character in header field name');
6316           }
6317
6318           return name.toLowerCase();
6319         }
6320
6321         function normalizeValue(value) {
6322           if (typeof value !== 'string') {
6323             value = String(value);
6324           }
6325
6326           return value;
6327         } // Build a destructive iterator for the value list
6328
6329
6330         function iteratorFor(items) {
6331           var iterator = {
6332             next: function next() {
6333               var value = items.shift();
6334               return {
6335                 done: value === undefined,
6336                 value: value
6337               };
6338             }
6339           };
6340
6341           if (support.iterable) {
6342             iterator[Symbol.iterator] = function () {
6343               return iterator;
6344             };
6345           }
6346
6347           return iterator;
6348         }
6349
6350         function Headers$1(headers) {
6351           this.map = {};
6352
6353           if (headers instanceof Headers$1) {
6354             headers.forEach(function (value, name) {
6355               this.append(name, value);
6356             }, this);
6357           } else if (Array.isArray(headers)) {
6358             headers.forEach(function (header) {
6359               this.append(header[0], header[1]);
6360             }, this);
6361           } else if (headers) {
6362             Object.getOwnPropertyNames(headers).forEach(function (name) {
6363               this.append(name, headers[name]);
6364             }, this);
6365           }
6366         }
6367
6368         Headers$1.prototype.append = function (name, value) {
6369           name = normalizeName(name);
6370           value = normalizeValue(value);
6371           var oldValue = this.map[name];
6372           this.map[name] = oldValue ? oldValue + ', ' + value : value;
6373         };
6374
6375         Headers$1.prototype['delete'] = function (name) {
6376           delete this.map[normalizeName(name)];
6377         };
6378
6379         Headers$1.prototype.get = function (name) {
6380           name = normalizeName(name);
6381           return this.has(name) ? this.map[name] : null;
6382         };
6383
6384         Headers$1.prototype.has = function (name) {
6385           return this.map.hasOwnProperty(normalizeName(name));
6386         };
6387
6388         Headers$1.prototype.set = function (name, value) {
6389           this.map[normalizeName(name)] = normalizeValue(value);
6390         };
6391
6392         Headers$1.prototype.forEach = function (callback, thisArg) {
6393           for (var name in this.map) {
6394             if (this.map.hasOwnProperty(name)) {
6395               callback.call(thisArg, this.map[name], name, this);
6396             }
6397           }
6398         };
6399
6400         Headers$1.prototype.keys = function () {
6401           var items = [];
6402           this.forEach(function (value, name) {
6403             items.push(name);
6404           });
6405           return iteratorFor(items);
6406         };
6407
6408         Headers$1.prototype.values = function () {
6409           var items = [];
6410           this.forEach(function (value) {
6411             items.push(value);
6412           });
6413           return iteratorFor(items);
6414         };
6415
6416         Headers$1.prototype.entries = function () {
6417           var items = [];
6418           this.forEach(function (value, name) {
6419             items.push([name, value]);
6420           });
6421           return iteratorFor(items);
6422         };
6423
6424         if (support.iterable) {
6425           Headers$1.prototype[Symbol.iterator] = Headers$1.prototype.entries;
6426         }
6427
6428         function consumed(body) {
6429           if (body.bodyUsed) {
6430             return Promise.reject(new TypeError('Already read'));
6431           }
6432
6433           body.bodyUsed = true;
6434         }
6435
6436         function fileReaderReady(reader) {
6437           return new Promise(function (resolve, reject) {
6438             reader.onload = function () {
6439               resolve(reader.result);
6440             };
6441
6442             reader.onerror = function () {
6443               reject(reader.error);
6444             };
6445           });
6446         }
6447
6448         function readBlobAsArrayBuffer(blob) {
6449           var reader = new FileReader();
6450           var promise = fileReaderReady(reader);
6451           reader.readAsArrayBuffer(blob);
6452           return promise;
6453         }
6454
6455         function readBlobAsText(blob) {
6456           var reader = new FileReader();
6457           var promise = fileReaderReady(reader);
6458           reader.readAsText(blob);
6459           return promise;
6460         }
6461
6462         function readArrayBufferAsText(buf) {
6463           var view = new Uint8Array(buf);
6464           var chars = new Array(view.length);
6465
6466           for (var i = 0; i < view.length; i++) {
6467             chars[i] = String.fromCharCode(view[i]);
6468           }
6469
6470           return chars.join('');
6471         }
6472
6473         function bufferClone(buf) {
6474           if (buf.slice) {
6475             return buf.slice(0);
6476           } else {
6477             var view = new Uint8Array(buf.byteLength);
6478             view.set(new Uint8Array(buf));
6479             return view.buffer;
6480           }
6481         }
6482
6483         function Body() {
6484           this.bodyUsed = false;
6485
6486           this._initBody = function (body) {
6487             /*
6488               fetch-mock wraps the Response object in an ES6 Proxy to
6489               provide useful test harness features such as flush. However, on
6490               ES5 browsers without fetch or Proxy support pollyfills must be used;
6491               the proxy-pollyfill is unable to proxy an attribute unless it exists
6492               on the object before the Proxy is created. This change ensures
6493               Response.bodyUsed exists on the instance, while maintaining the
6494               semantic of setting Request.bodyUsed in the constructor before
6495               _initBody is called.
6496             */
6497             this.bodyUsed = this.bodyUsed;
6498             this._bodyInit = body;
6499
6500             if (!body) {
6501               this._bodyText = '';
6502             } else if (typeof body === 'string') {
6503               this._bodyText = body;
6504             } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
6505               this._bodyBlob = body;
6506             } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
6507               this._bodyFormData = body;
6508             } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6509               this._bodyText = body.toString();
6510             } else if (support.arrayBuffer && support.blob && isDataView(body)) {
6511               this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.
6512
6513               this._bodyInit = new Blob([this._bodyArrayBuffer]);
6514             } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
6515               this._bodyArrayBuffer = bufferClone(body);
6516             } else {
6517               this._bodyText = body = Object.prototype.toString.call(body);
6518             }
6519
6520             if (!this.headers.get('content-type')) {
6521               if (typeof body === 'string') {
6522                 this.headers.set('content-type', 'text/plain;charset=UTF-8');
6523               } else if (this._bodyBlob && this._bodyBlob.type) {
6524                 this.headers.set('content-type', this._bodyBlob.type);
6525               } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
6526                 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
6527               }
6528             }
6529           };
6530
6531           if (support.blob) {
6532             this.blob = function () {
6533               var rejected = consumed(this);
6534
6535               if (rejected) {
6536                 return rejected;
6537               }
6538
6539               if (this._bodyBlob) {
6540                 return Promise.resolve(this._bodyBlob);
6541               } else if (this._bodyArrayBuffer) {
6542                 return Promise.resolve(new Blob([this._bodyArrayBuffer]));
6543               } else if (this._bodyFormData) {
6544                 throw new Error('could not read FormData body as blob');
6545               } else {
6546                 return Promise.resolve(new Blob([this._bodyText]));
6547               }
6548             };
6549
6550             this.arrayBuffer = function () {
6551               if (this._bodyArrayBuffer) {
6552                 var isConsumed = consumed(this);
6553
6554                 if (isConsumed) {
6555                   return isConsumed;
6556                 }
6557
6558                 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
6559                   return Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength));
6560                 } else {
6561                   return Promise.resolve(this._bodyArrayBuffer);
6562                 }
6563               } else {
6564                 return this.blob().then(readBlobAsArrayBuffer);
6565               }
6566             };
6567           }
6568
6569           this.text = function () {
6570             var rejected = consumed(this);
6571
6572             if (rejected) {
6573               return rejected;
6574             }
6575
6576             if (this._bodyBlob) {
6577               return readBlobAsText(this._bodyBlob);
6578             } else if (this._bodyArrayBuffer) {
6579               return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
6580             } else if (this._bodyFormData) {
6581               throw new Error('could not read FormData body as text');
6582             } else {
6583               return Promise.resolve(this._bodyText);
6584             }
6585           };
6586
6587           if (support.formData) {
6588             this.formData = function () {
6589               return this.text().then(decode);
6590             };
6591           }
6592
6593           this.json = function () {
6594             return this.text().then(JSON.parse);
6595           };
6596
6597           return this;
6598         } // HTTP methods whose capitalization should be normalized
6599
6600
6601         var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
6602
6603         function normalizeMethod(method) {
6604           var upcased = method.toUpperCase();
6605           return methods.indexOf(upcased) > -1 ? upcased : method;
6606         }
6607
6608         function Request(input, options) {
6609           if (!(this instanceof Request)) {
6610             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6611           }
6612
6613           options = options || {};
6614           var body = options.body;
6615
6616           if (input instanceof Request) {
6617             if (input.bodyUsed) {
6618               throw new TypeError('Already read');
6619             }
6620
6621             this.url = input.url;
6622             this.credentials = input.credentials;
6623
6624             if (!options.headers) {
6625               this.headers = new Headers$1(input.headers);
6626             }
6627
6628             this.method = input.method;
6629             this.mode = input.mode;
6630             this.signal = input.signal;
6631
6632             if (!body && input._bodyInit != null) {
6633               body = input._bodyInit;
6634               input.bodyUsed = true;
6635             }
6636           } else {
6637             this.url = String(input);
6638           }
6639
6640           this.credentials = options.credentials || this.credentials || 'same-origin';
6641
6642           if (options.headers || !this.headers) {
6643             this.headers = new Headers$1(options.headers);
6644           }
6645
6646           this.method = normalizeMethod(options.method || this.method || 'GET');
6647           this.mode = options.mode || this.mode || null;
6648           this.signal = options.signal || this.signal;
6649           this.referrer = null;
6650
6651           if ((this.method === 'GET' || this.method === 'HEAD') && body) {
6652             throw new TypeError('Body not allowed for GET or HEAD requests');
6653           }
6654
6655           this._initBody(body);
6656
6657           if (this.method === 'GET' || this.method === 'HEAD') {
6658             if (options.cache === 'no-store' || options.cache === 'no-cache') {
6659               // Search for a '_' parameter in the query string
6660               var reParamSearch = /([?&])_=[^&]*/;
6661
6662               if (reParamSearch.test(this.url)) {
6663                 // If it already exists then set the value with the current time
6664                 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
6665               } else {
6666                 // Otherwise add a new '_' parameter to the end with the current time
6667                 var reQueryString = /\?/;
6668                 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
6669               }
6670             }
6671           }
6672         }
6673
6674         Request.prototype.clone = function () {
6675           return new Request(this, {
6676             body: this._bodyInit
6677           });
6678         };
6679
6680         function decode(body) {
6681           var form = new FormData();
6682           body.trim().split('&').forEach(function (bytes) {
6683             if (bytes) {
6684               var split = bytes.split('=');
6685               var name = split.shift().replace(/\+/g, ' ');
6686               var value = split.join('=').replace(/\+/g, ' ');
6687               form.append(decodeURIComponent(name), decodeURIComponent(value));
6688             }
6689           });
6690           return form;
6691         }
6692
6693         function parseHeaders(rawHeaders) {
6694           var headers = new Headers$1(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
6695           // https://tools.ietf.org/html/rfc7230#section-3.2
6696
6697           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
6698           // https://github.com/github/fetch/issues/748
6699           // https://github.com/zloirock/core-js/issues/751
6700
6701           preProcessedHeaders.split('\r').map(function (header) {
6702             return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header;
6703           }).forEach(function (line) {
6704             var parts = line.split(':');
6705             var key = parts.shift().trim();
6706
6707             if (key) {
6708               var value = parts.join(':').trim();
6709               headers.append(key, value);
6710             }
6711           });
6712           return headers;
6713         }
6714
6715         Body.call(Request.prototype);
6716         function Response(bodyInit, options) {
6717           if (!(this instanceof Response)) {
6718             throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
6719           }
6720
6721           if (!options) {
6722             options = {};
6723           }
6724
6725           this.type = 'default';
6726           this.status = options.status === undefined ? 200 : options.status;
6727           this.ok = this.status >= 200 && this.status < 300;
6728           this.statusText = 'statusText' in options ? options.statusText : '';
6729           this.headers = new Headers$1(options.headers);
6730           this.url = options.url || '';
6731
6732           this._initBody(bodyInit);
6733         }
6734         Body.call(Response.prototype);
6735
6736         Response.prototype.clone = function () {
6737           return new Response(this._bodyInit, {
6738             status: this.status,
6739             statusText: this.statusText,
6740             headers: new Headers$1(this.headers),
6741             url: this.url
6742           });
6743         };
6744
6745         Response.error = function () {
6746           var response = new Response(null, {
6747             status: 0,
6748             statusText: ''
6749           });
6750           response.type = 'error';
6751           return response;
6752         };
6753
6754         var redirectStatuses = [301, 302, 303, 307, 308];
6755
6756         Response.redirect = function (url, status) {
6757           if (redirectStatuses.indexOf(status) === -1) {
6758             throw new RangeError('Invalid status code');
6759           }
6760
6761           return new Response(null, {
6762             status: status,
6763             headers: {
6764               location: url
6765             }
6766           });
6767         };
6768
6769         var DOMException$1 = global$1.DOMException;
6770
6771         try {
6772           new DOMException$1();
6773         } catch (err) {
6774           DOMException$1 = function DOMException(message, name) {
6775             this.message = message;
6776             this.name = name;
6777             var error = Error(message);
6778             this.stack = error.stack;
6779           };
6780
6781           DOMException$1.prototype = Object.create(Error.prototype);
6782           DOMException$1.prototype.constructor = DOMException$1;
6783         }
6784
6785         function fetch$1(input, init) {
6786           return new Promise(function (resolve, reject) {
6787             var request = new Request(input, init);
6788
6789             if (request.signal && request.signal.aborted) {
6790               return reject(new DOMException$1('Aborted', 'AbortError'));
6791             }
6792
6793             var xhr = new XMLHttpRequest();
6794
6795             function abortXhr() {
6796               xhr.abort();
6797             }
6798
6799             xhr.onload = function () {
6800               var options = {
6801                 status: xhr.status,
6802                 statusText: xhr.statusText,
6803                 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
6804               };
6805               options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
6806               var body = 'response' in xhr ? xhr.response : xhr.responseText;
6807               setTimeout(function () {
6808                 resolve(new Response(body, options));
6809               }, 0);
6810             };
6811
6812             xhr.onerror = function () {
6813               setTimeout(function () {
6814                 reject(new TypeError('Network request failed'));
6815               }, 0);
6816             };
6817
6818             xhr.ontimeout = function () {
6819               setTimeout(function () {
6820                 reject(new TypeError('Network request failed'));
6821               }, 0);
6822             };
6823
6824             xhr.onabort = function () {
6825               setTimeout(function () {
6826                 reject(new DOMException$1('Aborted', 'AbortError'));
6827               }, 0);
6828             };
6829
6830             function fixUrl(url) {
6831               try {
6832                 return url === '' && global$1.location.href ? global$1.location.href : url;
6833               } catch (e) {
6834                 return url;
6835               }
6836             }
6837
6838             xhr.open(request.method, fixUrl(request.url), true);
6839
6840             if (request.credentials === 'include') {
6841               xhr.withCredentials = true;
6842             } else if (request.credentials === 'omit') {
6843               xhr.withCredentials = false;
6844             }
6845
6846             if ('responseType' in xhr) {
6847               if (support.blob) {
6848                 xhr.responseType = 'blob';
6849               } else if (support.arrayBuffer && request.headers.get('Content-Type') && request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1) {
6850                 xhr.responseType = 'arraybuffer';
6851               }
6852             }
6853
6854             if (init && _typeof(init.headers) === 'object' && !(init.headers instanceof Headers$1)) {
6855               Object.getOwnPropertyNames(init.headers).forEach(function (name) {
6856                 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
6857               });
6858             } else {
6859               request.headers.forEach(function (value, name) {
6860                 xhr.setRequestHeader(name, value);
6861               });
6862             }
6863
6864             if (request.signal) {
6865               request.signal.addEventListener('abort', abortXhr);
6866
6867               xhr.onreadystatechange = function () {
6868                 // DONE (success or failure)
6869                 if (xhr.readyState === 4) {
6870                   request.signal.removeEventListener('abort', abortXhr);
6871                 }
6872               };
6873             }
6874
6875             xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
6876           });
6877         }
6878         fetch$1.polyfill = true;
6879
6880         if (!global$1.fetch) {
6881           global$1.fetch = fetch$1;
6882           global$1.Headers = Headers$1;
6883           global$1.Request = Request;
6884           global$1.Response = Response;
6885         }
6886
6887         // `Symbol.toStringTag` well-known symbol
6888         // https://tc39.github.io/ecma262/#sec-symbol.tostringtag
6889         defineWellKnownSymbol('toStringTag');
6890
6891         var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('splice');
6892         var USES_TO_LENGTH$5 = arrayMethodUsesToLength('splice', { ACCESSORS: true, 0: 0, 1: 2 });
6893
6894         var max$3 = Math.max;
6895         var min$6 = Math.min;
6896         var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
6897         var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
6898
6899         // `Array.prototype.splice` method
6900         // https://tc39.github.io/ecma262/#sec-array.prototype.splice
6901         // with adding support of @@species
6902         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 || !USES_TO_LENGTH$5 }, {
6903           splice: function splice(start, deleteCount /* , ...items */) {
6904             var O = toObject(this);
6905             var len = toLength(O.length);
6906             var actualStart = toAbsoluteIndex(start, len);
6907             var argumentsLength = arguments.length;
6908             var insertCount, actualDeleteCount, A, k, from, to;
6909             if (argumentsLength === 0) {
6910               insertCount = actualDeleteCount = 0;
6911             } else if (argumentsLength === 1) {
6912               insertCount = 0;
6913               actualDeleteCount = len - actualStart;
6914             } else {
6915               insertCount = argumentsLength - 2;
6916               actualDeleteCount = min$6(max$3(toInteger(deleteCount), 0), len - actualStart);
6917             }
6918             if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
6919               throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
6920             }
6921             A = arraySpeciesCreate(O, actualDeleteCount);
6922             for (k = 0; k < actualDeleteCount; k++) {
6923               from = actualStart + k;
6924               if (from in O) createProperty(A, k, O[from]);
6925             }
6926             A.length = actualDeleteCount;
6927             if (insertCount < actualDeleteCount) {
6928               for (k = actualStart; k < len - actualDeleteCount; k++) {
6929                 from = k + actualDeleteCount;
6930                 to = k + insertCount;
6931                 if (from in O) O[to] = O[from];
6932                 else delete O[to];
6933               }
6934               for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
6935             } else if (insertCount > actualDeleteCount) {
6936               for (k = len - actualDeleteCount; k > actualStart; k--) {
6937                 from = k + actualDeleteCount - 1;
6938                 to = k + insertCount - 1;
6939                 if (from in O) O[to] = O[from];
6940                 else delete O[to];
6941               }
6942             }
6943             for (k = 0; k < insertCount; k++) {
6944               O[k + actualStart] = arguments[k + 2];
6945             }
6946             O.length = len - actualDeleteCount + insertCount;
6947             return A;
6948           }
6949         });
6950
6951         // JSON[@@toStringTag] property
6952         // https://tc39.github.io/ecma262/#sec-json-@@tostringtag
6953         setToStringTag(global_1.JSON, 'JSON', true);
6954
6955         // Math[@@toStringTag] property
6956         // https://tc39.github.io/ecma262/#sec-math-@@tostringtag
6957         setToStringTag(Math, 'Math', true);
6958
6959         // `Object.defineProperty` method
6960         // https://tc39.github.io/ecma262/#sec-object.defineproperty
6961         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
6962           defineProperty: objectDefineProperty.f
6963         });
6964
6965         var nativeGetOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
6966
6967
6968         var FAILS_ON_PRIMITIVES$1 = fails(function () { nativeGetOwnPropertyDescriptor$2(1); });
6969         var FORCED$5 = !descriptors || FAILS_ON_PRIMITIVES$1;
6970
6971         // `Object.getOwnPropertyDescriptor` method
6972         // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor
6973         _export({ target: 'Object', stat: true, forced: FORCED$5, sham: !descriptors }, {
6974           getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
6975             return nativeGetOwnPropertyDescriptor$2(toIndexedObject(it), key);
6976           }
6977         });
6978
6979         var FAILS_ON_PRIMITIVES$2 = fails(function () { objectGetPrototypeOf(1); });
6980
6981         // `Object.getPrototypeOf` method
6982         // https://tc39.github.io/ecma262/#sec-object.getprototypeof
6983         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$2, sham: !correctPrototypeGetter }, {
6984           getPrototypeOf: function getPrototypeOf(it) {
6985             return objectGetPrototypeOf(toObject(it));
6986           }
6987         });
6988
6989         // `Object.setPrototypeOf` method
6990         // https://tc39.github.io/ecma262/#sec-object.setprototypeof
6991         _export({ target: 'Object', stat: true }, {
6992           setPrototypeOf: objectSetPrototypeOf
6993         });
6994
6995         var slice$1 = [].slice;
6996         var factories = {};
6997
6998         var construct = function (C, argsLength, args) {
6999           if (!(argsLength in factories)) {
7000             for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
7001             // eslint-disable-next-line no-new-func
7002             factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
7003           } return factories[argsLength](C, args);
7004         };
7005
7006         // `Function.prototype.bind` method implementation
7007         // https://tc39.github.io/ecma262/#sec-function.prototype.bind
7008         var functionBind = Function.bind || function bind(that /* , ...args */) {
7009           var fn = aFunction$1(this);
7010           var partArgs = slice$1.call(arguments, 1);
7011           var boundFunction = function bound(/* args... */) {
7012             var args = partArgs.concat(slice$1.call(arguments));
7013             return this instanceof boundFunction ? construct(fn, args.length, args) : fn.apply(that, args);
7014           };
7015           if (isObject(fn.prototype)) boundFunction.prototype = fn.prototype;
7016           return boundFunction;
7017         };
7018
7019         var nativeConstruct = getBuiltIn('Reflect', 'construct');
7020
7021         // `Reflect.construct` method
7022         // https://tc39.github.io/ecma262/#sec-reflect.construct
7023         // MS Edge supports only 2 arguments and argumentsList argument is optional
7024         // FF Nightly sets third argument as `new.target`, but does not create `this` from it
7025         var NEW_TARGET_BUG = fails(function () {
7026           function F() { /* empty */ }
7027           return !(nativeConstruct(function () { /* empty */ }, [], F) instanceof F);
7028         });
7029         var ARGS_BUG = !fails(function () {
7030           nativeConstruct(function () { /* empty */ });
7031         });
7032         var FORCED$6 = NEW_TARGET_BUG || ARGS_BUG;
7033
7034         _export({ target: 'Reflect', stat: true, forced: FORCED$6, sham: FORCED$6 }, {
7035           construct: function construct(Target, args /* , newTarget */) {
7036             aFunction$1(Target);
7037             anObject(args);
7038             var newTarget = arguments.length < 3 ? Target : aFunction$1(arguments[2]);
7039             if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
7040             if (Target == newTarget) {
7041               // w/o altered newTarget, optimization for 0-4 arguments
7042               switch (args.length) {
7043                 case 0: return new Target();
7044                 case 1: return new Target(args[0]);
7045                 case 2: return new Target(args[0], args[1]);
7046                 case 3: return new Target(args[0], args[1], args[2]);
7047                 case 4: return new Target(args[0], args[1], args[2], args[3]);
7048               }
7049               // w/o altered newTarget, lot of arguments case
7050               var $args = [null];
7051               $args.push.apply($args, args);
7052               return new (functionBind.apply(Target, $args))();
7053             }
7054             // with altered newTarget, not support built-in constructors
7055             var proto = newTarget.prototype;
7056             var instance = objectCreate(isObject(proto) ? proto : Object.prototype);
7057             var result = Function.apply.call(Target, instance, args);
7058             return isObject(result) ? result : instance;
7059           }
7060         });
7061
7062         // `Reflect.get` method
7063         // https://tc39.github.io/ecma262/#sec-reflect.get
7064         function get$2(target, propertyKey /* , receiver */) {
7065           var receiver = arguments.length < 3 ? target : arguments[2];
7066           var descriptor, prototype;
7067           if (anObject(target) === receiver) return target[propertyKey];
7068           if (descriptor = objectGetOwnPropertyDescriptor.f(target, propertyKey)) return has(descriptor, 'value')
7069             ? descriptor.value
7070             : descriptor.get === undefined
7071               ? undefined
7072               : descriptor.get.call(receiver);
7073           if (isObject(prototype = objectGetPrototypeOf(target))) return get$2(prototype, propertyKey, receiver);
7074         }
7075
7076         _export({ target: 'Reflect', stat: true }, {
7077           get: get$2
7078         });
7079
7080         (function (factory) {
7081            factory();
7082         })(function () {
7083
7084           function _classCallCheck(instance, Constructor) {
7085             if (!(instance instanceof Constructor)) {
7086               throw new TypeError("Cannot call a class as a function");
7087             }
7088           }
7089
7090           function _defineProperties(target, props) {
7091             for (var i = 0; i < props.length; i++) {
7092               var descriptor = props[i];
7093               descriptor.enumerable = descriptor.enumerable || false;
7094               descriptor.configurable = true;
7095               if ("value" in descriptor) descriptor.writable = true;
7096               Object.defineProperty(target, descriptor.key, descriptor);
7097             }
7098           }
7099
7100           function _createClass(Constructor, protoProps, staticProps) {
7101             if (protoProps) _defineProperties(Constructor.prototype, protoProps);
7102             if (staticProps) _defineProperties(Constructor, staticProps);
7103             return Constructor;
7104           }
7105
7106           function _inherits(subClass, superClass) {
7107             if (typeof superClass !== "function" && superClass !== null) {
7108               throw new TypeError("Super expression must either be null or a function");
7109             }
7110
7111             subClass.prototype = Object.create(superClass && superClass.prototype, {
7112               constructor: {
7113                 value: subClass,
7114                 writable: true,
7115                 configurable: true
7116               }
7117             });
7118             if (superClass) _setPrototypeOf(subClass, superClass);
7119           }
7120
7121           function _getPrototypeOf(o) {
7122             _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
7123               return o.__proto__ || Object.getPrototypeOf(o);
7124             };
7125             return _getPrototypeOf(o);
7126           }
7127
7128           function _setPrototypeOf(o, p) {
7129             _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
7130               o.__proto__ = p;
7131               return o;
7132             };
7133
7134             return _setPrototypeOf(o, p);
7135           }
7136
7137           function _isNativeReflectConstruct() {
7138             if (typeof Reflect === "undefined" || !Reflect.construct) return false;
7139             if (Reflect.construct.sham) return false;
7140             if (typeof Proxy === "function") return true;
7141
7142             try {
7143               Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
7144               return true;
7145             } catch (e) {
7146               return false;
7147             }
7148           }
7149
7150           function _assertThisInitialized(self) {
7151             if (self === void 0) {
7152               throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
7153             }
7154
7155             return self;
7156           }
7157
7158           function _possibleConstructorReturn(self, call) {
7159             if (call && (_typeof(call) === "object" || typeof call === "function")) {
7160               return call;
7161             }
7162
7163             return _assertThisInitialized(self);
7164           }
7165
7166           function _createSuper(Derived) {
7167             var hasNativeReflectConstruct = _isNativeReflectConstruct();
7168
7169             return function _createSuperInternal() {
7170               var Super = _getPrototypeOf(Derived),
7171                   result;
7172
7173               if (hasNativeReflectConstruct) {
7174                 var NewTarget = _getPrototypeOf(this).constructor;
7175
7176                 result = Reflect.construct(Super, arguments, NewTarget);
7177               } else {
7178                 result = Super.apply(this, arguments);
7179               }
7180
7181               return _possibleConstructorReturn(this, result);
7182             };
7183           }
7184
7185           function _superPropBase(object, property) {
7186             while (!Object.prototype.hasOwnProperty.call(object, property)) {
7187               object = _getPrototypeOf(object);
7188               if (object === null) break;
7189             }
7190
7191             return object;
7192           }
7193
7194           function _get(target, property, receiver) {
7195             if (typeof Reflect !== "undefined" && Reflect.get) {
7196               _get = Reflect.get;
7197             } else {
7198               _get = function _get(target, property, receiver) {
7199                 var base = _superPropBase(target, property);
7200
7201                 if (!base) return;
7202                 var desc = Object.getOwnPropertyDescriptor(base, property);
7203
7204                 if (desc.get) {
7205                   return desc.get.call(receiver);
7206                 }
7207
7208                 return desc.value;
7209               };
7210             }
7211
7212             return _get(target, property, receiver || target);
7213           }
7214
7215           var Emitter = /*#__PURE__*/function () {
7216             function Emitter() {
7217               _classCallCheck(this, Emitter);
7218
7219               Object.defineProperty(this, 'listeners', {
7220                 value: {},
7221                 writable: true,
7222                 configurable: true
7223               });
7224             }
7225
7226             _createClass(Emitter, [{
7227               key: "addEventListener",
7228               value: function addEventListener(type, callback) {
7229                 if (!(type in this.listeners)) {
7230                   this.listeners[type] = [];
7231                 }
7232
7233                 this.listeners[type].push(callback);
7234               }
7235             }, {
7236               key: "removeEventListener",
7237               value: function removeEventListener(type, callback) {
7238                 if (!(type in this.listeners)) {
7239                   return;
7240                 }
7241
7242                 var stack = this.listeners[type];
7243
7244                 for (var i = 0, l = stack.length; i < l; i++) {
7245                   if (stack[i] === callback) {
7246                     stack.splice(i, 1);
7247                     return;
7248                   }
7249                 }
7250               }
7251             }, {
7252               key: "dispatchEvent",
7253               value: function dispatchEvent(event) {
7254                 var _this = this;
7255
7256                 if (!(event.type in this.listeners)) {
7257                   return;
7258                 }
7259
7260                 var debounce = function debounce(callback) {
7261                   setTimeout(function () {
7262                     return callback.call(_this, event);
7263                   });
7264                 };
7265
7266                 var stack = this.listeners[event.type];
7267
7268                 for (var i = 0, l = stack.length; i < l; i++) {
7269                   debounce(stack[i]);
7270                 }
7271
7272                 return !event.defaultPrevented;
7273               }
7274             }]);
7275
7276             return Emitter;
7277           }();
7278
7279           var AbortSignal = /*#__PURE__*/function (_Emitter) {
7280             _inherits(AbortSignal, _Emitter);
7281
7282             var _super = _createSuper(AbortSignal);
7283
7284             function AbortSignal() {
7285               var _this2;
7286
7287               _classCallCheck(this, AbortSignal);
7288
7289               _this2 = _super.call(this); // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
7290               // constructor has failed to run, then "this.listeners" will still be undefined and then we call
7291               // the parent constructor directly instead as a workaround. For general details, see babel bug:
7292               // https://github.com/babel/babel/issues/3041
7293               // This hack was added as a fix for the issue described here:
7294               // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
7295
7296               if (!_this2.listeners) {
7297                 Emitter.call(_assertThisInitialized(_this2));
7298               } // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7299               // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
7300
7301
7302               Object.defineProperty(_assertThisInitialized(_this2), 'aborted', {
7303                 value: false,
7304                 writable: true,
7305                 configurable: true
7306               });
7307               Object.defineProperty(_assertThisInitialized(_this2), 'onabort', {
7308                 value: null,
7309                 writable: true,
7310                 configurable: true
7311               });
7312               return _this2;
7313             }
7314
7315             _createClass(AbortSignal, [{
7316               key: "toString",
7317               value: function toString() {
7318                 return '[object AbortSignal]';
7319               }
7320             }, {
7321               key: "dispatchEvent",
7322               value: function dispatchEvent(event) {
7323                 if (event.type === 'abort') {
7324                   this.aborted = true;
7325
7326                   if (typeof this.onabort === 'function') {
7327                     this.onabort.call(this, event);
7328                   }
7329                 }
7330
7331                 _get(_getPrototypeOf(AbortSignal.prototype), "dispatchEvent", this).call(this, event);
7332               }
7333             }]);
7334
7335             return AbortSignal;
7336           }(Emitter);
7337
7338           var AbortController = /*#__PURE__*/function () {
7339             function AbortController() {
7340               _classCallCheck(this, AbortController); // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
7341               // we want Object.keys(new AbortController()) to be [] for compat with the native impl
7342
7343
7344               Object.defineProperty(this, 'signal', {
7345                 value: new AbortSignal(),
7346                 writable: true,
7347                 configurable: true
7348               });
7349             }
7350
7351             _createClass(AbortController, [{
7352               key: "abort",
7353               value: function abort() {
7354                 var event;
7355
7356                 try {
7357                   event = new Event('abort');
7358                 } catch (e) {
7359                   if (typeof document !== 'undefined') {
7360                     if (!document.createEvent) {
7361                       // For Internet Explorer 8:
7362                       event = document.createEventObject();
7363                       event.type = 'abort';
7364                     } else {
7365                       // For Internet Explorer 11:
7366                       event = document.createEvent('Event');
7367                       event.initEvent('abort', false, false);
7368                     }
7369                   } else {
7370                     // Fallback where document isn't available:
7371                     event = {
7372                       type: 'abort',
7373                       bubbles: false,
7374                       cancelable: false
7375                     };
7376                   }
7377                 }
7378
7379                 this.signal.dispatchEvent(event);
7380               }
7381             }, {
7382               key: "toString",
7383               value: function toString() {
7384                 return '[object AbortController]';
7385               }
7386             }]);
7387
7388             return AbortController;
7389           }();
7390
7391           if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
7392             // These are necessary to make sure that we get correct output for:
7393             // Object.prototype.toString.call(new AbortController())
7394             AbortController.prototype[Symbol.toStringTag] = 'AbortController';
7395             AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
7396           }
7397
7398           function polyfillNeeded(self) {
7399             if (self.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7400               console.log('__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill');
7401               return true;
7402             } // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7403             // defining window.Request, and this polyfill need to work on top of unfetch
7404             // so the below feature detection needs the !self.AbortController part.
7405             // The Request.prototype check is also needed because Safari versions 11.1.2
7406             // up to and including 12.1.x has a window.AbortController present but still
7407             // does NOT correctly implement abortable fetch:
7408             // https://bugs.webkit.org/show_bug.cgi?id=174980#c2
7409
7410
7411             return typeof self.Request === 'function' && !self.Request.prototype.hasOwnProperty('signal') || !self.AbortController;
7412           }
7413           /**
7414            * Note: the "fetch.Request" default value is available for fetch imported from
7415            * the "node-fetch" package and not in browsers. This is OK since browsers
7416            * will be importing umd-polyfill.js from that path "self" is passed the
7417            * decorator so the default value will not be used (because browsers that define
7418            * fetch also has Request). One quirky setup where self.fetch exists but
7419            * self.Request does not is when the "unfetch" minimal fetch polyfill is used
7420            * on top of IE11; for this case the browser will try to use the fetch.Request
7421            * default value which in turn will be undefined but then then "if (Request)"
7422            * will ensure that you get a patched fetch but still no Request (as expected).
7423            * @param {fetch, Request = fetch.Request}
7424            * @returns {fetch: abortableFetch, Request: AbortableRequest}
7425            */
7426
7427
7428           function abortableFetchDecorator(patchTargets) {
7429             if ('function' === typeof patchTargets) {
7430               patchTargets = {
7431                 fetch: patchTargets
7432               };
7433             }
7434
7435             var _patchTargets = patchTargets,
7436                 fetch = _patchTargets.fetch,
7437                 _patchTargets$Request = _patchTargets.Request,
7438                 NativeRequest = _patchTargets$Request === void 0 ? fetch.Request : _patchTargets$Request,
7439                 NativeAbortController = _patchTargets.AbortController,
7440                 _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL,
7441                 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
7442
7443             if (!polyfillNeeded({
7444               fetch: fetch,
7445               Request: NativeRequest,
7446               AbortController: NativeAbortController,
7447               __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL: __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
7448             })) {
7449               return {
7450                 fetch: fetch,
7451                 Request: Request
7452               };
7453             }
7454
7455             var Request = NativeRequest; // Note that the "unfetch" minimal fetch polyfill defines fetch() without
7456             // defining window.Request, and this polyfill need to work on top of unfetch
7457             // hence we only patch it if it's available. Also we don't patch it if signal
7458             // is already available on the Request prototype because in this case support
7459             // is present and the patching below can cause a crash since it assigns to
7460             // request.signal which is technically a read-only property. This latter error
7461             // happens when you run the main5.js node-fetch example in the repo
7462             // "abortcontroller-polyfill-examples". The exact error is:
7463             //   request.signal = init.signal;
7464             //   ^
7465             // TypeError: Cannot set property signal of #<Request> which has only a getter
7466
7467             if (Request && !Request.prototype.hasOwnProperty('signal') || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
7468               Request = function Request(input, init) {
7469                 var signal;
7470
7471                 if (init && init.signal) {
7472                   signal = init.signal; // Never pass init.signal to the native Request implementation when the polyfill has
7473                   // been installed because if we're running on top of a browser with a
7474                   // working native AbortController (i.e. the polyfill was installed due to
7475                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7476                   // fake AbortSignal to the native fetch will trigger:
7477                   // TypeError: Failed to construct 'Request': member signal is not of type AbortSignal.
7478
7479                   delete init.signal;
7480                 }
7481
7482                 var request = new NativeRequest(input, init);
7483
7484                 if (signal) {
7485                   Object.defineProperty(request, 'signal', {
7486                     writable: false,
7487                     enumerable: false,
7488                     configurable: true,
7489                     value: signal
7490                   });
7491                 }
7492
7493                 return request;
7494               };
7495
7496               Request.prototype = NativeRequest.prototype;
7497             }
7498
7499             var realFetch = fetch;
7500
7501             var abortableFetch = function abortableFetch(input, init) {
7502               var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : undefined;
7503
7504               if (signal) {
7505                 var abortError;
7506
7507                 try {
7508                   abortError = new DOMException('Aborted', 'AbortError');
7509                 } catch (err) {
7510                   // IE 11 does not support calling the DOMException constructor, use a
7511                   // regular error object on it instead.
7512                   abortError = new Error('Aborted');
7513                   abortError.name = 'AbortError';
7514                 } // Return early if already aborted, thus avoiding making an HTTP request
7515
7516
7517                 if (signal.aborted) {
7518                   return Promise.reject(abortError);
7519                 } // Turn an event into a promise, reject it once `abort` is dispatched
7520
7521
7522                 var cancellation = new Promise(function (_, reject) {
7523                   signal.addEventListener('abort', function () {
7524                     return reject(abortError);
7525                   }, {
7526                     once: true
7527                   });
7528                 });
7529
7530                 if (init && init.signal) {
7531                   // Never pass .signal to the native implementation when the polyfill has
7532                   // been installed because if we're running on top of a browser with a
7533                   // working native AbortController (i.e. the polyfill was installed due to
7534                   // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
7535                   // fake AbortSignal to the native fetch will trigger:
7536                   // TypeError: Failed to execute 'fetch' on 'Window': member signal is not of type AbortSignal.
7537                   delete init.signal;
7538                 } // Return the fastest promise (don't need to wait for request to finish)
7539
7540
7541                 return Promise.race([cancellation, realFetch(input, init)]);
7542               }
7543
7544               return realFetch(input, init);
7545             };
7546
7547             return {
7548               fetch: abortableFetch,
7549               Request: Request
7550             };
7551           }
7552
7553           (function (self) {
7554             if (!polyfillNeeded(self)) {
7555               return;
7556             }
7557
7558             if (!self.fetch) {
7559               console.warn('fetch() is not available, cannot install abortcontroller-polyfill');
7560               return;
7561             }
7562
7563             var _abortableFetch = abortableFetchDecorator(self),
7564                 fetch = _abortableFetch.fetch,
7565                 Request = _abortableFetch.Request;
7566
7567             self.fetch = fetch;
7568             self.Request = Request;
7569             Object.defineProperty(self, 'AbortController', {
7570               writable: true,
7571               enumerable: false,
7572               configurable: true,
7573               value: AbortController
7574             });
7575             Object.defineProperty(self, 'AbortSignal', {
7576               writable: true,
7577               enumerable: false,
7578               configurable: true,
7579               value: AbortSignal
7580             });
7581           })(typeof self !== 'undefined' ? self : commonjsGlobal);
7582         });
7583
7584         function actionAddEntity(way) {
7585           return function (graph) {
7586             return graph.replace(way);
7587           };
7588         }
7589
7590         var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
7591         var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
7592         var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
7593
7594         // We can't use this feature detection in V8 since it causes
7595         // deoptimization and serious performance degradation
7596         // https://github.com/zloirock/core-js/issues/679
7597         var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
7598           var array = [];
7599           array[IS_CONCAT_SPREADABLE] = false;
7600           return array.concat()[0] !== array;
7601         });
7602
7603         var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
7604
7605         var isConcatSpreadable = function (O) {
7606           if (!isObject(O)) return false;
7607           var spreadable = O[IS_CONCAT_SPREADABLE];
7608           return spreadable !== undefined ? !!spreadable : isArray(O);
7609         };
7610
7611         var FORCED$7 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
7612
7613         // `Array.prototype.concat` method
7614         // https://tc39.github.io/ecma262/#sec-array.prototype.concat
7615         // with adding support of @@isConcatSpreadable and @@species
7616         _export({ target: 'Array', proto: true, forced: FORCED$7 }, {
7617           concat: function concat(arg) { // eslint-disable-line no-unused-vars
7618             var O = toObject(this);
7619             var A = arraySpeciesCreate(O, 0);
7620             var n = 0;
7621             var i, k, length, len, E;
7622             for (i = -1, length = arguments.length; i < length; i++) {
7623               E = i === -1 ? O : arguments[i];
7624               if (isConcatSpreadable(E)) {
7625                 len = toLength(E.length);
7626                 if (n + len > MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7627                 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
7628               } else {
7629                 if (n >= MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
7630                 createProperty(A, n++, E);
7631               }
7632             }
7633             A.length = n;
7634             return A;
7635           }
7636         });
7637
7638         // `Object.assign` method
7639         // https://tc39.github.io/ecma262/#sec-object.assign
7640         _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {
7641           assign: objectAssign
7642         });
7643
7644         var $filter$1 = arrayIteration.filter;
7645
7646
7647
7648         var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport('filter');
7649         // Edge 14- issue
7650         var USES_TO_LENGTH$6 = arrayMethodUsesToLength('filter');
7651
7652         // `Array.prototype.filter` method
7653         // https://tc39.github.io/ecma262/#sec-array.prototype.filter
7654         // with adding support of @@species
7655         _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 || !USES_TO_LENGTH$6 }, {
7656           filter: function filter(callbackfn /* , thisArg */) {
7657             return $filter$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
7658           }
7659         });
7660
7661         var nativeReverse = [].reverse;
7662         var test$1 = [1, 2];
7663
7664         // `Array.prototype.reverse` method
7665         // https://tc39.github.io/ecma262/#sec-array.prototype.reverse
7666         // fix for Safari 12.0 bug
7667         // https://bugs.webkit.org/show_bug.cgi?id=188794
7668         _export({ target: 'Array', proto: true, forced: String(test$1) === String(test$1.reverse()) }, {
7669           reverse: function reverse() {
7670             // eslint-disable-next-line no-self-assign
7671             if (isArray(this)) this.length = this.length;
7672             return nativeReverse.call(this);
7673           }
7674         });
7675
7676         var FAILS_ON_PRIMITIVES$3 = fails(function () { objectKeys(1); });
7677
7678         // `Object.keys` method
7679         // https://tc39.github.io/ecma262/#sec-object.keys
7680         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3 }, {
7681           keys: function keys(it) {
7682             return objectKeys(toObject(it));
7683           }
7684         });
7685
7686         var trim = stringTrim.trim;
7687
7688
7689         var $parseFloat = global_1.parseFloat;
7690         var FORCED$8 = 1 / $parseFloat(whitespaces + '-0') !== -Infinity;
7691
7692         // `parseFloat` method
7693         // https://tc39.github.io/ecma262/#sec-parsefloat-string
7694         var numberParseFloat = FORCED$8 ? function parseFloat(string) {
7695           var trimmedString = trim(String(string));
7696           var result = $parseFloat(trimmedString);
7697           return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
7698         } : $parseFloat;
7699
7700         // `parseFloat` method
7701         // https://tc39.github.io/ecma262/#sec-parsefloat-string
7702         _export({ global: true, forced: parseFloat != numberParseFloat }, {
7703           parseFloat: numberParseFloat
7704         });
7705
7706         /*
7707         Order the nodes of a way in reverse order and reverse any direction dependent tags
7708         other than `oneway`. (We assume that correcting a backwards oneway is the primary
7709         reason for reversing a way.)
7710
7711         In addition, numeric-valued `incline` tags are negated.
7712
7713         The JOSM implementation was used as a guide, but transformations that were of unclear benefit
7714         or adjusted tags that don't seem to be used in practice were omitted.
7715
7716         References:
7717             http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
7718             http://wiki.openstreetmap.org/wiki/Key:direction#Steps
7719             http://wiki.openstreetmap.org/wiki/Key:incline
7720             http://wiki.openstreetmap.org/wiki/Route#Members
7721             http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
7722             http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
7723             http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
7724         */
7725         function actionReverse(entityID, options) {
7726           var ignoreKey = /^.*(_|:)?(description|name|note|website|ref|source|comment|watch|attribution)(_|:)?/;
7727           var numeric = /^([+\-]?)(?=[\d.])/;
7728           var directionKey = /direction$/;
7729           var turn_lanes = /^turn:lanes:?/;
7730           var keyReplacements = [[/:right$/, ':left'], [/:left$/, ':right'], [/:forward$/, ':backward'], [/:backward$/, ':forward'], [/:right:/, ':left:'], [/:left:/, ':right:'], [/:forward:/, ':backward:'], [/:backward:/, ':forward:']];
7731           var valueReplacements = {
7732             left: 'right',
7733             right: 'left',
7734             up: 'down',
7735             down: 'up',
7736             forward: 'backward',
7737             backward: 'forward',
7738             forwards: 'backward',
7739             backwards: 'forward'
7740           };
7741           var roleReplacements = {
7742             forward: 'backward',
7743             backward: 'forward',
7744             forwards: 'backward',
7745             backwards: 'forward'
7746           };
7747           var onewayReplacements = {
7748             yes: '-1',
7749             '1': '-1',
7750             '-1': 'yes'
7751           };
7752           var compassReplacements = {
7753             N: 'S',
7754             NNE: 'SSW',
7755             NE: 'SW',
7756             ENE: 'WSW',
7757             E: 'W',
7758             ESE: 'WNW',
7759             SE: 'NW',
7760             SSE: 'NNW',
7761             S: 'N',
7762             SSW: 'NNE',
7763             SW: 'NE',
7764             WSW: 'ENE',
7765             W: 'E',
7766             WNW: 'ESE',
7767             NW: 'SE',
7768             NNW: 'SSE'
7769           };
7770
7771           function reverseKey(key) {
7772             for (var i = 0; i < keyReplacements.length; ++i) {
7773               var replacement = keyReplacements[i];
7774
7775               if (replacement[0].test(key)) {
7776                 return key.replace(replacement[0], replacement[1]);
7777               }
7778             }
7779
7780             return key;
7781           }
7782
7783           function reverseValue(key, value, includeAbsolute) {
7784             if (ignoreKey.test(key)) return value; // Turn lanes are left/right to key (not way) direction - #5674
7785
7786             if (turn_lanes.test(key)) {
7787               return value;
7788             } else if (key === 'incline' && numeric.test(value)) {
7789               return value.replace(numeric, function (_, sign) {
7790                 return sign === '-' ? '' : '-';
7791               });
7792             } else if (options && options.reverseOneway && key === 'oneway') {
7793               return onewayReplacements[value] || value;
7794             } else if (includeAbsolute && directionKey.test(key)) {
7795               if (compassReplacements[value]) return compassReplacements[value];
7796               var degrees = parseFloat(value);
7797
7798               if (typeof degrees === 'number' && !isNaN(degrees)) {
7799                 if (degrees < 180) {
7800                   degrees += 180;
7801                 } else {
7802                   degrees -= 180;
7803                 }
7804
7805                 return degrees.toString();
7806               }
7807             }
7808
7809             return valueReplacements[value] || value;
7810           } // Reverse the direction of tags attached to the nodes - #3076
7811
7812
7813           function reverseNodeTags(graph, nodeIDs) {
7814             for (var i = 0; i < nodeIDs.length; i++) {
7815               var node = graph.hasEntity(nodeIDs[i]);
7816               if (!node || !Object.keys(node.tags).length) continue;
7817               var tags = {};
7818
7819               for (var key in node.tags) {
7820                 tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
7821               }
7822
7823               graph = graph.replace(node.update({
7824                 tags: tags
7825               }));
7826             }
7827
7828             return graph;
7829           }
7830
7831           function reverseWay(graph, way) {
7832             var nodes = way.nodes.slice().reverse();
7833             var tags = {};
7834             var role;
7835
7836             for (var key in way.tags) {
7837               tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
7838             }
7839
7840             graph.parentRelations(way).forEach(function (relation) {
7841               relation.members.forEach(function (member, index) {
7842                 if (member.id === way.id && (role = roleReplacements[member.role])) {
7843                   relation = relation.updateMember({
7844                     role: role
7845                   }, index);
7846                   graph = graph.replace(relation);
7847                 }
7848               });
7849             }); // Reverse any associated directions on nodes on the way and then replace
7850             // the way itself with the reversed node ids and updated way tags
7851
7852             return reverseNodeTags(graph, nodes).replace(way.update({
7853               nodes: nodes,
7854               tags: tags
7855             }));
7856           }
7857
7858           var action = function action(graph) {
7859             var entity = graph.entity(entityID);
7860
7861             if (entity.type === 'way') {
7862               return reverseWay(graph, entity);
7863             }
7864
7865             return reverseNodeTags(graph, [entityID]);
7866           };
7867
7868           action.disabled = function (graph) {
7869             var entity = graph.hasEntity(entityID);
7870             if (!entity || entity.type === 'way') return false;
7871
7872             for (var key in entity.tags) {
7873               var value = entity.tags[key];
7874
7875               if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
7876                 return false;
7877               }
7878             }
7879
7880             return 'nondirectional_node';
7881           };
7882
7883           action.entityID = function () {
7884             return entityID;
7885           };
7886
7887           return action;
7888         }
7889
7890         function osmIsInterestingTag(key) {
7891           return key !== 'attribution' && key !== 'created_by' && key !== 'source' && key !== 'odbl' && key.indexOf('source:') !== 0 && key.indexOf('source_ref') !== 0 && // purposely exclude colon
7892           key.indexOf('tiger:') !== 0;
7893         }
7894         var osmAreaKeys = {};
7895         function osmSetAreaKeys(value) {
7896           osmAreaKeys = value;
7897         } // returns an object with the tag from `tags` that implies an area geometry, if any
7898
7899         function osmTagSuggestingArea(tags) {
7900           if (tags.area === 'yes') return {
7901             area: 'yes'
7902           };
7903           if (tags.area === 'no') return null; // `highway` and `railway` are typically linear features, but there
7904           // are a few exceptions that should be treated as areas, even in the
7905           // absence of a proper `area=yes` or `areaKeys` tag.. see #4194
7906
7907           var lineKeys = {
7908             highway: {
7909               rest_area: true,
7910               services: true
7911             },
7912             railway: {
7913               roundhouse: true,
7914               station: true,
7915               traverser: true,
7916               turntable: true,
7917               wash: true
7918             }
7919           };
7920           var returnTags = {};
7921
7922           for (var key in tags) {
7923             if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
7924               returnTags[key] = tags[key];
7925               return returnTags;
7926             }
7927
7928             if (key in lineKeys && tags[key] in lineKeys[key]) {
7929               returnTags[key] = tags[key];
7930               return returnTags;
7931             }
7932           }
7933
7934           return null;
7935         } // Tags that indicate a node can be a standalone point
7936         // e.g. { amenity: { bar: true, parking: true, ... } ... }
7937
7938         var osmPointTags = {};
7939         function osmSetPointTags(value) {
7940           osmPointTags = value;
7941         } // Tags that indicate a node can be part of a way
7942         // e.g. { amenity: { parking: true, ... }, highway: { stop: true ... } ... }
7943
7944         var osmVertexTags = {};
7945         function osmSetVertexTags(value) {
7946           osmVertexTags = value;
7947         }
7948         function osmNodeGeometriesForTags(nodeTags) {
7949           var geometries = {};
7950
7951           for (var key in nodeTags) {
7952             if (osmPointTags[key] && (osmPointTags[key]['*'] || osmPointTags[key][nodeTags[key]])) {
7953               geometries.point = true;
7954             }
7955
7956             if (osmVertexTags[key] && (osmVertexTags[key]['*'] || osmVertexTags[key][nodeTags[key]])) {
7957               geometries.vertex = true;
7958             } // break early if both are already supported
7959
7960
7961             if (geometries.point && geometries.vertex) break;
7962           }
7963
7964           return geometries;
7965         }
7966         var osmOneWayTags = {
7967           'aerialway': {
7968             'chair_lift': true,
7969             'drag_lift': true,
7970             'j-bar': true,
7971             'magic_carpet': true,
7972             'mixed_lift': true,
7973             'platter': true,
7974             'rope_tow': true,
7975             't-bar': true,
7976             'zip_line': true
7977           },
7978           'highway': {
7979             'motorway': true
7980           },
7981           'junction': {
7982             'circular': true,
7983             'roundabout': true
7984           },
7985           'man_made': {
7986             'goods_conveyor': true,
7987             'piste:halfpipe': true
7988           },
7989           'piste:type': {
7990             'downhill': true,
7991             'sled': true,
7992             'yes': true
7993           },
7994           'waterway': {
7995             'canal': true,
7996             'ditch': true,
7997             'drain': true,
7998             'fish_pass': true,
7999             'river': true,
8000             'stream': true,
8001             'tidal_channel': true
8002           }
8003         }; // solid and smooth surfaces akin to the assumed default road surface in OSM
8004
8005         var osmPavedTags = {
8006           'surface': {
8007             'paved': true,
8008             'asphalt': true,
8009             'concrete': true,
8010             'concrete:lanes': true,
8011             'concrete:plates': true
8012           },
8013           'tracktype': {
8014             'grade1': true
8015           }
8016         }; // solid, if somewhat uncommon surfaces with a high range of smoothness
8017
8018         var osmSemipavedTags = {
8019           'surface': {
8020             'cobblestone': true,
8021             'cobblestone:flattened': true,
8022             'unhewn_cobblestone': true,
8023             'sett': true,
8024             'paving_stones': true,
8025             'metal': true,
8026             'wood': true
8027           }
8028         };
8029         var osmRightSideIsInsideTags = {
8030           'natural': {
8031             'cliff': true,
8032             'coastline': 'coastline'
8033           },
8034           'barrier': {
8035             'retaining_wall': true,
8036             'kerb': true,
8037             'guard_rail': true,
8038             'city_wall': true
8039           },
8040           'man_made': {
8041             'embankment': true
8042           },
8043           'waterway': {
8044             'weir': true
8045           }
8046         }; // "highway" tag values for pedestrian or vehicle right-of-ways that make up the routable network
8047         // (does not include `raceway`)
8048
8049         var osmRoutableHighwayTagValues = {
8050           motorway: true,
8051           trunk: true,
8052           primary: true,
8053           secondary: true,
8054           tertiary: true,
8055           residential: true,
8056           motorway_link: true,
8057           trunk_link: true,
8058           primary_link: true,
8059           secondary_link: true,
8060           tertiary_link: true,
8061           unclassified: true,
8062           road: true,
8063           service: true,
8064           track: true,
8065           living_street: true,
8066           bus_guideway: true,
8067           path: true,
8068           footway: true,
8069           cycleway: true,
8070           bridleway: true,
8071           pedestrian: true,
8072           corridor: true,
8073           steps: true
8074         }; // "highway" tag values that generally do not allow motor vehicles
8075
8076         var osmPathHighwayTagValues = {
8077           path: true,
8078           footway: true,
8079           cycleway: true,
8080           bridleway: true,
8081           pedestrian: true,
8082           corridor: true,
8083           steps: true
8084         }; // "railway" tag values representing existing railroad tracks (purposely does not include 'abandoned')
8085
8086         var osmRailwayTrackTagValues = {
8087           rail: true,
8088           light_rail: true,
8089           tram: true,
8090           subway: true,
8091           monorail: true,
8092           funicular: true,
8093           miniature: true,
8094           narrow_gauge: true,
8095           disused: true,
8096           preserved: true
8097         }; // "waterway" tag values for line features representing water flow
8098
8099         var osmFlowingWaterwayTagValues = {
8100           canal: true,
8101           ditch: true,
8102           drain: true,
8103           fish_pass: true,
8104           river: true,
8105           stream: true,
8106           tidal_channel: true
8107         };
8108
8109         var trim$1 = stringTrim.trim;
8110
8111
8112         var $parseInt = global_1.parseInt;
8113         var hex$1 = /^[+-]?0[Xx]/;
8114         var FORCED$9 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22;
8115
8116         // `parseInt` method
8117         // https://tc39.github.io/ecma262/#sec-parseint-string-radix
8118         var numberParseInt = FORCED$9 ? function parseInt(string, radix) {
8119           var S = trim$1(String(string));
8120           return $parseInt(S, (radix >>> 0) || (hex$1.test(S) ? 16 : 10));
8121         } : $parseInt;
8122
8123         // `parseInt` method
8124         // https://tc39.github.io/ecma262/#sec-parseint-string-radix
8125         _export({ global: true, forced: parseInt != numberParseInt }, {
8126           parseInt: numberParseInt
8127         });
8128
8129         var freezing = !fails(function () {
8130           return Object.isExtensible(Object.preventExtensions({}));
8131         });
8132
8133         var internalMetadata = createCommonjsModule(function (module) {
8134         var defineProperty = objectDefineProperty.f;
8135
8136
8137
8138         var METADATA = uid('meta');
8139         var id = 0;
8140
8141         var isExtensible = Object.isExtensible || function () {
8142           return true;
8143         };
8144
8145         var setMetadata = function (it) {
8146           defineProperty(it, METADATA, { value: {
8147             objectID: 'O' + ++id, // object ID
8148             weakData: {}          // weak collections IDs
8149           } });
8150         };
8151
8152         var fastKey = function (it, create) {
8153           // return a primitive with prefix
8154           if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
8155           if (!has(it, METADATA)) {
8156             // can't set metadata to uncaught frozen object
8157             if (!isExtensible(it)) return 'F';
8158             // not necessary to add metadata
8159             if (!create) return 'E';
8160             // add missing metadata
8161             setMetadata(it);
8162           // return object ID
8163           } return it[METADATA].objectID;
8164         };
8165
8166         var getWeakData = function (it, create) {
8167           if (!has(it, METADATA)) {
8168             // can't set metadata to uncaught frozen object
8169             if (!isExtensible(it)) return true;
8170             // not necessary to add metadata
8171             if (!create) return false;
8172             // add missing metadata
8173             setMetadata(it);
8174           // return the store of weak collections IDs
8175           } return it[METADATA].weakData;
8176         };
8177
8178         // add metadata on freeze-family methods calling
8179         var onFreeze = function (it) {
8180           if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
8181           return it;
8182         };
8183
8184         var meta = module.exports = {
8185           REQUIRED: false,
8186           fastKey: fastKey,
8187           getWeakData: getWeakData,
8188           onFreeze: onFreeze
8189         };
8190
8191         hiddenKeys[METADATA] = true;
8192         });
8193
8194         var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
8195           var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
8196           var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
8197           var ADDER = IS_MAP ? 'set' : 'add';
8198           var NativeConstructor = global_1[CONSTRUCTOR_NAME];
8199           var NativePrototype = NativeConstructor && NativeConstructor.prototype;
8200           var Constructor = NativeConstructor;
8201           var exported = {};
8202
8203           var fixMethod = function (KEY) {
8204             var nativeMethod = NativePrototype[KEY];
8205             redefine(NativePrototype, KEY,
8206               KEY == 'add' ? function add(value) {
8207                 nativeMethod.call(this, value === 0 ? 0 : value);
8208                 return this;
8209               } : KEY == 'delete' ? function (key) {
8210                 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8211               } : KEY == 'get' ? function get(key) {
8212                 return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
8213               } : KEY == 'has' ? function has(key) {
8214                 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
8215               } : function set(key, value) {
8216                 nativeMethod.call(this, key === 0 ? 0 : key, value);
8217                 return this;
8218               }
8219             );
8220           };
8221
8222           // eslint-disable-next-line max-len
8223           if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
8224             new NativeConstructor().entries().next();
8225           })))) {
8226             // create collection constructor
8227             Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
8228             internalMetadata.REQUIRED = true;
8229           } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
8230             var instance = new Constructor();
8231             // early implementations not supports chaining
8232             var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
8233             // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
8234             var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });
8235             // most early implementations doesn't supports iterables, most modern - not close it correctly
8236             // eslint-disable-next-line no-new
8237             var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });
8238             // for early implementations -0 and +0 not the same
8239             var BUGGY_ZERO = !IS_WEAK && fails(function () {
8240               // V8 ~ Chromium 42- fails only with 5+ elements
8241               var $instance = new NativeConstructor();
8242               var index = 5;
8243               while (index--) $instance[ADDER](index, index);
8244               return !$instance.has(-0);
8245             });
8246
8247             if (!ACCEPT_ITERABLES) {
8248               Constructor = wrapper(function (dummy, iterable) {
8249                 anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
8250                 var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
8251                 if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
8252                 return that;
8253               });
8254               Constructor.prototype = NativePrototype;
8255               NativePrototype.constructor = Constructor;
8256             }
8257
8258             if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
8259               fixMethod('delete');
8260               fixMethod('has');
8261               IS_MAP && fixMethod('get');
8262             }
8263
8264             if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);
8265
8266             // weak collections should not contains .clear method
8267             if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
8268           }
8269
8270           exported[CONSTRUCTOR_NAME] = Constructor;
8271           _export({ global: true, forced: Constructor != NativeConstructor }, exported);
8272
8273           setToStringTag(Constructor, CONSTRUCTOR_NAME);
8274
8275           if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
8276
8277           return Constructor;
8278         };
8279
8280         var defineProperty$8 = objectDefineProperty.f;
8281
8282
8283
8284
8285
8286
8287
8288
8289         var fastKey = internalMetadata.fastKey;
8290
8291
8292         var setInternalState$7 = internalState.set;
8293         var internalStateGetterFor = internalState.getterFor;
8294
8295         var collectionStrong = {
8296           getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
8297             var C = wrapper(function (that, iterable) {
8298               anInstance(that, C, CONSTRUCTOR_NAME);
8299               setInternalState$7(that, {
8300                 type: CONSTRUCTOR_NAME,
8301                 index: objectCreate(null),
8302                 first: undefined,
8303                 last: undefined,
8304                 size: 0
8305               });
8306               if (!descriptors) that.size = 0;
8307               if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
8308             });
8309
8310             var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
8311
8312             var define = function (that, key, value) {
8313               var state = getInternalState(that);
8314               var entry = getEntry(that, key);
8315               var previous, index;
8316               // change existing entry
8317               if (entry) {
8318                 entry.value = value;
8319               // create new entry
8320               } else {
8321                 state.last = entry = {
8322                   index: index = fastKey(key, true),
8323                   key: key,
8324                   value: value,
8325                   previous: previous = state.last,
8326                   next: undefined,
8327                   removed: false
8328                 };
8329                 if (!state.first) state.first = entry;
8330                 if (previous) previous.next = entry;
8331                 if (descriptors) state.size++;
8332                 else that.size++;
8333                 // add to index
8334                 if (index !== 'F') state.index[index] = entry;
8335               } return that;
8336             };
8337
8338             var getEntry = function (that, key) {
8339               var state = getInternalState(that);
8340               // fast case
8341               var index = fastKey(key);
8342               var entry;
8343               if (index !== 'F') return state.index[index];
8344               // frozen object case
8345               for (entry = state.first; entry; entry = entry.next) {
8346                 if (entry.key == key) return entry;
8347               }
8348             };
8349
8350             redefineAll(C.prototype, {
8351               // 23.1.3.1 Map.prototype.clear()
8352               // 23.2.3.2 Set.prototype.clear()
8353               clear: function clear() {
8354                 var that = this;
8355                 var state = getInternalState(that);
8356                 var data = state.index;
8357                 var entry = state.first;
8358                 while (entry) {
8359                   entry.removed = true;
8360                   if (entry.previous) entry.previous = entry.previous.next = undefined;
8361                   delete data[entry.index];
8362                   entry = entry.next;
8363                 }
8364                 state.first = state.last = undefined;
8365                 if (descriptors) state.size = 0;
8366                 else that.size = 0;
8367               },
8368               // 23.1.3.3 Map.prototype.delete(key)
8369               // 23.2.3.4 Set.prototype.delete(value)
8370               'delete': function (key) {
8371                 var that = this;
8372                 var state = getInternalState(that);
8373                 var entry = getEntry(that, key);
8374                 if (entry) {
8375                   var next = entry.next;
8376                   var prev = entry.previous;
8377                   delete state.index[entry.index];
8378                   entry.removed = true;
8379                   if (prev) prev.next = next;
8380                   if (next) next.previous = prev;
8381                   if (state.first == entry) state.first = next;
8382                   if (state.last == entry) state.last = prev;
8383                   if (descriptors) state.size--;
8384                   else that.size--;
8385                 } return !!entry;
8386               },
8387               // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
8388               // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
8389               forEach: function forEach(callbackfn /* , that = undefined */) {
8390                 var state = getInternalState(this);
8391                 var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
8392                 var entry;
8393                 while (entry = entry ? entry.next : state.first) {
8394                   boundFunction(entry.value, entry.key, this);
8395                   // revert to the last existing entry
8396                   while (entry && entry.removed) entry = entry.previous;
8397                 }
8398               },
8399               // 23.1.3.7 Map.prototype.has(key)
8400               // 23.2.3.7 Set.prototype.has(value)
8401               has: function has(key) {
8402                 return !!getEntry(this, key);
8403               }
8404             });
8405
8406             redefineAll(C.prototype, IS_MAP ? {
8407               // 23.1.3.6 Map.prototype.get(key)
8408               get: function get(key) {
8409                 var entry = getEntry(this, key);
8410                 return entry && entry.value;
8411               },
8412               // 23.1.3.9 Map.prototype.set(key, value)
8413               set: function set(key, value) {
8414                 return define(this, key === 0 ? 0 : key, value);
8415               }
8416             } : {
8417               // 23.2.3.1 Set.prototype.add(value)
8418               add: function add(value) {
8419                 return define(this, value = value === 0 ? 0 : value, value);
8420               }
8421             });
8422             if (descriptors) defineProperty$8(C.prototype, 'size', {
8423               get: function () {
8424                 return getInternalState(this).size;
8425               }
8426             });
8427             return C;
8428           },
8429           setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
8430             var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
8431             var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
8432             var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
8433             // add .keys, .values, .entries, [@@iterator]
8434             // 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
8435             defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
8436               setInternalState$7(this, {
8437                 type: ITERATOR_NAME,
8438                 target: iterated,
8439                 state: getInternalCollectionState(iterated),
8440                 kind: kind,
8441                 last: undefined
8442               });
8443             }, function () {
8444               var state = getInternalIteratorState(this);
8445               var kind = state.kind;
8446               var entry = state.last;
8447               // revert to the last existing entry
8448               while (entry && entry.removed) entry = entry.previous;
8449               // get next entry
8450               if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
8451                 // or finish the iteration
8452                 state.target = undefined;
8453                 return { value: undefined, done: true };
8454               }
8455               // return step by kind
8456               if (kind == 'keys') return { value: entry.key, done: false };
8457               if (kind == 'values') return { value: entry.value, done: false };
8458               return { value: [entry.key, entry.value], done: false };
8459             }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
8460
8461             // add [@@species], 23.1.2.2, 23.2.2.2
8462             setSpecies(CONSTRUCTOR_NAME);
8463           }
8464         };
8465
8466         // `Set` constructor
8467         // https://tc39.github.io/ecma262/#sec-set-objects
8468         var es_set = collection('Set', function (init) {
8469           return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
8470         }, collectionStrong);
8471
8472         function d3_ascending (a, b) {
8473           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
8474         }
8475
8476         function d3_bisector (f) {
8477           var delta = f;
8478           var compare = f;
8479
8480           if (f.length === 1) {
8481             delta = function delta(d, x) {
8482               return f(d) - x;
8483             };
8484
8485             compare = ascendingComparator(f);
8486           }
8487
8488           function left(a, x, lo, hi) {
8489             if (lo == null) lo = 0;
8490             if (hi == null) hi = a.length;
8491
8492             while (lo < hi) {
8493               var mid = lo + hi >>> 1;
8494               if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
8495             }
8496
8497             return lo;
8498           }
8499
8500           function right(a, x, lo, hi) {
8501             if (lo == null) lo = 0;
8502             if (hi == null) hi = a.length;
8503
8504             while (lo < hi) {
8505               var mid = lo + hi >>> 1;
8506               if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
8507             }
8508
8509             return lo;
8510           }
8511
8512           function center(a, x, lo, hi) {
8513             if (lo == null) lo = 0;
8514             if (hi == null) hi = a.length;
8515             var i = left(a, x, lo, hi - 1);
8516             return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
8517           }
8518
8519           return {
8520             left: left,
8521             center: center,
8522             right: right
8523           };
8524         }
8525
8526         function ascendingComparator(f) {
8527           return function (d, x) {
8528             return d3_ascending(f(d), x);
8529           };
8530         }
8531
8532         // `Symbol.asyncIterator` well-known symbol
8533         // https://tc39.github.io/ecma262/#sec-symbol.asynciterator
8534         defineWellKnownSymbol('asyncIterator');
8535
8536         var runtime_1 = createCommonjsModule(function (module) {
8537           /**
8538            * Copyright (c) 2014-present, Facebook, Inc.
8539            *
8540            * This source code is licensed under the MIT license found in the
8541            * LICENSE file in the root directory of this source tree.
8542            */
8543           var runtime = function (exports) {
8544
8545             var Op = Object.prototype;
8546             var hasOwn = Op.hasOwnProperty;
8547             var undefined$1; // More compressible than void 0.
8548
8549             var $Symbol = typeof Symbol === "function" ? Symbol : {};
8550             var iteratorSymbol = $Symbol.iterator || "@@iterator";
8551             var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
8552             var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
8553
8554             function define(obj, key, value) {
8555               Object.defineProperty(obj, key, {
8556                 value: value,
8557                 enumerable: true,
8558                 configurable: true,
8559                 writable: true
8560               });
8561               return obj[key];
8562             }
8563
8564             try {
8565               // IE 8 has a broken Object.defineProperty that only works on DOM objects.
8566               define({}, "");
8567             } catch (err) {
8568               define = function define(obj, key, value) {
8569                 return obj[key] = value;
8570               };
8571             }
8572
8573             function wrap(innerFn, outerFn, self, tryLocsList) {
8574               // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
8575               var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
8576               var generator = Object.create(protoGenerator.prototype);
8577               var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
8578               // .throw, and .return methods.
8579
8580               generator._invoke = makeInvokeMethod(innerFn, self, context);
8581               return generator;
8582             }
8583
8584             exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
8585             // record like context.tryEntries[i].completion. This interface could
8586             // have been (and was previously) designed to take a closure to be
8587             // invoked without arguments, but in all the cases we care about we
8588             // already have an existing method we want to call, so there's no need
8589             // to create a new function object. We can even get away with assuming
8590             // the method takes exactly one argument, since that happens to be true
8591             // in every case, so we don't have to touch the arguments object. The
8592             // only additional allocation required is the completion record, which
8593             // has a stable shape and so hopefully should be cheap to allocate.
8594
8595             function tryCatch(fn, obj, arg) {
8596               try {
8597                 return {
8598                   type: "normal",
8599                   arg: fn.call(obj, arg)
8600                 };
8601               } catch (err) {
8602                 return {
8603                   type: "throw",
8604                   arg: err
8605                 };
8606               }
8607             }
8608
8609             var GenStateSuspendedStart = "suspendedStart";
8610             var GenStateSuspendedYield = "suspendedYield";
8611             var GenStateExecuting = "executing";
8612             var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
8613             // breaking out of the dispatch switch statement.
8614
8615             var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
8616             // .constructor.prototype properties for functions that return Generator
8617             // objects. For full spec compliance, you may wish to configure your
8618             // minifier not to mangle the names of these two functions.
8619
8620             function Generator() {}
8621
8622             function GeneratorFunction() {}
8623
8624             function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
8625             // don't natively support it.
8626
8627
8628             var IteratorPrototype = {};
8629
8630             IteratorPrototype[iteratorSymbol] = function () {
8631               return this;
8632             };
8633
8634             var getProto = Object.getPrototypeOf;
8635             var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
8636
8637             if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
8638               // This environment has a native %IteratorPrototype%; use it instead
8639               // of the polyfill.
8640               IteratorPrototype = NativeIteratorPrototype;
8641             }
8642
8643             var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
8644             GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
8645             GeneratorFunctionPrototype.constructor = GeneratorFunction;
8646             GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
8647             // Iterator interface in terms of a single ._invoke method.
8648
8649             function defineIteratorMethods(prototype) {
8650               ["next", "throw", "return"].forEach(function (method) {
8651                 define(prototype, method, function (arg) {
8652                   return this._invoke(method, arg);
8653                 });
8654               });
8655             }
8656
8657             exports.isGeneratorFunction = function (genFun) {
8658               var ctor = typeof genFun === "function" && genFun.constructor;
8659               return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
8660               // do is to check its .name property.
8661               (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
8662             };
8663
8664             exports.mark = function (genFun) {
8665               if (Object.setPrototypeOf) {
8666                 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
8667               } else {
8668                 genFun.__proto__ = GeneratorFunctionPrototype;
8669                 define(genFun, toStringTagSymbol, "GeneratorFunction");
8670               }
8671
8672               genFun.prototype = Object.create(Gp);
8673               return genFun;
8674             }; // Within the body of any async function, `await x` is transformed to
8675             // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
8676             // `hasOwn.call(value, "__await")` to determine if the yielded value is
8677             // meant to be awaited.
8678
8679
8680             exports.awrap = function (arg) {
8681               return {
8682                 __await: arg
8683               };
8684             };
8685
8686             function AsyncIterator(generator, PromiseImpl) {
8687               function invoke(method, arg, resolve, reject) {
8688                 var record = tryCatch(generator[method], generator, arg);
8689
8690                 if (record.type === "throw") {
8691                   reject(record.arg);
8692                 } else {
8693                   var result = record.arg;
8694                   var value = result.value;
8695
8696                   if (value && _typeof(value) === "object" && hasOwn.call(value, "__await")) {
8697                     return PromiseImpl.resolve(value.__await).then(function (value) {
8698                       invoke("next", value, resolve, reject);
8699                     }, function (err) {
8700                       invoke("throw", err, resolve, reject);
8701                     });
8702                   }
8703
8704                   return PromiseImpl.resolve(value).then(function (unwrapped) {
8705                     // When a yielded Promise is resolved, its final value becomes
8706                     // the .value of the Promise<{value,done}> result for the
8707                     // current iteration.
8708                     result.value = unwrapped;
8709                     resolve(result);
8710                   }, function (error) {
8711                     // If a rejected Promise was yielded, throw the rejection back
8712                     // into the async generator function so it can be handled there.
8713                     return invoke("throw", error, resolve, reject);
8714                   });
8715                 }
8716               }
8717
8718               var previousPromise;
8719
8720               function enqueue(method, arg) {
8721                 function callInvokeWithMethodAndArg() {
8722                   return new PromiseImpl(function (resolve, reject) {
8723                     invoke(method, arg, resolve, reject);
8724                   });
8725                 }
8726
8727                 return previousPromise = // If enqueue has been called before, then we want to wait until
8728                 // all previous Promises have been resolved before calling invoke,
8729                 // so that results are always delivered in the correct order. If
8730                 // enqueue has not been called before, then it is important to
8731                 // call invoke immediately, without waiting on a callback to fire,
8732                 // so that the async generator function has the opportunity to do
8733                 // any necessary setup in a predictable way. This predictability
8734                 // is why the Promise constructor synchronously invokes its
8735                 // executor callback, and why async functions synchronously
8736                 // execute code before the first await. Since we implement simple
8737                 // async functions in terms of async generators, it is especially
8738                 // important to get this right, even though it requires care.
8739                 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
8740                 // invocations of the iterator.
8741                 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
8742               } // Define the unified helper method that is used to implement .next,
8743               // .throw, and .return (see defineIteratorMethods).
8744
8745
8746               this._invoke = enqueue;
8747             }
8748
8749             defineIteratorMethods(AsyncIterator.prototype);
8750
8751             AsyncIterator.prototype[asyncIteratorSymbol] = function () {
8752               return this;
8753             };
8754
8755             exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
8756             // AsyncIterator objects; they just return a Promise for the value of
8757             // the final result produced by the iterator.
8758
8759             exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
8760               if (PromiseImpl === void 0) PromiseImpl = Promise;
8761               var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
8762               return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
8763               : iter.next().then(function (result) {
8764                 return result.done ? result.value : iter.next();
8765               });
8766             };
8767
8768             function makeInvokeMethod(innerFn, self, context) {
8769               var state = GenStateSuspendedStart;
8770               return function invoke(method, arg) {
8771                 if (state === GenStateExecuting) {
8772                   throw new Error("Generator is already running");
8773                 }
8774
8775                 if (state === GenStateCompleted) {
8776                   if (method === "throw") {
8777                     throw arg;
8778                   } // Be forgiving, per 25.3.3.3.3 of the spec:
8779                   // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
8780
8781
8782                   return doneResult();
8783                 }
8784
8785                 context.method = method;
8786                 context.arg = arg;
8787
8788                 while (true) {
8789                   var delegate = context.delegate;
8790
8791                   if (delegate) {
8792                     var delegateResult = maybeInvokeDelegate(delegate, context);
8793
8794                     if (delegateResult) {
8795                       if (delegateResult === ContinueSentinel) continue;
8796                       return delegateResult;
8797                     }
8798                   }
8799
8800                   if (context.method === "next") {
8801                     // Setting context._sent for legacy support of Babel's
8802                     // function.sent implementation.
8803                     context.sent = context._sent = context.arg;
8804                   } else if (context.method === "throw") {
8805                     if (state === GenStateSuspendedStart) {
8806                       state = GenStateCompleted;
8807                       throw context.arg;
8808                     }
8809
8810                     context.dispatchException(context.arg);
8811                   } else if (context.method === "return") {
8812                     context.abrupt("return", context.arg);
8813                   }
8814
8815                   state = GenStateExecuting;
8816                   var record = tryCatch(innerFn, self, context);
8817
8818                   if (record.type === "normal") {
8819                     // If an exception is thrown from innerFn, we leave state ===
8820                     // GenStateExecuting and loop back for another invocation.
8821                     state = context.done ? GenStateCompleted : GenStateSuspendedYield;
8822
8823                     if (record.arg === ContinueSentinel) {
8824                       continue;
8825                     }
8826
8827                     return {
8828                       value: record.arg,
8829                       done: context.done
8830                     };
8831                   } else if (record.type === "throw") {
8832                     state = GenStateCompleted; // Dispatch the exception by looping back around to the
8833                     // context.dispatchException(context.arg) call above.
8834
8835                     context.method = "throw";
8836                     context.arg = record.arg;
8837                   }
8838                 }
8839               };
8840             } // Call delegate.iterator[context.method](context.arg) and handle the
8841             // result, either by returning a { value, done } result from the
8842             // delegate iterator, or by modifying context.method and context.arg,
8843             // setting context.delegate to null, and returning the ContinueSentinel.
8844
8845
8846             function maybeInvokeDelegate(delegate, context) {
8847               var method = delegate.iterator[context.method];
8848
8849               if (method === undefined$1) {
8850                 // A .throw or .return when the delegate iterator has no .throw
8851                 // method always terminates the yield* loop.
8852                 context.delegate = null;
8853
8854                 if (context.method === "throw") {
8855                   // Note: ["return"] must be used for ES3 parsing compatibility.
8856                   if (delegate.iterator["return"]) {
8857                     // If the delegate iterator has a return method, give it a
8858                     // chance to clean up.
8859                     context.method = "return";
8860                     context.arg = undefined$1;
8861                     maybeInvokeDelegate(delegate, context);
8862
8863                     if (context.method === "throw") {
8864                       // If maybeInvokeDelegate(context) changed context.method from
8865                       // "return" to "throw", let that override the TypeError below.
8866                       return ContinueSentinel;
8867                     }
8868                   }
8869
8870                   context.method = "throw";
8871                   context.arg = new TypeError("The iterator does not provide a 'throw' method");
8872                 }
8873
8874                 return ContinueSentinel;
8875               }
8876
8877               var record = tryCatch(method, delegate.iterator, context.arg);
8878
8879               if (record.type === "throw") {
8880                 context.method = "throw";
8881                 context.arg = record.arg;
8882                 context.delegate = null;
8883                 return ContinueSentinel;
8884               }
8885
8886               var info = record.arg;
8887
8888               if (!info) {
8889                 context.method = "throw";
8890                 context.arg = new TypeError("iterator result is not an object");
8891                 context.delegate = null;
8892                 return ContinueSentinel;
8893               }
8894
8895               if (info.done) {
8896                 // Assign the result of the finished delegate to the temporary
8897                 // variable specified by delegate.resultName (see delegateYield).
8898                 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
8899
8900                 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
8901                 // exception, let the outer generator proceed normally. If
8902                 // context.method was "next", forget context.arg since it has been
8903                 // "consumed" by the delegate iterator. If context.method was
8904                 // "return", allow the original .return call to continue in the
8905                 // outer generator.
8906
8907                 if (context.method !== "return") {
8908                   context.method = "next";
8909                   context.arg = undefined$1;
8910                 }
8911               } else {
8912                 // Re-yield the result returned by the delegate method.
8913                 return info;
8914               } // The delegate iterator is finished, so forget it and continue with
8915               // the outer generator.
8916
8917
8918               context.delegate = null;
8919               return ContinueSentinel;
8920             } // Define Generator.prototype.{next,throw,return} in terms of the
8921             // unified ._invoke helper method.
8922
8923
8924             defineIteratorMethods(Gp);
8925             define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
8926             // @@iterator function is called on it. Some browsers' implementations of the
8927             // iterator prototype chain incorrectly implement this, causing the Generator
8928             // object to not be returned from this call. This ensures that doesn't happen.
8929             // See https://github.com/facebook/regenerator/issues/274 for more details.
8930
8931             Gp[iteratorSymbol] = function () {
8932               return this;
8933             };
8934
8935             Gp.toString = function () {
8936               return "[object Generator]";
8937             };
8938
8939             function pushTryEntry(locs) {
8940               var entry = {
8941                 tryLoc: locs[0]
8942               };
8943
8944               if (1 in locs) {
8945                 entry.catchLoc = locs[1];
8946               }
8947
8948               if (2 in locs) {
8949                 entry.finallyLoc = locs[2];
8950                 entry.afterLoc = locs[3];
8951               }
8952
8953               this.tryEntries.push(entry);
8954             }
8955
8956             function resetTryEntry(entry) {
8957               var record = entry.completion || {};
8958               record.type = "normal";
8959               delete record.arg;
8960               entry.completion = record;
8961             }
8962
8963             function Context(tryLocsList) {
8964               // The root entry object (effectively a try statement without a catch
8965               // or a finally block) gives us a place to store values thrown from
8966               // locations where there is no enclosing try statement.
8967               this.tryEntries = [{
8968                 tryLoc: "root"
8969               }];
8970               tryLocsList.forEach(pushTryEntry, this);
8971               this.reset(true);
8972             }
8973
8974             exports.keys = function (object) {
8975               var keys = [];
8976
8977               for (var key in object) {
8978                 keys.push(key);
8979               }
8980
8981               keys.reverse(); // Rather than returning an object with a next method, we keep
8982               // things simple and return the next function itself.
8983
8984               return function next() {
8985                 while (keys.length) {
8986                   var key = keys.pop();
8987
8988                   if (key in object) {
8989                     next.value = key;
8990                     next.done = false;
8991                     return next;
8992                   }
8993                 } // To avoid creating an additional object, we just hang the .value
8994                 // and .done properties off the next function object itself. This
8995                 // also ensures that the minifier will not anonymize the function.
8996
8997
8998                 next.done = true;
8999                 return next;
9000               };
9001             };
9002
9003             function values(iterable) {
9004               if (iterable) {
9005                 var iteratorMethod = iterable[iteratorSymbol];
9006
9007                 if (iteratorMethod) {
9008                   return iteratorMethod.call(iterable);
9009                 }
9010
9011                 if (typeof iterable.next === "function") {
9012                   return iterable;
9013                 }
9014
9015                 if (!isNaN(iterable.length)) {
9016                   var i = -1,
9017                       next = function next() {
9018                     while (++i < iterable.length) {
9019                       if (hasOwn.call(iterable, i)) {
9020                         next.value = iterable[i];
9021                         next.done = false;
9022                         return next;
9023                       }
9024                     }
9025
9026                     next.value = undefined$1;
9027                     next.done = true;
9028                     return next;
9029                   };
9030
9031                   return next.next = next;
9032                 }
9033               } // Return an iterator with no values.
9034
9035
9036               return {
9037                 next: doneResult
9038               };
9039             }
9040
9041             exports.values = values;
9042
9043             function doneResult() {
9044               return {
9045                 value: undefined$1,
9046                 done: true
9047               };
9048             }
9049
9050             Context.prototype = {
9051               constructor: Context,
9052               reset: function reset(skipTempReset) {
9053                 this.prev = 0;
9054                 this.next = 0; // Resetting context._sent for legacy support of Babel's
9055                 // function.sent implementation.
9056
9057                 this.sent = this._sent = undefined$1;
9058                 this.done = false;
9059                 this.delegate = null;
9060                 this.method = "next";
9061                 this.arg = undefined$1;
9062                 this.tryEntries.forEach(resetTryEntry);
9063
9064                 if (!skipTempReset) {
9065                   for (var name in this) {
9066                     // Not sure about the optimal order of these conditions:
9067                     if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
9068                       this[name] = undefined$1;
9069                     }
9070                   }
9071                 }
9072               },
9073               stop: function stop() {
9074                 this.done = true;
9075                 var rootEntry = this.tryEntries[0];
9076                 var rootRecord = rootEntry.completion;
9077
9078                 if (rootRecord.type === "throw") {
9079                   throw rootRecord.arg;
9080                 }
9081
9082                 return this.rval;
9083               },
9084               dispatchException: function dispatchException(exception) {
9085                 if (this.done) {
9086                   throw exception;
9087                 }
9088
9089                 var context = this;
9090
9091                 function handle(loc, caught) {
9092                   record.type = "throw";
9093                   record.arg = exception;
9094                   context.next = loc;
9095
9096                   if (caught) {
9097                     // If the dispatched exception was caught by a catch block,
9098                     // then let that catch block handle the exception normally.
9099                     context.method = "next";
9100                     context.arg = undefined$1;
9101                   }
9102
9103                   return !!caught;
9104                 }
9105
9106                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9107                   var entry = this.tryEntries[i];
9108                   var record = entry.completion;
9109
9110                   if (entry.tryLoc === "root") {
9111                     // Exception thrown outside of any try block that could handle
9112                     // it, so set the completion value of the entire function to
9113                     // throw the exception.
9114                     return handle("end");
9115                   }
9116
9117                   if (entry.tryLoc <= this.prev) {
9118                     var hasCatch = hasOwn.call(entry, "catchLoc");
9119                     var hasFinally = hasOwn.call(entry, "finallyLoc");
9120
9121                     if (hasCatch && hasFinally) {
9122                       if (this.prev < entry.catchLoc) {
9123                         return handle(entry.catchLoc, true);
9124                       } else if (this.prev < entry.finallyLoc) {
9125                         return handle(entry.finallyLoc);
9126                       }
9127                     } else if (hasCatch) {
9128                       if (this.prev < entry.catchLoc) {
9129                         return handle(entry.catchLoc, true);
9130                       }
9131                     } else if (hasFinally) {
9132                       if (this.prev < entry.finallyLoc) {
9133                         return handle(entry.finallyLoc);
9134                       }
9135                     } else {
9136                       throw new Error("try statement without catch or finally");
9137                     }
9138                   }
9139                 }
9140               },
9141               abrupt: function abrupt(type, arg) {
9142                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9143                   var entry = this.tryEntries[i];
9144
9145                   if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
9146                     var finallyEntry = entry;
9147                     break;
9148                   }
9149                 }
9150
9151                 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
9152                   // Ignore the finally entry if control is not jumping to a
9153                   // location outside the try/catch block.
9154                   finallyEntry = null;
9155                 }
9156
9157                 var record = finallyEntry ? finallyEntry.completion : {};
9158                 record.type = type;
9159                 record.arg = arg;
9160
9161                 if (finallyEntry) {
9162                   this.method = "next";
9163                   this.next = finallyEntry.finallyLoc;
9164                   return ContinueSentinel;
9165                 }
9166
9167                 return this.complete(record);
9168               },
9169               complete: function complete(record, afterLoc) {
9170                 if (record.type === "throw") {
9171                   throw record.arg;
9172                 }
9173
9174                 if (record.type === "break" || record.type === "continue") {
9175                   this.next = record.arg;
9176                 } else if (record.type === "return") {
9177                   this.rval = this.arg = record.arg;
9178                   this.method = "return";
9179                   this.next = "end";
9180                 } else if (record.type === "normal" && afterLoc) {
9181                   this.next = afterLoc;
9182                 }
9183
9184                 return ContinueSentinel;
9185               },
9186               finish: function finish(finallyLoc) {
9187                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9188                   var entry = this.tryEntries[i];
9189
9190                   if (entry.finallyLoc === finallyLoc) {
9191                     this.complete(entry.completion, entry.afterLoc);
9192                     resetTryEntry(entry);
9193                     return ContinueSentinel;
9194                   }
9195                 }
9196               },
9197               "catch": function _catch(tryLoc) {
9198                 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
9199                   var entry = this.tryEntries[i];
9200
9201                   if (entry.tryLoc === tryLoc) {
9202                     var record = entry.completion;
9203
9204                     if (record.type === "throw") {
9205                       var thrown = record.arg;
9206                       resetTryEntry(entry);
9207                     }
9208
9209                     return thrown;
9210                   }
9211                 } // The context.catch method must only be called with a location
9212                 // argument that corresponds to a known catch block.
9213
9214
9215                 throw new Error("illegal catch attempt");
9216               },
9217               delegateYield: function delegateYield(iterable, resultName, nextLoc) {
9218                 this.delegate = {
9219                   iterator: values(iterable),
9220                   resultName: resultName,
9221                   nextLoc: nextLoc
9222                 };
9223
9224                 if (this.method === "next") {
9225                   // Deliberately forget the last sent value so that we don't
9226                   // accidentally pass it on to the delegate.
9227                   this.arg = undefined$1;
9228                 }
9229
9230                 return ContinueSentinel;
9231               }
9232             }; // Regardless of whether this script is executing as a CommonJS module
9233             // or not, return the runtime object so that we can declare the variable
9234             // regeneratorRuntime in the outer scope, which allows this module to be
9235             // injected easily by `bin/regenerator --include-runtime script.js`.
9236
9237             return exports;
9238           }( // If this script is executing as a CommonJS module, use module.exports
9239           // as the regeneratorRuntime namespace. Otherwise create a new empty
9240           // object. Either way, the resulting object will be used to initialize
9241           // the regeneratorRuntime variable at the top of this file.
9242            module.exports );
9243
9244           try {
9245             regeneratorRuntime = runtime;
9246           } catch (accidentalStrictMode) {
9247             // This module should not be running in strict mode, so the above
9248             // assignment should always work unless something is misconfigured. Just
9249             // in case runtime.js accidentally runs in strict mode, we can escape
9250             // strict mode using a global Function call. This could conceivably fail
9251             // if a Content Security Policy forbids using Function, but in that case
9252             // the proper solution is to fix the accidental strict mode problem. If
9253             // you've misconfigured your bundler to force strict mode and applied a
9254             // CSP to forbid Function, and you're not willing to fix either of those
9255             // problems, please detail your unique predicament in a GitHub issue.
9256             Function("r", "regeneratorRuntime = r")(runtime);
9257           }
9258         });
9259
9260         var _marked = /*#__PURE__*/regeneratorRuntime.mark(numbers);
9261
9262         function number (x) {
9263           return x === null ? NaN : +x;
9264         }
9265         function numbers(values, valueof) {
9266           var _iterator, _step, value, index, _iterator2, _step2, _value;
9267
9268           return regeneratorRuntime.wrap(function numbers$(_context) {
9269             while (1) {
9270               switch (_context.prev = _context.next) {
9271                 case 0:
9272                   if (!(valueof === undefined)) {
9273                     _context.next = 21;
9274                     break;
9275                   }
9276
9277                   _iterator = _createForOfIteratorHelper(values);
9278                   _context.prev = 2;
9279
9280                   _iterator.s();
9281
9282                 case 4:
9283                   if ((_step = _iterator.n()).done) {
9284                     _context.next = 11;
9285                     break;
9286                   }
9287
9288                   value = _step.value;
9289
9290                   if (!(value != null && (value = +value) >= value)) {
9291                     _context.next = 9;
9292                     break;
9293                   }
9294
9295                   _context.next = 9;
9296                   return value;
9297
9298                 case 9:
9299                   _context.next = 4;
9300                   break;
9301
9302                 case 11:
9303                   _context.next = 16;
9304                   break;
9305
9306                 case 13:
9307                   _context.prev = 13;
9308                   _context.t0 = _context["catch"](2);
9309
9310                   _iterator.e(_context.t0);
9311
9312                 case 16:
9313                   _context.prev = 16;
9314
9315                   _iterator.f();
9316
9317                   return _context.finish(16);
9318
9319                 case 19:
9320                   _context.next = 40;
9321                   break;
9322
9323                 case 21:
9324                   index = -1;
9325                   _iterator2 = _createForOfIteratorHelper(values);
9326                   _context.prev = 23;
9327
9328                   _iterator2.s();
9329
9330                 case 25:
9331                   if ((_step2 = _iterator2.n()).done) {
9332                     _context.next = 32;
9333                     break;
9334                   }
9335
9336                   _value = _step2.value;
9337
9338                   if (!((_value = valueof(_value, ++index, values)) != null && (_value = +_value) >= _value)) {
9339                     _context.next = 30;
9340                     break;
9341                   }
9342
9343                   _context.next = 30;
9344                   return _value;
9345
9346                 case 30:
9347                   _context.next = 25;
9348                   break;
9349
9350                 case 32:
9351                   _context.next = 37;
9352                   break;
9353
9354                 case 34:
9355                   _context.prev = 34;
9356                   _context.t1 = _context["catch"](23);
9357
9358                   _iterator2.e(_context.t1);
9359
9360                 case 37:
9361                   _context.prev = 37;
9362
9363                   _iterator2.f();
9364
9365                   return _context.finish(37);
9366
9367                 case 40:
9368                 case "end":
9369                   return _context.stop();
9370               }
9371             }
9372           }, _marked, null, [[2, 13, 16, 19], [23, 34, 37, 40]]);
9373         }
9374
9375         var ascendingBisect = d3_bisector(d3_ascending);
9376         var bisectRight = ascendingBisect.right;
9377         var bisectCenter = d3_bisector(number).center;
9378
9379         // `Array.prototype.fill` method
9380         // https://tc39.github.io/ecma262/#sec-array.prototype.fill
9381         _export({ target: 'Array', proto: true }, {
9382           fill: arrayFill
9383         });
9384
9385         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
9386         addToUnscopables('fill');
9387
9388         var INCORRECT_ITERATION$1 = !checkCorrectnessOfIteration(function (iterable) {
9389           Array.from(iterable);
9390         });
9391
9392         // `Array.from` method
9393         // https://tc39.github.io/ecma262/#sec-array.from
9394         _export({ target: 'Array', stat: true, forced: INCORRECT_ITERATION$1 }, {
9395           from: arrayFrom
9396         });
9397
9398         var $some$1 = arrayIteration.some;
9399
9400
9401
9402         var STRICT_METHOD$4 = arrayMethodIsStrict('some');
9403         var USES_TO_LENGTH$7 = arrayMethodUsesToLength('some');
9404
9405         // `Array.prototype.some` method
9406         // https://tc39.github.io/ecma262/#sec-array.prototype.some
9407         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$4 || !USES_TO_LENGTH$7 }, {
9408           some: function some(callbackfn /* , thisArg */) {
9409             return $some$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
9410           }
9411         });
9412
9413         // `Float64Array` constructor
9414         // https://tc39.github.io/ecma262/#sec-typedarray-objects
9415         typedArrayConstructor('Float64', function (init) {
9416           return function Float64Array(data, byteOffset, length) {
9417             return init(this, data, byteOffset, length);
9418           };
9419         });
9420
9421         var exportTypedArrayStaticMethod$1 = arrayBufferViewCore.exportTypedArrayStaticMethod;
9422
9423
9424         // `%TypedArray%.from` method
9425         // https://tc39.github.io/ecma262/#sec-%typedarray%.from
9426         exportTypedArrayStaticMethod$1('from', typedArrayFrom, typedArrayConstructorsRequireWrappers);
9427
9428         function d3_descending (a, b) {
9429           return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
9430         }
9431
9432         // https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
9433         var Adder = /*#__PURE__*/function () {
9434           function Adder() {
9435             _classCallCheck(this, Adder);
9436
9437             this._partials = new Float64Array(32);
9438             this._n = 0;
9439           }
9440
9441           _createClass(Adder, [{
9442             key: "add",
9443             value: function add(x) {
9444               var p = this._partials;
9445               var i = 0;
9446
9447               for (var j = 0; j < this._n && j < 32; j++) {
9448                 var y = p[j],
9449                     hi = x + y,
9450                     lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
9451                 if (lo) p[i++] = lo;
9452                 x = hi;
9453               }
9454
9455               p[i] = x;
9456               this._n = i + 1;
9457               return this;
9458             }
9459           }, {
9460             key: "valueOf",
9461             value: function valueOf() {
9462               var p = this._partials;
9463               var n = this._n,
9464                   x,
9465                   y,
9466                   lo,
9467                   hi = 0;
9468
9469               if (n > 0) {
9470                 hi = p[--n];
9471
9472                 while (n > 0) {
9473                   x = hi;
9474                   y = p[--n];
9475                   hi = x + y;
9476                   lo = y - (hi - x);
9477                   if (lo) break;
9478                 }
9479
9480                 if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
9481                   y = lo * 2;
9482                   x = hi + y;
9483                   if (y == x - hi) hi = x;
9484                 }
9485               }
9486
9487               return hi;
9488             }
9489           }]);
9490
9491           return Adder;
9492         }();
9493
9494         // `Map` constructor
9495         // https://tc39.github.io/ecma262/#sec-map-objects
9496         var es_map = collection('Map', function (init) {
9497           return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };
9498         }, collectionStrong);
9499
9500         var e10 = Math.sqrt(50),
9501             e5 = Math.sqrt(10),
9502             e2 = Math.sqrt(2);
9503         function ticks (start, stop, count) {
9504           var reverse,
9505               i = -1,
9506               n,
9507               ticks,
9508               step;
9509           stop = +stop, start = +start, count = +count;
9510           if (start === stop && count > 0) return [start];
9511           if (reverse = stop < start) n = start, start = stop, stop = n;
9512           if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
9513
9514           if (step > 0) {
9515             start = Math.ceil(start / step);
9516             stop = Math.floor(stop / step);
9517             ticks = new Array(n = Math.ceil(stop - start + 1));
9518
9519             while (++i < n) {
9520               ticks[i] = (start + i) * step;
9521             }
9522           } else {
9523             step = -step;
9524             start = Math.ceil(start * step);
9525             stop = Math.floor(stop * step);
9526             ticks = new Array(n = Math.ceil(stop - start + 1));
9527
9528             while (++i < n) {
9529               ticks[i] = (start + i) / step;
9530             }
9531           }
9532
9533           if (reverse) ticks.reverse();
9534           return ticks;
9535         }
9536         function tickIncrement(start, stop, count) {
9537           var step = (stop - start) / Math.max(0, count),
9538               power = Math.floor(Math.log(step) / Math.LN10),
9539               error = step / Math.pow(10, power);
9540           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);
9541         }
9542         function tickStep(start, stop, count) {
9543           var step0 = Math.abs(stop - start) / Math.max(0, count),
9544               step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
9545               error = step0 / step1;
9546           if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
9547           return stop < start ? -step1 : step1;
9548         }
9549
9550         function max$4(values, valueof) {
9551           var max;
9552
9553           if (valueof === undefined) {
9554             var _iterator = _createForOfIteratorHelper(values),
9555                 _step;
9556
9557             try {
9558               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9559                 var value = _step.value;
9560
9561                 if (value != null && (max < value || max === undefined && value >= value)) {
9562                   max = value;
9563                 }
9564               }
9565             } catch (err) {
9566               _iterator.e(err);
9567             } finally {
9568               _iterator.f();
9569             }
9570           } else {
9571             var index = -1;
9572
9573             var _iterator2 = _createForOfIteratorHelper(values),
9574                 _step2;
9575
9576             try {
9577               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9578                 var _value = _step2.value;
9579
9580                 if ((_value = valueof(_value, ++index, values)) != null && (max < _value || max === undefined && _value >= _value)) {
9581                   max = _value;
9582                 }
9583               }
9584             } catch (err) {
9585               _iterator2.e(err);
9586             } finally {
9587               _iterator2.f();
9588             }
9589           }
9590
9591           return max;
9592         }
9593
9594         function min$7(values, valueof) {
9595           var min;
9596
9597           if (valueof === undefined) {
9598             var _iterator = _createForOfIteratorHelper(values),
9599                 _step;
9600
9601             try {
9602               for (_iterator.s(); !(_step = _iterator.n()).done;) {
9603                 var value = _step.value;
9604
9605                 if (value != null && (min > value || min === undefined && value >= value)) {
9606                   min = value;
9607                 }
9608               }
9609             } catch (err) {
9610               _iterator.e(err);
9611             } finally {
9612               _iterator.f();
9613             }
9614           } else {
9615             var index = -1;
9616
9617             var _iterator2 = _createForOfIteratorHelper(values),
9618                 _step2;
9619
9620             try {
9621               for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
9622                 var _value = _step2.value;
9623
9624                 if ((_value = valueof(_value, ++index, values)) != null && (min > _value || min === undefined && _value >= _value)) {
9625                   min = _value;
9626                 }
9627               }
9628             } catch (err) {
9629               _iterator2.e(err);
9630             } finally {
9631               _iterator2.f();
9632             }
9633           }
9634
9635           return min;
9636         }
9637
9638         // ISC license, Copyright 2018 Vladimir Agafonkin.
9639
9640         function quickselect(array, k) {
9641           var left = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
9642           var right = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : array.length - 1;
9643           var compare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : d3_ascending;
9644
9645           while (right > left) {
9646             if (right - left > 600) {
9647               var n = right - left + 1;
9648               var m = k - left + 1;
9649               var z = Math.log(n);
9650               var s = 0.5 * Math.exp(2 * z / 3);
9651               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
9652               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
9653               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
9654               quickselect(array, k, newLeft, newRight, compare);
9655             }
9656
9657             var t = array[k];
9658             var i = left;
9659             var j = right;
9660             swap(array, left, k);
9661             if (compare(array[right], t) > 0) swap(array, left, right);
9662
9663             while (i < j) {
9664               swap(array, i, j), ++i, --j;
9665
9666               while (compare(array[i], t) < 0) {
9667                 ++i;
9668               }
9669
9670               while (compare(array[j], t) > 0) {
9671                 --j;
9672               }
9673             }
9674
9675             if (compare(array[left], t) === 0) swap(array, left, j);else ++j, swap(array, j, right);
9676             if (j <= k) left = j + 1;
9677             if (k <= j) right = j - 1;
9678           }
9679
9680           return array;
9681         }
9682
9683         function swap(array, i, j) {
9684           var t = array[i];
9685           array[i] = array[j];
9686           array[j] = t;
9687         }
9688
9689         function quantile(values, p, valueof) {
9690           values = Float64Array.from(numbers(values, valueof));
9691           if (!(n = values.length)) return;
9692           if ((p = +p) <= 0 || n < 2) return min$7(values);
9693           if (p >= 1) return max$4(values);
9694           var n,
9695               i = (n - 1) * p,
9696               i0 = Math.floor(i),
9697               value0 = max$4(quickselect(values, i0).subarray(0, i0 + 1)),
9698               value1 = min$7(values.subarray(i0 + 1));
9699           return value0 + (value1 - value0) * (i - i0);
9700         }
9701
9702         function d3_median (values, valueof) {
9703           return quantile(values, 0.5, valueof);
9704         }
9705
9706         var _marked$1 = /*#__PURE__*/regeneratorRuntime.mark(flatten);
9707
9708         function flatten(arrays) {
9709           var _iterator, _step, array;
9710
9711           return regeneratorRuntime.wrap(function flatten$(_context) {
9712             while (1) {
9713               switch (_context.prev = _context.next) {
9714                 case 0:
9715                   _iterator = _createForOfIteratorHelper(arrays);
9716                   _context.prev = 1;
9717
9718                   _iterator.s();
9719
9720                 case 3:
9721                   if ((_step = _iterator.n()).done) {
9722                     _context.next = 8;
9723                     break;
9724                   }
9725
9726                   array = _step.value;
9727                   return _context.delegateYield(array, "t0", 6);
9728
9729                 case 6:
9730                   _context.next = 3;
9731                   break;
9732
9733                 case 8:
9734                   _context.next = 13;
9735                   break;
9736
9737                 case 10:
9738                   _context.prev = 10;
9739                   _context.t1 = _context["catch"](1);
9740
9741                   _iterator.e(_context.t1);
9742
9743                 case 13:
9744                   _context.prev = 13;
9745
9746                   _iterator.f();
9747
9748                   return _context.finish(13);
9749
9750                 case 16:
9751                 case "end":
9752                   return _context.stop();
9753               }
9754             }
9755           }, _marked$1, null, [[1, 10, 13, 16]]);
9756         }
9757
9758         function merge(arrays) {
9759           return Array.from(flatten(arrays));
9760         }
9761
9762         function range (start, stop, step) {
9763           start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
9764           var i = -1,
9765               n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
9766               range = new Array(n);
9767
9768           while (++i < n) {
9769             range[i] = start + i * step;
9770           }
9771
9772           return range;
9773         }
9774
9775         var test$2 = [];
9776         var nativeSort = test$2.sort;
9777
9778         // IE8-
9779         var FAILS_ON_UNDEFINED = fails(function () {
9780           test$2.sort(undefined);
9781         });
9782         // V8 bug
9783         var FAILS_ON_NULL = fails(function () {
9784           test$2.sort(null);
9785         });
9786         // Old WebKit
9787         var STRICT_METHOD$5 = arrayMethodIsStrict('sort');
9788
9789         var FORCED$a = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$5;
9790
9791         // `Array.prototype.sort` method
9792         // https://tc39.github.io/ecma262/#sec-array.prototype.sort
9793         _export({ target: 'Array', proto: true, forced: FORCED$a }, {
9794           sort: function sort(comparefn) {
9795             return comparefn === undefined
9796               ? nativeSort.call(toObject(this))
9797               : nativeSort.call(toObject(this), aFunction$1(comparefn));
9798           }
9799         });
9800
9801         // `SameValue` abstract operation
9802         // https://tc39.github.io/ecma262/#sec-samevalue
9803         var sameValue = Object.is || function is(x, y) {
9804           // eslint-disable-next-line no-self-compare
9805           return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
9806         };
9807
9808         var $hypot = Math.hypot;
9809         var abs$1 = Math.abs;
9810         var sqrt = Math.sqrt;
9811
9812         // Chrome 77 bug
9813         // https://bugs.chromium.org/p/v8/issues/detail?id=9546
9814         var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity;
9815
9816         // `Math.hypot` method
9817         // https://tc39.github.io/ecma262/#sec-math.hypot
9818         _export({ target: 'Math', stat: true, forced: BUGGY }, {
9819           hypot: function hypot(value1, value2) { // eslint-disable-line no-unused-vars
9820             var sum = 0;
9821             var i = 0;
9822             var aLen = arguments.length;
9823             var larg = 0;
9824             var arg, div;
9825             while (i < aLen) {
9826               arg = abs$1(arguments[i++]);
9827               if (larg < arg) {
9828                 div = larg / arg;
9829                 sum = sum * div * div + 1;
9830                 larg = arg;
9831               } else if (arg > 0) {
9832                 div = arg / larg;
9833                 sum += div * div;
9834               } else sum += arg;
9835             }
9836             return larg === Infinity ? Infinity : larg * sqrt(sum);
9837           }
9838         });
9839
9840         // `Math.sign` method implementation
9841         // https://tc39.github.io/ecma262/#sec-math.sign
9842         var mathSign = Math.sign || function sign(x) {
9843           // eslint-disable-next-line no-self-compare
9844           return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
9845         };
9846
9847         // `Math.sign` method
9848         // https://tc39.github.io/ecma262/#sec-math.sign
9849         _export({ target: 'Math', stat: true }, {
9850           sign: mathSign
9851         });
9852
9853         var epsilon = 1e-6;
9854         var epsilon2 = 1e-12;
9855         var pi = Math.PI;
9856         var halfPi = pi / 2;
9857         var quarterPi = pi / 4;
9858         var tau = pi * 2;
9859         var degrees = 180 / pi;
9860         var radians = pi / 180;
9861         var abs$2 = Math.abs;
9862         var atan = Math.atan;
9863         var atan2 = Math.atan2;
9864         var cos = Math.cos;
9865         var exp = Math.exp;
9866         var hypot = Math.hypot;
9867         var log$1 = Math.log;
9868         var sin = Math.sin;
9869         var sign = Math.sign || function (x) {
9870           return x > 0 ? 1 : x < 0 ? -1 : 0;
9871         };
9872         var sqrt$1 = Math.sqrt;
9873         var tan = Math.tan;
9874         function acos(x) {
9875           return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
9876         }
9877         function asin(x) {
9878           return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
9879         }
9880
9881         function noop() {}
9882
9883         function streamGeometry(geometry, stream) {
9884           if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
9885             streamGeometryType[geometry.type](geometry, stream);
9886           }
9887         }
9888
9889         var streamObjectType = {
9890           Feature: function Feature(object, stream) {
9891             streamGeometry(object.geometry, stream);
9892           },
9893           FeatureCollection: function FeatureCollection(object, stream) {
9894             var features = object.features,
9895                 i = -1,
9896                 n = features.length;
9897
9898             while (++i < n) {
9899               streamGeometry(features[i].geometry, stream);
9900             }
9901           }
9902         };
9903         var streamGeometryType = {
9904           Sphere: function Sphere(object, stream) {
9905             stream.sphere();
9906           },
9907           Point: function Point(object, stream) {
9908             object = object.coordinates;
9909             stream.point(object[0], object[1], object[2]);
9910           },
9911           MultiPoint: function MultiPoint(object, stream) {
9912             var coordinates = object.coordinates,
9913                 i = -1,
9914                 n = coordinates.length;
9915
9916             while (++i < n) {
9917               object = coordinates[i], stream.point(object[0], object[1], object[2]);
9918             }
9919           },
9920           LineString: function LineString(object, stream) {
9921             streamLine(object.coordinates, stream, 0);
9922           },
9923           MultiLineString: function MultiLineString(object, stream) {
9924             var coordinates = object.coordinates,
9925                 i = -1,
9926                 n = coordinates.length;
9927
9928             while (++i < n) {
9929               streamLine(coordinates[i], stream, 0);
9930             }
9931           },
9932           Polygon: function Polygon(object, stream) {
9933             streamPolygon(object.coordinates, stream);
9934           },
9935           MultiPolygon: function MultiPolygon(object, stream) {
9936             var coordinates = object.coordinates,
9937                 i = -1,
9938                 n = coordinates.length;
9939
9940             while (++i < n) {
9941               streamPolygon(coordinates[i], stream);
9942             }
9943           },
9944           GeometryCollection: function GeometryCollection(object, stream) {
9945             var geometries = object.geometries,
9946                 i = -1,
9947                 n = geometries.length;
9948
9949             while (++i < n) {
9950               streamGeometry(geometries[i], stream);
9951             }
9952           }
9953         };
9954
9955         function streamLine(coordinates, stream, closed) {
9956           var i = -1,
9957               n = coordinates.length - closed,
9958               coordinate;
9959           stream.lineStart();
9960
9961           while (++i < n) {
9962             coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
9963           }
9964
9965           stream.lineEnd();
9966         }
9967
9968         function streamPolygon(coordinates, stream) {
9969           var i = -1,
9970               n = coordinates.length;
9971           stream.polygonStart();
9972
9973           while (++i < n) {
9974             streamLine(coordinates[i], stream, 1);
9975           }
9976
9977           stream.polygonEnd();
9978         }
9979
9980         function d3_geoStream (object, stream) {
9981           if (object && streamObjectType.hasOwnProperty(object.type)) {
9982             streamObjectType[object.type](object, stream);
9983           } else {
9984             streamGeometry(object, stream);
9985           }
9986         }
9987
9988         var areaRingSum = new Adder(); // hello?
9989
9990         var areaSum = new Adder(),
9991             lambda00,
9992             phi00,
9993             lambda0,
9994             cosPhi0,
9995             sinPhi0;
9996         var areaStream = {
9997           point: noop,
9998           lineStart: noop,
9999           lineEnd: noop,
10000           polygonStart: function polygonStart() {
10001             areaRingSum = new Adder();
10002             areaStream.lineStart = areaRingStart;
10003             areaStream.lineEnd = areaRingEnd;
10004           },
10005           polygonEnd: function polygonEnd() {
10006             var areaRing = +areaRingSum;
10007             areaSum.add(areaRing < 0 ? tau + areaRing : areaRing);
10008             this.lineStart = this.lineEnd = this.point = noop;
10009           },
10010           sphere: function sphere() {
10011             areaSum.add(tau);
10012           }
10013         };
10014
10015         function areaRingStart() {
10016           areaStream.point = areaPointFirst;
10017         }
10018
10019         function areaRingEnd() {
10020           areaPoint(lambda00, phi00);
10021         }
10022
10023         function areaPointFirst(lambda, phi) {
10024           areaStream.point = areaPoint;
10025           lambda00 = lambda, phi00 = phi;
10026           lambda *= radians, phi *= radians;
10027           lambda0 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
10028         }
10029
10030         function areaPoint(lambda, phi) {
10031           lambda *= radians, phi *= radians;
10032           phi = phi / 2 + quarterPi; // half the angular distance from south pole
10033           // Spherical excess E for a spherical triangle with vertices: south pole,
10034           // previous point, current point.  Uses a formula derived from Cagnoli’s
10035           // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
10036
10037           var dLambda = lambda - lambda0,
10038               sdLambda = dLambda >= 0 ? 1 : -1,
10039               adLambda = sdLambda * dLambda,
10040               cosPhi = cos(phi),
10041               sinPhi = sin(phi),
10042               k = sinPhi0 * sinPhi,
10043               u = cosPhi0 * cosPhi + k * cos(adLambda),
10044               v = k * sdLambda * sin(adLambda);
10045           areaRingSum.add(atan2(v, u)); // Advance the previous points.
10046
10047           lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
10048         }
10049
10050         function d3_geoArea (object) {
10051           areaSum = new Adder();
10052           d3_geoStream(object, areaStream);
10053           return areaSum * 2;
10054         }
10055
10056         function spherical(cartesian) {
10057           return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
10058         }
10059         function cartesian(spherical) {
10060           var lambda = spherical[0],
10061               phi = spherical[1],
10062               cosPhi = cos(phi);
10063           return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
10064         }
10065         function cartesianDot(a, b) {
10066           return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
10067         }
10068         function cartesianCross(a, b) {
10069           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]];
10070         } // TODO return a
10071
10072         function cartesianAddInPlace(a, b) {
10073           a[0] += b[0], a[1] += b[1], a[2] += b[2];
10074         }
10075         function cartesianScale(vector, k) {
10076           return [vector[0] * k, vector[1] * k, vector[2] * k];
10077         } // TODO return d
10078
10079         function cartesianNormalizeInPlace(d) {
10080           var l = sqrt$1(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
10081           d[0] /= l, d[1] /= l, d[2] /= l;
10082         }
10083
10084         var lambda0$1, phi0, lambda1, phi1, // bounds
10085         lambda2, // previous lambda-coordinate
10086         lambda00$1, phi00$1, // first point
10087         p0, // previous 3D point
10088         deltaSum, ranges, range$1;
10089         var boundsStream = {
10090           point: boundsPoint,
10091           lineStart: boundsLineStart,
10092           lineEnd: boundsLineEnd,
10093           polygonStart: function polygonStart() {
10094             boundsStream.point = boundsRingPoint;
10095             boundsStream.lineStart = boundsRingStart;
10096             boundsStream.lineEnd = boundsRingEnd;
10097             deltaSum = new Adder();
10098             areaStream.polygonStart();
10099           },
10100           polygonEnd: function polygonEnd() {
10101             areaStream.polygonEnd();
10102             boundsStream.point = boundsPoint;
10103             boundsStream.lineStart = boundsLineStart;
10104             boundsStream.lineEnd = boundsLineEnd;
10105             if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);else if (deltaSum > epsilon) phi1 = 90;else if (deltaSum < -epsilon) phi0 = -90;
10106             range$1[0] = lambda0$1, range$1[1] = lambda1;
10107           },
10108           sphere: function sphere() {
10109             lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
10110           }
10111         };
10112
10113         function boundsPoint(lambda, phi) {
10114           ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
10115           if (phi < phi0) phi0 = phi;
10116           if (phi > phi1) phi1 = phi;
10117         }
10118
10119         function linePoint(lambda, phi) {
10120           var p = cartesian([lambda * radians, phi * radians]);
10121
10122           if (p0) {
10123             var normal = cartesianCross(p0, p),
10124                 equatorial = [normal[1], -normal[0], 0],
10125                 inflection = cartesianCross(equatorial, normal);
10126             cartesianNormalizeInPlace(inflection);
10127             inflection = spherical(inflection);
10128             var delta = lambda - lambda2,
10129                 sign = delta > 0 ? 1 : -1,
10130                 lambdai = inflection[0] * degrees * sign,
10131                 phii,
10132                 antimeridian = abs$2(delta) > 180;
10133
10134             if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10135               phii = inflection[1] * degrees;
10136               if (phii > phi1) phi1 = phii;
10137             } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
10138               phii = -inflection[1] * degrees;
10139               if (phii < phi0) phi0 = phii;
10140             } else {
10141               if (phi < phi0) phi0 = phi;
10142               if (phi > phi1) phi1 = phi;
10143             }
10144
10145             if (antimeridian) {
10146               if (lambda < lambda2) {
10147                 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10148               } else {
10149                 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10150               }
10151             } else {
10152               if (lambda1 >= lambda0$1) {
10153                 if (lambda < lambda0$1) lambda0$1 = lambda;
10154                 if (lambda > lambda1) lambda1 = lambda;
10155               } else {
10156                 if (lambda > lambda2) {
10157                   if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
10158                 } else {
10159                   if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
10160                 }
10161               }
10162             }
10163           } else {
10164             ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
10165           }
10166
10167           if (phi < phi0) phi0 = phi;
10168           if (phi > phi1) phi1 = phi;
10169           p0 = p, lambda2 = lambda;
10170         }
10171
10172         function boundsLineStart() {
10173           boundsStream.point = linePoint;
10174         }
10175
10176         function boundsLineEnd() {
10177           range$1[0] = lambda0$1, range$1[1] = lambda1;
10178           boundsStream.point = boundsPoint;
10179           p0 = null;
10180         }
10181
10182         function boundsRingPoint(lambda, phi) {
10183           if (p0) {
10184             var delta = lambda - lambda2;
10185             deltaSum.add(abs$2(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
10186           } else {
10187             lambda00$1 = lambda, phi00$1 = phi;
10188           }
10189
10190           areaStream.point(lambda, phi);
10191           linePoint(lambda, phi);
10192         }
10193
10194         function boundsRingStart() {
10195           areaStream.lineStart();
10196         }
10197
10198         function boundsRingEnd() {
10199           boundsRingPoint(lambda00$1, phi00$1);
10200           areaStream.lineEnd();
10201           if (abs$2(deltaSum) > epsilon) lambda0$1 = -(lambda1 = 180);
10202           range$1[0] = lambda0$1, range$1[1] = lambda1;
10203           p0 = null;
10204         } // Finds the left-right distance between two longitudes.
10205         // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
10206         // the distance between ±180° to be 360°.
10207
10208
10209         function angle(lambda0, lambda1) {
10210           return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
10211         }
10212
10213         function rangeCompare(a, b) {
10214           return a[0] - b[0];
10215         }
10216
10217         function rangeContains(range, x) {
10218           return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
10219         }
10220
10221         function d3_geoBounds (feature) {
10222           var i, n, a, b, merged, deltaMax, delta;
10223           phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
10224           ranges = [];
10225           d3_geoStream(feature, boundsStream); // First, sort ranges by their minimum longitudes.
10226
10227           if (n = ranges.length) {
10228             ranges.sort(rangeCompare); // Then, merge any ranges that overlap.
10229
10230             for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
10231               b = ranges[i];
10232
10233               if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
10234                 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
10235                 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
10236               } else {
10237                 merged.push(a = b);
10238               }
10239             } // Finally, find the largest gap between the merged ranges.
10240             // The final bounding box will be the inverse of this gap.
10241
10242
10243             for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
10244               b = merged[i];
10245               if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
10246             }
10247           }
10248
10249           ranges = range$1 = null;
10250           return lambda0$1 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0$1, phi0], [lambda1, phi1]];
10251         }
10252
10253         var W0, W1, X0, Y0, Z0, X1, Y1, Z1, X2, Y2, Z2, lambda00$2, phi00$2, // first point
10254         x0, y0, z0; // previous point
10255
10256         var centroidStream = {
10257           sphere: noop,
10258           point: centroidPoint,
10259           lineStart: centroidLineStart,
10260           lineEnd: centroidLineEnd,
10261           polygonStart: function polygonStart() {
10262             centroidStream.lineStart = centroidRingStart;
10263             centroidStream.lineEnd = centroidRingEnd;
10264           },
10265           polygonEnd: function polygonEnd() {
10266             centroidStream.lineStart = centroidLineStart;
10267             centroidStream.lineEnd = centroidLineEnd;
10268           }
10269         }; // Arithmetic mean of Cartesian vectors.
10270
10271         function centroidPoint(lambda, phi) {
10272           lambda *= radians, phi *= radians;
10273           var cosPhi = cos(phi);
10274           centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
10275         }
10276
10277         function centroidPointCartesian(x, y, z) {
10278           ++W0;
10279           X0 += (x - X0) / W0;
10280           Y0 += (y - Y0) / W0;
10281           Z0 += (z - Z0) / W0;
10282         }
10283
10284         function centroidLineStart() {
10285           centroidStream.point = centroidLinePointFirst;
10286         }
10287
10288         function centroidLinePointFirst(lambda, phi) {
10289           lambda *= radians, phi *= radians;
10290           var cosPhi = cos(phi);
10291           x0 = cosPhi * cos(lambda);
10292           y0 = cosPhi * sin(lambda);
10293           z0 = sin(phi);
10294           centroidStream.point = centroidLinePoint;
10295           centroidPointCartesian(x0, y0, z0);
10296         }
10297
10298         function centroidLinePoint(lambda, phi) {
10299           lambda *= radians, phi *= radians;
10300           var cosPhi = cos(phi),
10301               x = cosPhi * cos(lambda),
10302               y = cosPhi * sin(lambda),
10303               z = sin(phi),
10304               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);
10305           W1 += w;
10306           X1 += w * (x0 + (x0 = x));
10307           Y1 += w * (y0 + (y0 = y));
10308           Z1 += w * (z0 + (z0 = z));
10309           centroidPointCartesian(x0, y0, z0);
10310         }
10311
10312         function centroidLineEnd() {
10313           centroidStream.point = centroidPoint;
10314         } // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
10315         // J. Applied Mechanics 42, 239 (1975).
10316
10317
10318         function centroidRingStart() {
10319           centroidStream.point = centroidRingPointFirst;
10320         }
10321
10322         function centroidRingEnd() {
10323           centroidRingPoint(lambda00$2, phi00$2);
10324           centroidStream.point = centroidPoint;
10325         }
10326
10327         function centroidRingPointFirst(lambda, phi) {
10328           lambda00$2 = lambda, phi00$2 = phi;
10329           lambda *= radians, phi *= radians;
10330           centroidStream.point = centroidRingPoint;
10331           var cosPhi = cos(phi);
10332           x0 = cosPhi * cos(lambda);
10333           y0 = cosPhi * sin(lambda);
10334           z0 = sin(phi);
10335           centroidPointCartesian(x0, y0, z0);
10336         }
10337
10338         function centroidRingPoint(lambda, phi) {
10339           lambda *= radians, phi *= radians;
10340           var cosPhi = cos(phi),
10341               x = cosPhi * cos(lambda),
10342               y = cosPhi * sin(lambda),
10343               z = sin(phi),
10344               cx = y0 * z - z0 * y,
10345               cy = z0 * x - x0 * z,
10346               cz = x0 * y - y0 * x,
10347               m = hypot(cx, cy, cz),
10348               w = asin(m),
10349               // line weight = angle
10350           v = m && -w / m; // area weight multiplier
10351
10352           X2.add(v * cx);
10353           Y2.add(v * cy);
10354           Z2.add(v * cz);
10355           W1 += w;
10356           X1 += w * (x0 + (x0 = x));
10357           Y1 += w * (y0 + (y0 = y));
10358           Z1 += w * (z0 + (z0 = z));
10359           centroidPointCartesian(x0, y0, z0);
10360         }
10361
10362         function d3_geoCentroid (object) {
10363           W0 = W1 = X0 = Y0 = Z0 = X1 = Y1 = Z1 = 0;
10364           X2 = new Adder();
10365           Y2 = new Adder();
10366           Z2 = new Adder();
10367           d3_geoStream(object, centroidStream);
10368           var x = +X2,
10369               y = +Y2,
10370               z = +Z2,
10371               m = hypot(x, y, z); // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
10372
10373           if (m < epsilon2) {
10374             x = X1, y = Y1, z = Z1; // If the feature has zero length, fall back to arithmetic mean of point vectors.
10375
10376             if (W1 < epsilon) x = X0, y = Y0, z = Z0;
10377             m = hypot(x, y, z); // If the feature still has an undefined ccentroid, then return.
10378
10379             if (m < epsilon2) return [NaN, NaN];
10380           }
10381
10382           return [atan2(y, x) * degrees, asin(z / m) * degrees];
10383         }
10384
10385         function compose (a, b) {
10386           function compose(x, y) {
10387             return x = a(x, y), b(x[0], x[1]);
10388           }
10389
10390           if (a.invert && b.invert) compose.invert = function (x, y) {
10391             return x = b.invert(x, y), x && a.invert(x[0], x[1]);
10392           };
10393           return compose;
10394         }
10395
10396         function rotationIdentity(lambda, phi) {
10397           return [abs$2(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
10398         }
10399
10400         rotationIdentity.invert = rotationIdentity;
10401         function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
10402           return (deltaLambda %= tau) ? deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda) : deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity;
10403         }
10404
10405         function forwardRotationLambda(deltaLambda) {
10406           return function (lambda, phi) {
10407             return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
10408           };
10409         }
10410
10411         function rotationLambda(deltaLambda) {
10412           var rotation = forwardRotationLambda(deltaLambda);
10413           rotation.invert = forwardRotationLambda(-deltaLambda);
10414           return rotation;
10415         }
10416
10417         function rotationPhiGamma(deltaPhi, deltaGamma) {
10418           var cosDeltaPhi = cos(deltaPhi),
10419               sinDeltaPhi = sin(deltaPhi),
10420               cosDeltaGamma = cos(deltaGamma),
10421               sinDeltaGamma = sin(deltaGamma);
10422
10423           function rotation(lambda, phi) {
10424             var cosPhi = cos(phi),
10425                 x = cos(lambda) * cosPhi,
10426                 y = sin(lambda) * cosPhi,
10427                 z = sin(phi),
10428                 k = z * cosDeltaPhi + x * sinDeltaPhi;
10429             return [atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin(k * cosDeltaGamma + y * sinDeltaGamma)];
10430           }
10431
10432           rotation.invert = function (lambda, phi) {
10433             var cosPhi = cos(phi),
10434                 x = cos(lambda) * cosPhi,
10435                 y = sin(lambda) * cosPhi,
10436                 z = sin(phi),
10437                 k = z * cosDeltaGamma - y * sinDeltaGamma;
10438             return [atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin(k * cosDeltaPhi - x * sinDeltaPhi)];
10439           };
10440
10441           return rotation;
10442         }
10443
10444         function rotation (rotate) {
10445           rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
10446
10447           function forward(coordinates) {
10448             coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
10449             return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
10450           }
10451
10452           forward.invert = function (coordinates) {
10453             coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
10454             return coordinates[0] *= degrees, coordinates[1] *= degrees, coordinates;
10455           };
10456
10457           return forward;
10458         }
10459
10460         function circleStream(stream, radius, delta, direction, t0, t1) {
10461           if (!delta) return;
10462           var cosRadius = cos(radius),
10463               sinRadius = sin(radius),
10464               step = direction * delta;
10465
10466           if (t0 == null) {
10467             t0 = radius + direction * tau;
10468             t1 = radius - step / 2;
10469           } else {
10470             t0 = circleRadius(cosRadius, t0);
10471             t1 = circleRadius(cosRadius, t1);
10472             if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
10473           }
10474
10475           for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
10476             point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
10477             stream.point(point[0], point[1]);
10478           }
10479         } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
10480
10481         function circleRadius(cosRadius, point) {
10482           point = cartesian(point), point[0] -= cosRadius;
10483           cartesianNormalizeInPlace(point);
10484           var radius = acos(-point[1]);
10485           return ((-point[2] < 0 ? -radius : radius) + tau - epsilon) % tau;
10486         }
10487
10488         function clipBuffer () {
10489           var lines = [],
10490               line;
10491           return {
10492             point: function point(x, y, m) {
10493               line.push([x, y, m]);
10494             },
10495             lineStart: function lineStart() {
10496               lines.push(line = []);
10497             },
10498             lineEnd: noop,
10499             rejoin: function rejoin() {
10500               if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
10501             },
10502             result: function result() {
10503               var result = lines;
10504               lines = [];
10505               line = null;
10506               return result;
10507             }
10508           };
10509         }
10510
10511         function pointEqual (a, b) {
10512           return abs$2(a[0] - b[0]) < epsilon && abs$2(a[1] - b[1]) < epsilon;
10513         }
10514
10515         function Intersection(point, points, other, entry) {
10516           this.x = point;
10517           this.z = points;
10518           this.o = other; // another intersection
10519
10520           this.e = entry; // is an entry?
10521
10522           this.v = false; // visited
10523
10524           this.n = this.p = null; // next & previous
10525         } // A generalized polygon clipping algorithm: given a polygon that has been cut
10526         // into its visible line segments, and rejoins the segments by interpolating
10527         // along the clip edge.
10528
10529
10530         function clipRejoin (segments, compareIntersection, startInside, interpolate, stream) {
10531           var subject = [],
10532               clip = [],
10533               i,
10534               n;
10535           segments.forEach(function (segment) {
10536             if ((n = segment.length - 1) <= 0) return;
10537             var n,
10538                 p0 = segment[0],
10539                 p1 = segment[n],
10540                 x;
10541
10542             if (pointEqual(p0, p1)) {
10543               if (!p0[2] && !p1[2]) {
10544                 stream.lineStart();
10545
10546                 for (i = 0; i < n; ++i) {
10547                   stream.point((p0 = segment[i])[0], p0[1]);
10548                 }
10549
10550                 stream.lineEnd();
10551                 return;
10552               } // handle degenerate cases by moving the point
10553
10554
10555               p1[0] += 2 * epsilon;
10556             }
10557
10558             subject.push(x = new Intersection(p0, segment, null, true));
10559             clip.push(x.o = new Intersection(p0, null, x, false));
10560             subject.push(x = new Intersection(p1, segment, null, false));
10561             clip.push(x.o = new Intersection(p1, null, x, true));
10562           });
10563           if (!subject.length) return;
10564           clip.sort(compareIntersection);
10565           link(subject);
10566           link(clip);
10567
10568           for (i = 0, n = clip.length; i < n; ++i) {
10569             clip[i].e = startInside = !startInside;
10570           }
10571
10572           var start = subject[0],
10573               points,
10574               point;
10575
10576           while (1) {
10577             // Find first unvisited intersection.
10578             var current = start,
10579                 isSubject = true;
10580
10581             while (current.v) {
10582               if ((current = current.n) === start) return;
10583             }
10584
10585             points = current.z;
10586             stream.lineStart();
10587
10588             do {
10589               current.v = current.o.v = true;
10590
10591               if (current.e) {
10592                 if (isSubject) {
10593                   for (i = 0, n = points.length; i < n; ++i) {
10594                     stream.point((point = points[i])[0], point[1]);
10595                   }
10596                 } else {
10597                   interpolate(current.x, current.n.x, 1, stream);
10598                 }
10599
10600                 current = current.n;
10601               } else {
10602                 if (isSubject) {
10603                   points = current.p.z;
10604
10605                   for (i = points.length - 1; i >= 0; --i) {
10606                     stream.point((point = points[i])[0], point[1]);
10607                   }
10608                 } else {
10609                   interpolate(current.x, current.p.x, -1, stream);
10610                 }
10611
10612                 current = current.p;
10613               }
10614
10615               current = current.o;
10616               points = current.z;
10617               isSubject = !isSubject;
10618             } while (!current.v);
10619
10620             stream.lineEnd();
10621           }
10622         }
10623
10624         function link(array) {
10625           if (!(n = array.length)) return;
10626           var n,
10627               i = 0,
10628               a = array[0],
10629               b;
10630
10631           while (++i < n) {
10632             a.n = b = array[i];
10633             b.p = a;
10634             a = b;
10635           }
10636
10637           a.n = b = array[0];
10638           b.p = a;
10639         }
10640
10641         function longitude(point) {
10642           if (abs$2(point[0]) <= pi) return point[0];else return sign(point[0]) * ((abs$2(point[0]) + pi) % tau - pi);
10643         }
10644
10645         function polygonContains (polygon, point) {
10646           var lambda = longitude(point),
10647               phi = point[1],
10648               sinPhi = sin(phi),
10649               normal = [sin(lambda), -cos(lambda), 0],
10650               angle = 0,
10651               winding = 0;
10652           var sum = new Adder();
10653           if (sinPhi === 1) phi = halfPi + epsilon;else if (sinPhi === -1) phi = -halfPi - epsilon;
10654
10655           for (var i = 0, n = polygon.length; i < n; ++i) {
10656             if (!(m = (ring = polygon[i]).length)) continue;
10657             var ring,
10658                 m,
10659                 point0 = ring[m - 1],
10660                 lambda0 = longitude(point0),
10661                 phi0 = point0[1] / 2 + quarterPi,
10662                 sinPhi0 = sin(phi0),
10663                 cosPhi0 = cos(phi0);
10664
10665             for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
10666               var point1 = ring[j],
10667                   lambda1 = longitude(point1),
10668                   phi1 = point1[1] / 2 + quarterPi,
10669                   sinPhi1 = sin(phi1),
10670                   cosPhi1 = cos(phi1),
10671                   delta = lambda1 - lambda0,
10672                   sign = delta >= 0 ? 1 : -1,
10673                   absDelta = sign * delta,
10674                   antimeridian = absDelta > pi,
10675                   k = sinPhi0 * sinPhi1;
10676               sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
10677               angle += antimeridian ? delta + sign * tau : delta; // Are the longitudes either side of the point’s meridian (lambda),
10678               // and are the latitudes smaller than the parallel (phi)?
10679
10680               if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
10681                 var arc = cartesianCross(cartesian(point0), cartesian(point1));
10682                 cartesianNormalizeInPlace(arc);
10683                 var intersection = cartesianCross(normal, arc);
10684                 cartesianNormalizeInPlace(intersection);
10685                 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
10686
10687                 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
10688                   winding += antimeridian ^ delta >= 0 ? 1 : -1;
10689                 }
10690               }
10691             }
10692           } // First, determine whether the South pole is inside or outside:
10693           //
10694           // It is inside if:
10695           // * the polygon winds around it in a clockwise direction.
10696           // * the polygon does not (cumulatively) wind around it, but has a negative
10697           //   (counter-clockwise) area.
10698           //
10699           // Second, count the (signed) number of times a segment crosses a lambda
10700           // from the point to the South pole.  If it is zero, then the point is the
10701           // same side as the South pole.
10702
10703
10704           return (angle < -epsilon || angle < epsilon && sum < -epsilon2) ^ winding & 1;
10705         }
10706
10707         function clip (pointVisible, clipLine, interpolate, start) {
10708           return function (sink) {
10709             var line = clipLine(sink),
10710                 ringBuffer = clipBuffer(),
10711                 ringSink = clipLine(ringBuffer),
10712                 polygonStarted = false,
10713                 polygon,
10714                 segments,
10715                 ring;
10716             var clip = {
10717               point: point,
10718               lineStart: lineStart,
10719               lineEnd: lineEnd,
10720               polygonStart: function polygonStart() {
10721                 clip.point = pointRing;
10722                 clip.lineStart = ringStart;
10723                 clip.lineEnd = ringEnd;
10724                 segments = [];
10725                 polygon = [];
10726               },
10727               polygonEnd: function polygonEnd() {
10728                 clip.point = point;
10729                 clip.lineStart = lineStart;
10730                 clip.lineEnd = lineEnd;
10731                 segments = merge(segments);
10732                 var startInside = polygonContains(polygon, start);
10733
10734                 if (segments.length) {
10735                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10736                   clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
10737                 } else if (startInside) {
10738                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10739                   sink.lineStart();
10740                   interpolate(null, null, 1, sink);
10741                   sink.lineEnd();
10742                 }
10743
10744                 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
10745                 segments = polygon = null;
10746               },
10747               sphere: function sphere() {
10748                 sink.polygonStart();
10749                 sink.lineStart();
10750                 interpolate(null, null, 1, sink);
10751                 sink.lineEnd();
10752                 sink.polygonEnd();
10753               }
10754             };
10755
10756             function point(lambda, phi) {
10757               if (pointVisible(lambda, phi)) sink.point(lambda, phi);
10758             }
10759
10760             function pointLine(lambda, phi) {
10761               line.point(lambda, phi);
10762             }
10763
10764             function lineStart() {
10765               clip.point = pointLine;
10766               line.lineStart();
10767             }
10768
10769             function lineEnd() {
10770               clip.point = point;
10771               line.lineEnd();
10772             }
10773
10774             function pointRing(lambda, phi) {
10775               ring.push([lambda, phi]);
10776               ringSink.point(lambda, phi);
10777             }
10778
10779             function ringStart() {
10780               ringSink.lineStart();
10781               ring = [];
10782             }
10783
10784             function ringEnd() {
10785               pointRing(ring[0][0], ring[0][1]);
10786               ringSink.lineEnd();
10787               var clean = ringSink.clean(),
10788                   ringSegments = ringBuffer.result(),
10789                   i,
10790                   n = ringSegments.length,
10791                   m,
10792                   segment,
10793                   point;
10794               ring.pop();
10795               polygon.push(ring);
10796               ring = null;
10797               if (!n) return; // No intersections.
10798
10799               if (clean & 1) {
10800                 segment = ringSegments[0];
10801
10802                 if ((m = segment.length - 1) > 0) {
10803                   if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
10804                   sink.lineStart();
10805
10806                   for (i = 0; i < m; ++i) {
10807                     sink.point((point = segment[i])[0], point[1]);
10808                   }
10809
10810                   sink.lineEnd();
10811                 }
10812
10813                 return;
10814               } // Rejoin connected segments.
10815               // TODO reuse ringBuffer.rejoin()?
10816
10817
10818               if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
10819               segments.push(ringSegments.filter(validSegment));
10820             }
10821
10822             return clip;
10823           };
10824         }
10825
10826         function validSegment(segment) {
10827           return segment.length > 1;
10828         } // Intersections are sorted along the clip edge. For both antimeridian cutting
10829         // and circle clipping, the same comparison is used.
10830
10831
10832         function compareIntersection(a, b) {
10833           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]);
10834         }
10835
10836         var clipAntimeridian = clip(function () {
10837           return true;
10838         }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi, -halfPi]); // Takes a line and cuts into visible segments. Return values: 0 - there were
10839         // intersections or the line was empty; 1 - no intersections; 2 - there were
10840         // intersections, and the first and last segments should be rejoined.
10841
10842         function clipAntimeridianLine(stream) {
10843           var lambda0 = NaN,
10844               phi0 = NaN,
10845               sign0 = NaN,
10846               _clean; // no intersections
10847
10848
10849           return {
10850             lineStart: function lineStart() {
10851               stream.lineStart();
10852               _clean = 1;
10853             },
10854             point: function point(lambda1, phi1) {
10855               var sign1 = lambda1 > 0 ? pi : -pi,
10856                   delta = abs$2(lambda1 - lambda0);
10857
10858               if (abs$2(delta - pi) < epsilon) {
10859                 // line crosses a pole
10860                 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
10861                 stream.point(sign0, phi0);
10862                 stream.lineEnd();
10863                 stream.lineStart();
10864                 stream.point(sign1, phi0);
10865                 stream.point(lambda1, phi0);
10866                 _clean = 0;
10867               } else if (sign0 !== sign1 && delta >= pi) {
10868                 // line crosses antimeridian
10869                 if (abs$2(lambda0 - sign0) < epsilon) lambda0 -= sign0 * epsilon; // handle degeneracies
10870
10871                 if (abs$2(lambda1 - sign1) < epsilon) lambda1 -= sign1 * epsilon;
10872                 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
10873                 stream.point(sign0, phi0);
10874                 stream.lineEnd();
10875                 stream.lineStart();
10876                 stream.point(sign1, phi0);
10877                 _clean = 0;
10878               }
10879
10880               stream.point(lambda0 = lambda1, phi0 = phi1);
10881               sign0 = sign1;
10882             },
10883             lineEnd: function lineEnd() {
10884               stream.lineEnd();
10885               lambda0 = phi0 = NaN;
10886             },
10887             clean: function clean() {
10888               return 2 - _clean; // if intersections, rejoin first and last segments
10889             }
10890           };
10891         }
10892
10893         function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
10894           var cosPhi0,
10895               cosPhi1,
10896               sinLambda0Lambda1 = sin(lambda0 - lambda1);
10897           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;
10898         }
10899
10900         function clipAntimeridianInterpolate(from, to, direction, stream) {
10901           var phi;
10902
10903           if (from == null) {
10904             phi = direction * halfPi;
10905             stream.point(-pi, phi);
10906             stream.point(0, phi);
10907             stream.point(pi, phi);
10908             stream.point(pi, 0);
10909             stream.point(pi, -phi);
10910             stream.point(0, -phi);
10911             stream.point(-pi, -phi);
10912             stream.point(-pi, 0);
10913             stream.point(-pi, phi);
10914           } else if (abs$2(from[0] - to[0]) > epsilon) {
10915             var lambda = from[0] < to[0] ? pi : -pi;
10916             phi = direction * lambda / 2;
10917             stream.point(-lambda, phi);
10918             stream.point(0, phi);
10919             stream.point(lambda, phi);
10920           } else {
10921             stream.point(to[0], to[1]);
10922           }
10923         }
10924
10925         function clipCircle (radius) {
10926           var cr = cos(radius),
10927               delta = 6 * radians,
10928               smallRadius = cr > 0,
10929               notHemisphere = abs$2(cr) > epsilon; // TODO optimise for this common case
10930
10931           function interpolate(from, to, direction, stream) {
10932             circleStream(stream, radius, delta, direction, from, to);
10933           }
10934
10935           function visible(lambda, phi) {
10936             return cos(lambda) * cos(phi) > cr;
10937           } // Takes a line and cuts into visible segments. Return values used for polygon
10938           // clipping: 0 - there were intersections or the line was empty; 1 - no
10939           // intersections 2 - there were intersections, and the first and last segments
10940           // should be rejoined.
10941
10942
10943           function clipLine(stream) {
10944             var point0, // previous point
10945             c0, // code for previous point
10946             v0, // visibility of previous point
10947             v00, // visibility of first point
10948             _clean; // no intersections
10949
10950
10951             return {
10952               lineStart: function lineStart() {
10953                 v00 = v0 = false;
10954                 _clean = 1;
10955               },
10956               point: function point(lambda, phi) {
10957                 var point1 = [lambda, phi],
10958                     point2,
10959                     v = visible(lambda, phi),
10960                     c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
10961                 if (!point0 && (v00 = v0 = v)) stream.lineStart();
10962
10963                 if (v !== v0) {
10964                   point2 = intersect(point0, point1);
10965                   if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) point1[2] = 1;
10966                 }
10967
10968                 if (v !== v0) {
10969                   _clean = 0;
10970
10971                   if (v) {
10972                     // outside going in
10973                     stream.lineStart();
10974                     point2 = intersect(point1, point0);
10975                     stream.point(point2[0], point2[1]);
10976                   } else {
10977                     // inside going out
10978                     point2 = intersect(point0, point1);
10979                     stream.point(point2[0], point2[1], 2);
10980                     stream.lineEnd();
10981                   }
10982
10983                   point0 = point2;
10984                 } else if (notHemisphere && point0 && smallRadius ^ v) {
10985                   var t; // If the codes for two points are different, or are both zero,
10986                   // and there this segment intersects with the small circle.
10987
10988                   if (!(c & c0) && (t = intersect(point1, point0, true))) {
10989                     _clean = 0;
10990
10991                     if (smallRadius) {
10992                       stream.lineStart();
10993                       stream.point(t[0][0], t[0][1]);
10994                       stream.point(t[1][0], t[1][1]);
10995                       stream.lineEnd();
10996                     } else {
10997                       stream.point(t[1][0], t[1][1]);
10998                       stream.lineEnd();
10999                       stream.lineStart();
11000                       stream.point(t[0][0], t[0][1], 3);
11001                     }
11002                   }
11003                 }
11004
11005                 if (v && (!point0 || !pointEqual(point0, point1))) {
11006                   stream.point(point1[0], point1[1]);
11007                 }
11008
11009                 point0 = point1, v0 = v, c0 = c;
11010               },
11011               lineEnd: function lineEnd() {
11012                 if (v0) stream.lineEnd();
11013                 point0 = null;
11014               },
11015               // Rejoin first and last segments if there were intersections and the first
11016               // and last points were visible.
11017               clean: function clean() {
11018                 return _clean | (v00 && v0) << 1;
11019               }
11020             };
11021           } // Intersects the great circle between a and b with the clip circle.
11022
11023
11024           function intersect(a, b, two) {
11025             var pa = cartesian(a),
11026                 pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2.
11027             // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
11028
11029             var n1 = [1, 0, 0],
11030                 // normal
11031             n2 = cartesianCross(pa, pb),
11032                 n2n2 = cartesianDot(n2, n2),
11033                 n1n2 = n2[0],
11034                 // cartesianDot(n1, n2),
11035             determinant = n2n2 - n1n2 * n1n2; // Two polar points.
11036
11037             if (!determinant) return !two && a;
11038             var c1 = cr * n2n2 / determinant,
11039                 c2 = -cr * n1n2 / determinant,
11040                 n1xn2 = cartesianCross(n1, n2),
11041                 A = cartesianScale(n1, c1),
11042                 B = cartesianScale(n2, c2);
11043             cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1.
11044
11045             var u = n1xn2,
11046                 w = cartesianDot(A, u),
11047                 uu = cartesianDot(u, u),
11048                 t2 = w * w - uu * (cartesianDot(A, A) - 1);
11049             if (t2 < 0) return;
11050             var t = sqrt$1(t2),
11051                 q = cartesianScale(u, (-w - t) / uu);
11052             cartesianAddInPlace(q, A);
11053             q = spherical(q);
11054             if (!two) return q; // Two intersection points.
11055
11056             var lambda0 = a[0],
11057                 lambda1 = b[0],
11058                 phi0 = a[1],
11059                 phi1 = b[1],
11060                 z;
11061             if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
11062             var delta = lambda1 - lambda0,
11063                 polar = abs$2(delta - pi) < epsilon,
11064                 meridian = polar || delta < epsilon;
11065             if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b.
11066
11067             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)) {
11068               var q1 = cartesianScale(u, (-w + t) / uu);
11069               cartesianAddInPlace(q1, A);
11070               return [q, spherical(q1)];
11071             }
11072           } // Generates a 4-bit vector representing the location of a point relative to
11073           // the small circle's bounding box.
11074
11075
11076           function code(lambda, phi) {
11077             var r = smallRadius ? radius : pi - radius,
11078                 code = 0;
11079             if (lambda < -r) code |= 1; // left
11080             else if (lambda > r) code |= 2; // right
11081
11082             if (phi < -r) code |= 4; // below
11083             else if (phi > r) code |= 8; // above
11084
11085             return code;
11086           }
11087
11088           return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
11089         }
11090
11091         function clipLine (a, b, x0, y0, x1, y1) {
11092           var ax = a[0],
11093               ay = a[1],
11094               bx = b[0],
11095               by = b[1],
11096               t0 = 0,
11097               t1 = 1,
11098               dx = bx - ax,
11099               dy = by - ay,
11100               r;
11101           r = x0 - ax;
11102           if (!dx && r > 0) return;
11103           r /= dx;
11104
11105           if (dx < 0) {
11106             if (r < t0) return;
11107             if (r < t1) t1 = r;
11108           } else if (dx > 0) {
11109             if (r > t1) return;
11110             if (r > t0) t0 = r;
11111           }
11112
11113           r = x1 - ax;
11114           if (!dx && r < 0) return;
11115           r /= dx;
11116
11117           if (dx < 0) {
11118             if (r > t1) return;
11119             if (r > t0) t0 = r;
11120           } else if (dx > 0) {
11121             if (r < t0) return;
11122             if (r < t1) t1 = r;
11123           }
11124
11125           r = y0 - ay;
11126           if (!dy && r > 0) return;
11127           r /= dy;
11128
11129           if (dy < 0) {
11130             if (r < t0) return;
11131             if (r < t1) t1 = r;
11132           } else if (dy > 0) {
11133             if (r > t1) return;
11134             if (r > t0) t0 = r;
11135           }
11136
11137           r = y1 - ay;
11138           if (!dy && r < 0) return;
11139           r /= dy;
11140
11141           if (dy < 0) {
11142             if (r > t1) return;
11143             if (r > t0) t0 = r;
11144           } else if (dy > 0) {
11145             if (r < t0) return;
11146             if (r < t1) t1 = r;
11147           }
11148
11149           if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
11150           if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
11151           return true;
11152         }
11153
11154         var clipMax = 1e9,
11155             clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check?
11156         // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
11157
11158         function clipRectangle(x0, y0, x1, y1) {
11159           function visible(x, y) {
11160             return x0 <= x && x <= x1 && y0 <= y && y <= y1;
11161           }
11162
11163           function interpolate(from, to, direction, stream) {
11164             var a = 0,
11165                 a1 = 0;
11166
11167             if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
11168               do {
11169                 stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
11170               } while ((a = (a + direction + 4) % 4) !== a1);
11171             } else {
11172               stream.point(to[0], to[1]);
11173             }
11174           }
11175
11176           function corner(p, direction) {
11177             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
11178           }
11179
11180           function compareIntersection(a, b) {
11181             return comparePoint(a.x, b.x);
11182           }
11183
11184           function comparePoint(a, b) {
11185             var ca = corner(a, 1),
11186                 cb = corner(b, 1);
11187             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];
11188           }
11189
11190           return function (stream) {
11191             var activeStream = stream,
11192                 bufferStream = clipBuffer(),
11193                 segments,
11194                 polygon,
11195                 ring,
11196                 x__,
11197                 y__,
11198                 v__,
11199                 // first point
11200             x_,
11201                 y_,
11202                 v_,
11203                 // previous point
11204             first,
11205                 clean;
11206             var clipStream = {
11207               point: point,
11208               lineStart: lineStart,
11209               lineEnd: lineEnd,
11210               polygonStart: polygonStart,
11211               polygonEnd: polygonEnd
11212             };
11213
11214             function point(x, y) {
11215               if (visible(x, y)) activeStream.point(x, y);
11216             }
11217
11218             function polygonInside() {
11219               var winding = 0;
11220
11221               for (var i = 0, n = polygon.length; i < n; ++i) {
11222                 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
11223                   a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
11224
11225                   if (a1 <= y1) {
11226                     if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding;
11227                   } else {
11228                     if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding;
11229                   }
11230                 }
11231               }
11232
11233               return winding;
11234             } // Buffer geometry within a polygon and then clip it en masse.
11235
11236
11237             function polygonStart() {
11238               activeStream = bufferStream, segments = [], polygon = [], clean = true;
11239             }
11240
11241             function polygonEnd() {
11242               var startInside = polygonInside(),
11243                   cleanInside = clean && startInside,
11244                   visible = (segments = merge(segments)).length;
11245
11246               if (cleanInside || visible) {
11247                 stream.polygonStart();
11248
11249                 if (cleanInside) {
11250                   stream.lineStart();
11251                   interpolate(null, null, 1, stream);
11252                   stream.lineEnd();
11253                 }
11254
11255                 if (visible) {
11256                   clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
11257                 }
11258
11259                 stream.polygonEnd();
11260               }
11261
11262               activeStream = stream, segments = polygon = ring = null;
11263             }
11264
11265             function lineStart() {
11266               clipStream.point = linePoint;
11267               if (polygon) polygon.push(ring = []);
11268               first = true;
11269               v_ = false;
11270               x_ = y_ = NaN;
11271             } // TODO rather than special-case polygons, simply handle them separately.
11272             // Ideally, coincident intersection points should be jittered to avoid
11273             // clipping issues.
11274
11275
11276             function lineEnd() {
11277               if (segments) {
11278                 linePoint(x__, y__);
11279                 if (v__ && v_) bufferStream.rejoin();
11280                 segments.push(bufferStream.result());
11281               }
11282
11283               clipStream.point = point;
11284               if (v_) activeStream.lineEnd();
11285             }
11286
11287             function linePoint(x, y) {
11288               var v = visible(x, y);
11289               if (polygon) ring.push([x, y]);
11290
11291               if (first) {
11292                 x__ = x, y__ = y, v__ = v;
11293                 first = false;
11294
11295                 if (v) {
11296                   activeStream.lineStart();
11297                   activeStream.point(x, y);
11298                 }
11299               } else {
11300                 if (v && v_) activeStream.point(x, y);else {
11301                   var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
11302                       b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
11303
11304                   if (clipLine(a, b, x0, y0, x1, y1)) {
11305                     if (!v_) {
11306                       activeStream.lineStart();
11307                       activeStream.point(a[0], a[1]);
11308                     }
11309
11310                     activeStream.point(b[0], b[1]);
11311                     if (!v) activeStream.lineEnd();
11312                     clean = false;
11313                   } else if (v) {
11314                     activeStream.lineStart();
11315                     activeStream.point(x, y);
11316                     clean = false;
11317                   }
11318                 }
11319               }
11320
11321               x_ = x, y_ = y, v_ = v;
11322             }
11323
11324             return clipStream;
11325           };
11326         }
11327
11328         var lengthSum, lambda0$2, sinPhi0$1, cosPhi0$1;
11329         var lengthStream = {
11330           sphere: noop,
11331           point: noop,
11332           lineStart: lengthLineStart,
11333           lineEnd: noop,
11334           polygonStart: noop,
11335           polygonEnd: noop
11336         };
11337
11338         function lengthLineStart() {
11339           lengthStream.point = lengthPointFirst;
11340           lengthStream.lineEnd = lengthLineEnd;
11341         }
11342
11343         function lengthLineEnd() {
11344           lengthStream.point = lengthStream.lineEnd = noop;
11345         }
11346
11347         function lengthPointFirst(lambda, phi) {
11348           lambda *= radians, phi *= radians;
11349           lambda0$2 = lambda, sinPhi0$1 = sin(phi), cosPhi0$1 = cos(phi);
11350           lengthStream.point = lengthPoint;
11351         }
11352
11353         function lengthPoint(lambda, phi) {
11354           lambda *= radians, phi *= radians;
11355           var sinPhi = sin(phi),
11356               cosPhi = cos(phi),
11357               delta = abs$2(lambda - lambda0$2),
11358               cosDelta = cos(delta),
11359               sinDelta = sin(delta),
11360               x = cosPhi * sinDelta,
11361               y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
11362               z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
11363           lengthSum.add(atan2(sqrt$1(x * x + y * y), z));
11364           lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
11365         }
11366
11367         function d3_geoLength (object) {
11368           lengthSum = new Adder();
11369           d3_geoStream(object, lengthStream);
11370           return +lengthSum;
11371         }
11372
11373         var identity = (function (x) {
11374           return x;
11375         });
11376
11377         var areaSum$1 = new Adder(),
11378             areaRingSum$1 = new Adder(),
11379             x00,
11380             y00,
11381             x0$1,
11382             y0$1;
11383         var areaStream$1 = {
11384           point: noop,
11385           lineStart: noop,
11386           lineEnd: noop,
11387           polygonStart: function polygonStart() {
11388             areaStream$1.lineStart = areaRingStart$1;
11389             areaStream$1.lineEnd = areaRingEnd$1;
11390           },
11391           polygonEnd: function polygonEnd() {
11392             areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop;
11393             areaSum$1.add(abs$2(areaRingSum$1));
11394             areaRingSum$1 = new Adder();
11395           },
11396           result: function result() {
11397             var area = areaSum$1 / 2;
11398             areaSum$1 = new Adder();
11399             return area;
11400           }
11401         };
11402
11403         function areaRingStart$1() {
11404           areaStream$1.point = areaPointFirst$1;
11405         }
11406
11407         function areaPointFirst$1(x, y) {
11408           areaStream$1.point = areaPoint$1;
11409           x00 = x0$1 = x, y00 = y0$1 = y;
11410         }
11411
11412         function areaPoint$1(x, y) {
11413           areaRingSum$1.add(y0$1 * x - x0$1 * y);
11414           x0$1 = x, y0$1 = y;
11415         }
11416
11417         function areaRingEnd$1() {
11418           areaPoint$1(x00, y00);
11419         }
11420
11421         var x0$2 = Infinity,
11422             y0$2 = x0$2,
11423             x1 = -x0$2,
11424             y1 = x1;
11425         var boundsStream$1 = {
11426           point: boundsPoint$1,
11427           lineStart: noop,
11428           lineEnd: noop,
11429           polygonStart: noop,
11430           polygonEnd: noop,
11431           result: function result() {
11432             var bounds = [[x0$2, y0$2], [x1, y1]];
11433             x1 = y1 = -(y0$2 = x0$2 = Infinity);
11434             return bounds;
11435           }
11436         };
11437
11438         function boundsPoint$1(x, y) {
11439           if (x < x0$2) x0$2 = x;
11440           if (x > x1) x1 = x;
11441           if (y < y0$2) y0$2 = y;
11442           if (y > y1) y1 = y;
11443         }
11444
11445         var X0$1 = 0,
11446             Y0$1 = 0,
11447             Z0$1 = 0,
11448             X1$1 = 0,
11449             Y1$1 = 0,
11450             Z1$1 = 0,
11451             X2$1 = 0,
11452             Y2$1 = 0,
11453             Z2$1 = 0,
11454             x00$1,
11455             y00$1,
11456             x0$3,
11457             y0$3;
11458         var centroidStream$1 = {
11459           point: centroidPoint$1,
11460           lineStart: centroidLineStart$1,
11461           lineEnd: centroidLineEnd$1,
11462           polygonStart: function polygonStart() {
11463             centroidStream$1.lineStart = centroidRingStart$1;
11464             centroidStream$1.lineEnd = centroidRingEnd$1;
11465           },
11466           polygonEnd: function polygonEnd() {
11467             centroidStream$1.point = centroidPoint$1;
11468             centroidStream$1.lineStart = centroidLineStart$1;
11469             centroidStream$1.lineEnd = centroidLineEnd$1;
11470           },
11471           result: function result() {
11472             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];
11473             X0$1 = Y0$1 = Z0$1 = X1$1 = Y1$1 = Z1$1 = X2$1 = Y2$1 = Z2$1 = 0;
11474             return centroid;
11475           }
11476         };
11477
11478         function centroidPoint$1(x, y) {
11479           X0$1 += x;
11480           Y0$1 += y;
11481           ++Z0$1;
11482         }
11483
11484         function centroidLineStart$1() {
11485           centroidStream$1.point = centroidPointFirstLine;
11486         }
11487
11488         function centroidPointFirstLine(x, y) {
11489           centroidStream$1.point = centroidPointLine;
11490           centroidPoint$1(x0$3 = x, y0$3 = y);
11491         }
11492
11493         function centroidPointLine(x, y) {
11494           var dx = x - x0$3,
11495               dy = y - y0$3,
11496               z = sqrt$1(dx * dx + dy * dy);
11497           X1$1 += z * (x0$3 + x) / 2;
11498           Y1$1 += z * (y0$3 + y) / 2;
11499           Z1$1 += z;
11500           centroidPoint$1(x0$3 = x, y0$3 = y);
11501         }
11502
11503         function centroidLineEnd$1() {
11504           centroidStream$1.point = centroidPoint$1;
11505         }
11506
11507         function centroidRingStart$1() {
11508           centroidStream$1.point = centroidPointFirstRing;
11509         }
11510
11511         function centroidRingEnd$1() {
11512           centroidPointRing(x00$1, y00$1);
11513         }
11514
11515         function centroidPointFirstRing(x, y) {
11516           centroidStream$1.point = centroidPointRing;
11517           centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
11518         }
11519
11520         function centroidPointRing(x, y) {
11521           var dx = x - x0$3,
11522               dy = y - y0$3,
11523               z = sqrt$1(dx * dx + dy * dy);
11524           X1$1 += z * (x0$3 + x) / 2;
11525           Y1$1 += z * (y0$3 + y) / 2;
11526           Z1$1 += z;
11527           z = y0$3 * x - x0$3 * y;
11528           X2$1 += z * (x0$3 + x);
11529           Y2$1 += z * (y0$3 + y);
11530           Z2$1 += z * 3;
11531           centroidPoint$1(x0$3 = x, y0$3 = y);
11532         }
11533
11534         function PathContext(context) {
11535           this._context = context;
11536         }
11537         PathContext.prototype = {
11538           _radius: 4.5,
11539           pointRadius: function pointRadius(_) {
11540             return this._radius = _, this;
11541           },
11542           polygonStart: function polygonStart() {
11543             this._line = 0;
11544           },
11545           polygonEnd: function polygonEnd() {
11546             this._line = NaN;
11547           },
11548           lineStart: function lineStart() {
11549             this._point = 0;
11550           },
11551           lineEnd: function lineEnd() {
11552             if (this._line === 0) this._context.closePath();
11553             this._point = NaN;
11554           },
11555           point: function point(x, y) {
11556             switch (this._point) {
11557               case 0:
11558                 {
11559                   this._context.moveTo(x, y);
11560
11561                   this._point = 1;
11562                   break;
11563                 }
11564
11565               case 1:
11566                 {
11567                   this._context.lineTo(x, y);
11568
11569                   break;
11570                 }
11571
11572               default:
11573                 {
11574                   this._context.moveTo(x + this._radius, y);
11575
11576                   this._context.arc(x, y, this._radius, 0, tau);
11577
11578                   break;
11579                 }
11580             }
11581           },
11582           result: noop
11583         };
11584
11585         var lengthSum$1 = new Adder(),
11586             lengthRing,
11587             x00$2,
11588             y00$2,
11589             x0$4,
11590             y0$4;
11591         var lengthStream$1 = {
11592           point: noop,
11593           lineStart: function lineStart() {
11594             lengthStream$1.point = lengthPointFirst$1;
11595           },
11596           lineEnd: function lineEnd() {
11597             if (lengthRing) lengthPoint$1(x00$2, y00$2);
11598             lengthStream$1.point = noop;
11599           },
11600           polygonStart: function polygonStart() {
11601             lengthRing = true;
11602           },
11603           polygonEnd: function polygonEnd() {
11604             lengthRing = null;
11605           },
11606           result: function result() {
11607             var length = +lengthSum$1;
11608             lengthSum$1 = new Adder();
11609             return length;
11610           }
11611         };
11612
11613         function lengthPointFirst$1(x, y) {
11614           lengthStream$1.point = lengthPoint$1;
11615           x00$2 = x0$4 = x, y00$2 = y0$4 = y;
11616         }
11617
11618         function lengthPoint$1(x, y) {
11619           x0$4 -= x, y0$4 -= y;
11620           lengthSum$1.add(sqrt$1(x0$4 * x0$4 + y0$4 * y0$4));
11621           x0$4 = x, y0$4 = y;
11622         }
11623
11624         function PathString() {
11625           this._string = [];
11626         }
11627         PathString.prototype = {
11628           _radius: 4.5,
11629           _circle: circle(4.5),
11630           pointRadius: function pointRadius(_) {
11631             if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
11632             return this;
11633           },
11634           polygonStart: function polygonStart() {
11635             this._line = 0;
11636           },
11637           polygonEnd: function polygonEnd() {
11638             this._line = NaN;
11639           },
11640           lineStart: function lineStart() {
11641             this._point = 0;
11642           },
11643           lineEnd: function lineEnd() {
11644             if (this._line === 0) this._string.push("Z");
11645             this._point = NaN;
11646           },
11647           point: function point(x, y) {
11648             switch (this._point) {
11649               case 0:
11650                 {
11651                   this._string.push("M", x, ",", y);
11652
11653                   this._point = 1;
11654                   break;
11655                 }
11656
11657               case 1:
11658                 {
11659                   this._string.push("L", x, ",", y);
11660
11661                   break;
11662                 }
11663
11664               default:
11665                 {
11666                   if (this._circle == null) this._circle = circle(this._radius);
11667
11668                   this._string.push("M", x, ",", y, this._circle);
11669
11670                   break;
11671                 }
11672             }
11673           },
11674           result: function result() {
11675             if (this._string.length) {
11676               var result = this._string.join("");
11677
11678               this._string = [];
11679               return result;
11680             } else {
11681               return null;
11682             }
11683           }
11684         };
11685
11686         function circle(radius) {
11687           return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
11688         }
11689
11690         function d3_geoPath (projection, context) {
11691           var pointRadius = 4.5,
11692               projectionStream,
11693               contextStream;
11694
11695           function path(object) {
11696             if (object) {
11697               if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
11698               d3_geoStream(object, projectionStream(contextStream));
11699             }
11700
11701             return contextStream.result();
11702           }
11703
11704           path.area = function (object) {
11705             d3_geoStream(object, projectionStream(areaStream$1));
11706             return areaStream$1.result();
11707           };
11708
11709           path.measure = function (object) {
11710             d3_geoStream(object, projectionStream(lengthStream$1));
11711             return lengthStream$1.result();
11712           };
11713
11714           path.bounds = function (object) {
11715             d3_geoStream(object, projectionStream(boundsStream$1));
11716             return boundsStream$1.result();
11717           };
11718
11719           path.centroid = function (object) {
11720             d3_geoStream(object, projectionStream(centroidStream$1));
11721             return centroidStream$1.result();
11722           };
11723
11724           path.projection = function (_) {
11725             return arguments.length ? (projectionStream = _ == null ? (projection = null, identity) : (projection = _).stream, path) : projection;
11726           };
11727
11728           path.context = function (_) {
11729             if (!arguments.length) return context;
11730             contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
11731             if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
11732             return path;
11733           };
11734
11735           path.pointRadius = function (_) {
11736             if (!arguments.length) return pointRadius;
11737             pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
11738             return path;
11739           };
11740
11741           return path.projection(projection).context(context);
11742         }
11743
11744         function d3_geoTransform (methods) {
11745           return {
11746             stream: transformer(methods)
11747           };
11748         }
11749         function transformer(methods) {
11750           return function (stream) {
11751             var s = new TransformStream();
11752
11753             for (var key in methods) {
11754               s[key] = methods[key];
11755             }
11756
11757             s.stream = stream;
11758             return s;
11759           };
11760         }
11761
11762         function TransformStream() {}
11763
11764         TransformStream.prototype = {
11765           constructor: TransformStream,
11766           point: function point(x, y) {
11767             this.stream.point(x, y);
11768           },
11769           sphere: function sphere() {
11770             this.stream.sphere();
11771           },
11772           lineStart: function lineStart() {
11773             this.stream.lineStart();
11774           },
11775           lineEnd: function lineEnd() {
11776             this.stream.lineEnd();
11777           },
11778           polygonStart: function polygonStart() {
11779             this.stream.polygonStart();
11780           },
11781           polygonEnd: function polygonEnd() {
11782             this.stream.polygonEnd();
11783           }
11784         };
11785
11786         function fit(projection, fitBounds, object) {
11787           var clip = projection.clipExtent && projection.clipExtent();
11788           projection.scale(150).translate([0, 0]);
11789           if (clip != null) projection.clipExtent(null);
11790           d3_geoStream(object, projection.stream(boundsStream$1));
11791           fitBounds(boundsStream$1.result());
11792           if (clip != null) projection.clipExtent(clip);
11793           return projection;
11794         }
11795
11796         function fitExtent(projection, extent, object) {
11797           return fit(projection, function (b) {
11798             var w = extent[1][0] - extent[0][0],
11799                 h = extent[1][1] - extent[0][1],
11800                 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
11801                 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
11802                 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
11803             projection.scale(150 * k).translate([x, y]);
11804           }, object);
11805         }
11806         function fitSize(projection, size, object) {
11807           return fitExtent(projection, [[0, 0], size], object);
11808         }
11809         function fitWidth(projection, width, object) {
11810           return fit(projection, function (b) {
11811             var w = +width,
11812                 k = w / (b[1][0] - b[0][0]),
11813                 x = (w - k * (b[1][0] + b[0][0])) / 2,
11814                 y = -k * b[0][1];
11815             projection.scale(150 * k).translate([x, y]);
11816           }, object);
11817         }
11818         function fitHeight(projection, height, object) {
11819           return fit(projection, function (b) {
11820             var h = +height,
11821                 k = h / (b[1][1] - b[0][1]),
11822                 x = -k * b[0][0],
11823                 y = (h - k * (b[1][1] + b[0][1])) / 2;
11824             projection.scale(150 * k).translate([x, y]);
11825           }, object);
11826         }
11827
11828         var maxDepth = 16,
11829             // maximum depth of subdivision
11830         cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
11831
11832         function resample (project, delta2) {
11833           return +delta2 ? resample$1(project, delta2) : resampleNone(project);
11834         }
11835
11836         function resampleNone(project) {
11837           return transformer({
11838             point: function point(x, y) {
11839               x = project(x, y);
11840               this.stream.point(x[0], x[1]);
11841             }
11842           });
11843         }
11844
11845         function resample$1(project, delta2) {
11846           function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
11847             var dx = x1 - x0,
11848                 dy = y1 - y0,
11849                 d2 = dx * dx + dy * dy;
11850
11851             if (d2 > 4 * delta2 && depth--) {
11852               var a = a0 + a1,
11853                   b = b0 + b1,
11854                   c = c0 + c1,
11855                   m = sqrt$1(a * a + b * b + c * c),
11856                   phi2 = asin(c /= m),
11857                   lambda2 = abs$2(abs$2(c) - 1) < epsilon || abs$2(lambda0 - lambda1) < epsilon ? (lambda0 + lambda1) / 2 : atan2(b, a),
11858                   p = project(lambda2, phi2),
11859                   x2 = p[0],
11860                   y2 = p[1],
11861                   dx2 = x2 - x0,
11862                   dy2 = y2 - y0,
11863                   dz = dy * dx2 - dx * dy2;
11864
11865               if (dz * dz / d2 > delta2 // perpendicular projected distance
11866               || abs$2((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
11867               || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
11868                 // angular distance
11869                 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
11870                 stream.point(x2, y2);
11871                 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
11872               }
11873             }
11874           }
11875
11876           return function (stream) {
11877             var lambda00, x00, y00, a00, b00, c00, // first point
11878             lambda0, x0, y0, a0, b0, c0; // previous point
11879
11880             var resampleStream = {
11881               point: point,
11882               lineStart: lineStart,
11883               lineEnd: lineEnd,
11884               polygonStart: function polygonStart() {
11885                 stream.polygonStart();
11886                 resampleStream.lineStart = ringStart;
11887               },
11888               polygonEnd: function polygonEnd() {
11889                 stream.polygonEnd();
11890                 resampleStream.lineStart = lineStart;
11891               }
11892             };
11893
11894             function point(x, y) {
11895               x = project(x, y);
11896               stream.point(x[0], x[1]);
11897             }
11898
11899             function lineStart() {
11900               x0 = NaN;
11901               resampleStream.point = linePoint;
11902               stream.lineStart();
11903             }
11904
11905             function linePoint(lambda, phi) {
11906               var c = cartesian([lambda, phi]),
11907                   p = project(lambda, phi);
11908               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);
11909               stream.point(x0, y0);
11910             }
11911
11912             function lineEnd() {
11913               resampleStream.point = point;
11914               stream.lineEnd();
11915             }
11916
11917             function ringStart() {
11918               lineStart();
11919               resampleStream.point = ringPoint;
11920               resampleStream.lineEnd = ringEnd;
11921             }
11922
11923             function ringPoint(lambda, phi) {
11924               linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
11925               resampleStream.point = linePoint;
11926             }
11927
11928             function ringEnd() {
11929               resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
11930               resampleStream.lineEnd = lineEnd;
11931               lineEnd();
11932             }
11933
11934             return resampleStream;
11935           };
11936         }
11937
11938         var transformRadians = transformer({
11939           point: function point(x, y) {
11940             this.stream.point(x * radians, y * radians);
11941           }
11942         });
11943
11944         function transformRotate(rotate) {
11945           return transformer({
11946             point: function point(x, y) {
11947               var r = rotate(x, y);
11948               return this.stream.point(r[0], r[1]);
11949             }
11950           });
11951         }
11952
11953         function scaleTranslate(k, dx, dy, sx, sy) {
11954           function transform(x, y) {
11955             x *= sx;
11956             y *= sy;
11957             return [dx + k * x, dy - k * y];
11958           }
11959
11960           transform.invert = function (x, y) {
11961             return [(x - dx) / k * sx, (dy - y) / k * sy];
11962           };
11963
11964           return transform;
11965         }
11966
11967         function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
11968           if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
11969           var cosAlpha = cos(alpha),
11970               sinAlpha = sin(alpha),
11971               a = cosAlpha * k,
11972               b = sinAlpha * k,
11973               ai = cosAlpha / k,
11974               bi = sinAlpha / k,
11975               ci = (sinAlpha * dy - cosAlpha * dx) / k,
11976               fi = (sinAlpha * dx + cosAlpha * dy) / k;
11977
11978           function transform(x, y) {
11979             x *= sx;
11980             y *= sy;
11981             return [a * x - b * y + dx, dy - b * x - a * y];
11982           }
11983
11984           transform.invert = function (x, y) {
11985             return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
11986           };
11987
11988           return transform;
11989         }
11990
11991         function projection(project) {
11992           return projectionMutator(function () {
11993             return project;
11994           })();
11995         }
11996         function projectionMutator(projectAt) {
11997           var project,
11998               k = 150,
11999               // scale
12000           x = 480,
12001               y = 250,
12002               // translate
12003           lambda = 0,
12004               phi = 0,
12005               // center
12006           deltaLambda = 0,
12007               deltaPhi = 0,
12008               deltaGamma = 0,
12009               rotate,
12010               // pre-rotate
12011           alpha = 0,
12012               // post-rotate angle
12013           sx = 1,
12014               // reflectX
12015           sy = 1,
12016               // reflectX
12017           theta = null,
12018               preclip = clipAntimeridian,
12019               // pre-clip angle
12020           x0 = null,
12021               y0,
12022               x1,
12023               y1,
12024               postclip = identity,
12025               // post-clip extent
12026           delta2 = 0.5,
12027               // precision
12028           projectResample,
12029               projectTransform,
12030               projectRotateTransform,
12031               cache,
12032               cacheStream;
12033
12034           function projection(point) {
12035             return projectRotateTransform(point[0] * radians, point[1] * radians);
12036           }
12037
12038           function invert(point) {
12039             point = projectRotateTransform.invert(point[0], point[1]);
12040             return point && [point[0] * degrees, point[1] * degrees];
12041           }
12042
12043           projection.stream = function (stream) {
12044             return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
12045           };
12046
12047           projection.preclip = function (_) {
12048             return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
12049           };
12050
12051           projection.postclip = function (_) {
12052             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12053           };
12054
12055           projection.clipAngle = function (_) {
12056             return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees;
12057           };
12058
12059           projection.clipExtent = function (_) {
12060             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]];
12061           };
12062
12063           projection.scale = function (_) {
12064             return arguments.length ? (k = +_, recenter()) : k;
12065           };
12066
12067           projection.translate = function (_) {
12068             return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
12069           };
12070
12071           projection.center = function (_) {
12072             return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees, phi * degrees];
12073           };
12074
12075           projection.rotate = function (_) {
12076             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];
12077           };
12078
12079           projection.angle = function (_) {
12080             return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees;
12081           };
12082
12083           projection.reflectX = function (_) {
12084             return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
12085           };
12086
12087           projection.reflectY = function (_) {
12088             return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
12089           };
12090
12091           projection.precision = function (_) {
12092             return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$1(delta2);
12093           };
12094
12095           projection.fitExtent = function (extent, object) {
12096             return fitExtent(projection, extent, object);
12097           };
12098
12099           projection.fitSize = function (size, object) {
12100             return fitSize(projection, size, object);
12101           };
12102
12103           projection.fitWidth = function (width, object) {
12104             return fitWidth(projection, width, object);
12105           };
12106
12107           projection.fitHeight = function (height, object) {
12108             return fitHeight(projection, height, object);
12109           };
12110
12111           function recenter() {
12112             var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
12113                 transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
12114             rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
12115             projectTransform = compose(project, transform);
12116             projectRotateTransform = compose(rotate, projectTransform);
12117             projectResample = resample(projectTransform, delta2);
12118             return reset();
12119           }
12120
12121           function reset() {
12122             cache = cacheStream = null;
12123             return projection;
12124           }
12125
12126           return function () {
12127             project = projectAt.apply(this, arguments);
12128             projection.invert = project.invert && invert;
12129             return recenter();
12130           };
12131         }
12132
12133         function mercatorRaw(lambda, phi) {
12134           return [lambda, log$1(tan((halfPi + phi) / 2))];
12135         }
12136
12137         mercatorRaw.invert = function (x, y) {
12138           return [x, 2 * atan(exp(y)) - halfPi];
12139         };
12140
12141         function mercator () {
12142           return mercatorProjection(mercatorRaw).scale(961 / tau);
12143         }
12144         function mercatorProjection(project) {
12145           var m = projection(project),
12146               center = m.center,
12147               scale = m.scale,
12148               translate = m.translate,
12149               clipExtent = m.clipExtent,
12150               x0 = null,
12151               y0,
12152               x1,
12153               y1; // clip extent
12154
12155           m.scale = function (_) {
12156             return arguments.length ? (scale(_), reclip()) : scale();
12157           };
12158
12159           m.translate = function (_) {
12160             return arguments.length ? (translate(_), reclip()) : translate();
12161           };
12162
12163           m.center = function (_) {
12164             return arguments.length ? (center(_), reclip()) : center();
12165           };
12166
12167           m.clipExtent = function (_) {
12168             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]];
12169           };
12170
12171           function reclip() {
12172             var k = pi * scale(),
12173                 t = m(rotation(m.rotate()).invert([0, 0]));
12174             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)]]);
12175           }
12176
12177           return reclip();
12178         }
12179
12180         function d3_geoIdentity () {
12181           var k = 1,
12182               tx = 0,
12183               ty = 0,
12184               sx = 1,
12185               sy = 1,
12186               // scale, translate and reflect
12187           alpha = 0,
12188               ca,
12189               sa,
12190               // angle
12191           x0 = null,
12192               y0,
12193               x1,
12194               y1,
12195               // clip extent
12196           kx = 1,
12197               ky = 1,
12198               transform = transformer({
12199             point: function point(x, y) {
12200               var p = projection([x, y]);
12201               this.stream.point(p[0], p[1]);
12202             }
12203           }),
12204               postclip = identity,
12205               cache,
12206               cacheStream;
12207
12208           function reset() {
12209             kx = k * sx;
12210             ky = k * sy;
12211             cache = cacheStream = null;
12212             return projection;
12213           }
12214
12215           function projection(p) {
12216             var x = p[0] * kx,
12217                 y = p[1] * ky;
12218
12219             if (alpha) {
12220               var t = y * ca - x * sa;
12221               x = x * ca + y * sa;
12222               y = t;
12223             }
12224
12225             return [x + tx, y + ty];
12226           }
12227
12228           projection.invert = function (p) {
12229             var x = p[0] - tx,
12230                 y = p[1] - ty;
12231
12232             if (alpha) {
12233               var t = y * ca + x * sa;
12234               x = x * ca - y * sa;
12235               y = t;
12236             }
12237
12238             return [x / kx, y / ky];
12239           };
12240
12241           projection.stream = function (stream) {
12242             return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
12243           };
12244
12245           projection.postclip = function (_) {
12246             return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12247           };
12248
12249           projection.clipExtent = function (_) {
12250             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]];
12251           };
12252
12253           projection.scale = function (_) {
12254             return arguments.length ? (k = +_, reset()) : k;
12255           };
12256
12257           projection.translate = function (_) {
12258             return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
12259           };
12260
12261           projection.angle = function (_) {
12262             return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees;
12263           };
12264
12265           projection.reflectX = function (_) {
12266             return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
12267           };
12268
12269           projection.reflectY = function (_) {
12270             return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
12271           };
12272
12273           projection.fitExtent = function (extent, object) {
12274             return fitExtent(projection, extent, object);
12275           };
12276
12277           projection.fitSize = function (size, object) {
12278             return fitSize(projection, size, object);
12279           };
12280
12281           projection.fitWidth = function (width, object) {
12282             return fitWidth(projection, width, object);
12283           };
12284
12285           projection.fitHeight = function (height, object) {
12286             return fitHeight(projection, height, object);
12287           };
12288
12289           return projection;
12290         }
12291
12292         // constants
12293         var TAU = 2 * Math.PI;
12294         var EQUATORIAL_RADIUS = 6356752.314245179;
12295         var POLAR_RADIUS = 6378137.0;
12296         function geoLatToMeters(dLat) {
12297           return dLat * (TAU * POLAR_RADIUS / 360);
12298         }
12299         function geoLonToMeters(dLon, atLat) {
12300           return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
12301         }
12302         function geoMetersToLat(m) {
12303           return m / (TAU * POLAR_RADIUS / 360);
12304         }
12305         function geoMetersToLon(m, atLat) {
12306           return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
12307         }
12308         function geoMetersToOffset(meters, tileSize) {
12309           tileSize = tileSize || 256;
12310           return [meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), -meters[1] * tileSize / (TAU * POLAR_RADIUS)];
12311         }
12312         function geoOffsetToMeters(offset, tileSize) {
12313           tileSize = tileSize || 256;
12314           return [offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, -offset[1] * TAU * POLAR_RADIUS / tileSize];
12315         } // Equirectangular approximation of spherical distances on Earth
12316
12317         function geoSphericalDistance(a, b) {
12318           var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
12319           var y = geoLatToMeters(a[1] - b[1]);
12320           return Math.sqrt(x * x + y * y);
12321         } // scale to zoom
12322
12323         function geoScaleToZoom(k, tileSize) {
12324           tileSize = tileSize || 256;
12325           var log2ts = Math.log(tileSize) * Math.LOG2E;
12326           return Math.log(k * TAU) / Math.LN2 - log2ts;
12327         } // zoom to scale
12328
12329         function geoZoomToScale(z, tileSize) {
12330           tileSize = tileSize || 256;
12331           return tileSize * Math.pow(2, z) / TAU;
12332         } // returns info about the node from `nodes` closest to the given `point`
12333
12334         function geoSphericalClosestNode(nodes, point) {
12335           var minDistance = Infinity,
12336               distance;
12337           var indexOfMin;
12338
12339           for (var i in nodes) {
12340             distance = geoSphericalDistance(nodes[i].loc, point);
12341
12342             if (distance < minDistance) {
12343               minDistance = distance;
12344               indexOfMin = i;
12345             }
12346           }
12347
12348           if (indexOfMin !== undefined) {
12349             return {
12350               index: indexOfMin,
12351               distance: minDistance,
12352               node: nodes[indexOfMin]
12353             };
12354           } else {
12355             return null;
12356           }
12357         }
12358
12359         function geoExtent(min, max) {
12360           if (!(this instanceof geoExtent)) {
12361             return new geoExtent(min, max);
12362           } else if (min instanceof geoExtent) {
12363             return min;
12364           } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
12365             this[0] = min[0];
12366             this[1] = min[1];
12367           } else {
12368             this[0] = min || [Infinity, Infinity];
12369             this[1] = max || min || [-Infinity, -Infinity];
12370           }
12371         }
12372         geoExtent.prototype = new Array(2);
12373         Object.assign(geoExtent.prototype, {
12374           equals: function equals(obj) {
12375             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];
12376           },
12377           extend: function extend(obj) {
12378             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12379             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])]);
12380           },
12381           _extend: function _extend(extent) {
12382             this[0][0] = Math.min(extent[0][0], this[0][0]);
12383             this[0][1] = Math.min(extent[0][1], this[0][1]);
12384             this[1][0] = Math.max(extent[1][0], this[1][0]);
12385             this[1][1] = Math.max(extent[1][1], this[1][1]);
12386           },
12387           area: function area() {
12388             return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
12389           },
12390           center: function center() {
12391             return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
12392           },
12393           rectangle: function rectangle() {
12394             return [this[0][0], this[0][1], this[1][0], this[1][1]];
12395           },
12396           bbox: function bbox() {
12397             return {
12398               minX: this[0][0],
12399               minY: this[0][1],
12400               maxX: this[1][0],
12401               maxY: this[1][1]
12402             };
12403           },
12404           polygon: function polygon() {
12405             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]]];
12406           },
12407           contains: function contains(obj) {
12408             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12409             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];
12410           },
12411           intersects: function intersects(obj) {
12412             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12413             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];
12414           },
12415           intersection: function intersection(obj) {
12416             if (!this.intersects(obj)) return new geoExtent();
12417             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])]);
12418           },
12419           percentContainedIn: function percentContainedIn(obj) {
12420             if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
12421             var a1 = this.intersection(obj).area();
12422             var a2 = this.area();
12423
12424             if (a1 === Infinity || a2 === Infinity) {
12425               return 0;
12426             } else if (a1 === 0 || a2 === 0) {
12427               if (obj.contains(this)) {
12428                 return 1;
12429               }
12430
12431               return 0;
12432             } else {
12433               return a1 / a2;
12434             }
12435           },
12436           padByMeters: function padByMeters(meters) {
12437             var dLat = geoMetersToLat(meters);
12438             var dLon = geoMetersToLon(meters, this.center()[1]);
12439             return geoExtent([this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat]);
12440           },
12441           toParam: function toParam() {
12442             return this.rectangle().join(',');
12443           }
12444         });
12445
12446         var $every$1 = arrayIteration.every;
12447
12448
12449
12450         var STRICT_METHOD$6 = arrayMethodIsStrict('every');
12451         var USES_TO_LENGTH$8 = arrayMethodUsesToLength('every');
12452
12453         // `Array.prototype.every` method
12454         // https://tc39.github.io/ecma262/#sec-array.prototype.every
12455         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$6 || !USES_TO_LENGTH$8 }, {
12456           every: function every(callbackfn /* , thisArg */) {
12457             return $every$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
12458           }
12459         });
12460
12461         var $reduce$1 = arrayReduce.left;
12462
12463
12464
12465
12466
12467         var STRICT_METHOD$7 = arrayMethodIsStrict('reduce');
12468         var USES_TO_LENGTH$9 = arrayMethodUsesToLength('reduce', { 1: 0 });
12469         // Chrome 80-82 has a critical bug
12470         // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
12471         var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83;
12472
12473         // `Array.prototype.reduce` method
12474         // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
12475         _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$7 || !USES_TO_LENGTH$9 || CHROME_BUG }, {
12476           reduce: function reduce(callbackfn /* , initialValue */) {
12477             return $reduce$1(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
12478           }
12479         });
12480
12481         function d3_polygonArea (polygon) {
12482           var i = -1,
12483               n = polygon.length,
12484               a,
12485               b = polygon[n - 1],
12486               area = 0;
12487
12488           while (++i < n) {
12489             a = b;
12490             b = polygon[i];
12491             area += a[1] * b[0] - a[0] * b[1];
12492           }
12493
12494           return area / 2;
12495         }
12496
12497         function d3_polygonCentroid (polygon) {
12498           var i = -1,
12499               n = polygon.length,
12500               x = 0,
12501               y = 0,
12502               a,
12503               b = polygon[n - 1],
12504               c,
12505               k = 0;
12506
12507           while (++i < n) {
12508             a = b;
12509             b = polygon[i];
12510             k += c = a[0] * b[1] - b[0] * a[1];
12511             x += (a[0] + b[0]) * c;
12512             y += (a[1] + b[1]) * c;
12513           }
12514
12515           return k *= 3, [x / k, y / k];
12516         }
12517
12518         // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
12519         // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
12520         // right, +y is up). Returns a positive value if ABC is counter-clockwise,
12521         // negative if clockwise, and zero if the points are collinear.
12522         function cross (a, b, c) {
12523           return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
12524         }
12525
12526         function lexicographicOrder(a, b) {
12527           return a[0] - b[0] || a[1] - b[1];
12528         } // Computes the upper convex hull per the monotone chain algorithm.
12529         // Assumes points.length >= 3, is sorted by x, unique in y.
12530         // Returns an array of indices into points in left-to-right order.
12531
12532
12533         function computeUpperHullIndexes(points) {
12534           var n = points.length,
12535               indexes = [0, 1];
12536           var size = 2,
12537               i;
12538
12539           for (i = 2; i < n; ++i) {
12540             while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) {
12541               --size;
12542             }
12543
12544             indexes[size++] = i;
12545           }
12546
12547           return indexes.slice(0, size); // remove popped points
12548         }
12549
12550         function d3_polygonHull (points) {
12551           if ((n = points.length) < 3) return null;
12552           var i,
12553               n,
12554               sortedPoints = new Array(n),
12555               flippedPoints = new Array(n);
12556
12557           for (i = 0; i < n; ++i) {
12558             sortedPoints[i] = [+points[i][0], +points[i][1], i];
12559           }
12560
12561           sortedPoints.sort(lexicographicOrder);
12562
12563           for (i = 0; i < n; ++i) {
12564             flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
12565           }
12566
12567           var upperIndexes = computeUpperHullIndexes(sortedPoints),
12568               lowerIndexes = computeUpperHullIndexes(flippedPoints); // Construct the hull polygon, removing possible duplicate endpoints.
12569
12570           var skipLeft = lowerIndexes[0] === upperIndexes[0],
12571               skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
12572               hull = []; // Add upper hull in right-to-l order.
12573           // Then add lower hull in left-to-right order.
12574
12575           for (i = upperIndexes.length - 1; i >= 0; --i) {
12576             hull.push(points[sortedPoints[upperIndexes[i]][2]]);
12577           }
12578
12579           for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) {
12580             hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
12581           }
12582
12583           return hull;
12584         }
12585
12586         // vector equals
12587         function geoVecEqual(a, b, epsilon) {
12588           if (epsilon) {
12589             return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon;
12590           } else {
12591             return a[0] === b[0] && a[1] === b[1];
12592           }
12593         } // vector addition
12594
12595         function geoVecAdd(a, b) {
12596           return [a[0] + b[0], a[1] + b[1]];
12597         } // vector subtraction
12598
12599         function geoVecSubtract(a, b) {
12600           return [a[0] - b[0], a[1] - b[1]];
12601         } // vector scaling
12602
12603         function geoVecScale(a, mag) {
12604           return [a[0] * mag, a[1] * mag];
12605         } // vector rounding (was: geoRoundCoordinates)
12606
12607         function geoVecFloor(a) {
12608           return [Math.floor(a[0]), Math.floor(a[1])];
12609         } // linear interpolation
12610
12611         function geoVecInterp(a, b, t) {
12612           return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
12613         } // http://jsperf.com/id-dist-optimization
12614
12615         function geoVecLength(a, b) {
12616           return Math.sqrt(geoVecLengthSquare(a, b));
12617         } // length of vector raised to the power two
12618
12619         function geoVecLengthSquare(a, b) {
12620           b = b || [0, 0];
12621           var x = a[0] - b[0];
12622           var y = a[1] - b[1];
12623           return x * x + y * y;
12624         } // get a unit vector
12625
12626         function geoVecNormalize(a) {
12627           var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
12628
12629           if (length !== 0) {
12630             return geoVecScale(a, 1 / length);
12631           }
12632
12633           return [0, 0];
12634         } // Return the counterclockwise angle in the range (-pi, pi)
12635         // between the positive X axis and the line intersecting a and b.
12636
12637         function geoVecAngle(a, b) {
12638           return Math.atan2(b[1] - a[1], b[0] - a[0]);
12639         } // dot product
12640
12641         function geoVecDot(a, b, origin) {
12642           origin = origin || [0, 0];
12643           var p = geoVecSubtract(a, origin);
12644           var q = geoVecSubtract(b, origin);
12645           return p[0] * q[0] + p[1] * q[1];
12646         } // normalized dot product
12647
12648         function geoVecNormalizedDot(a, b, origin) {
12649           origin = origin || [0, 0];
12650           var p = geoVecNormalize(geoVecSubtract(a, origin));
12651           var q = geoVecNormalize(geoVecSubtract(b, origin));
12652           return geoVecDot(p, q);
12653         } // 2D cross product of OA and OB vectors, returns magnitude of Z vector
12654         // Returns a positive value, if OAB makes a counter-clockwise turn,
12655         // negative for clockwise turn, and zero if the points are collinear.
12656
12657         function geoVecCross(a, b, origin) {
12658           origin = origin || [0, 0];
12659           var p = geoVecSubtract(a, origin);
12660           var q = geoVecSubtract(b, origin);
12661           return p[0] * q[1] - p[1] * q[0];
12662         } // find closest orthogonal projection of point onto points array
12663
12664         function geoVecProject(a, points) {
12665           var min = Infinity;
12666           var idx;
12667           var target;
12668
12669           for (var i = 0; i < points.length - 1; i++) {
12670             var o = points[i];
12671             var s = geoVecSubtract(points[i + 1], o);
12672             var v = geoVecSubtract(a, o);
12673             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12674             var p;
12675
12676             if (proj < 0) {
12677               p = o;
12678             } else if (proj > 1) {
12679               p = points[i + 1];
12680             } else {
12681               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12682             }
12683
12684             var dist = geoVecLength(p, a);
12685
12686             if (dist < min) {
12687               min = dist;
12688               idx = i + 1;
12689               target = p;
12690             }
12691           }
12692
12693           if (idx !== undefined) {
12694             return {
12695               index: idx,
12696               distance: min,
12697               target: target
12698             };
12699           } else {
12700             return null;
12701           }
12702         }
12703
12704         // between the positive X axis and the line intersecting a and b.
12705
12706         function geoAngle(a, b, projection) {
12707           return geoVecAngle(projection(a.loc), projection(b.loc));
12708         }
12709         function geoEdgeEqual(a, b) {
12710           return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
12711         } // Rotate all points counterclockwise around a pivot point by given angle
12712
12713         function geoRotate(points, angle, around) {
12714           return points.map(function (point) {
12715             var radial = geoVecSubtract(point, around);
12716             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]];
12717           });
12718         } // Choose the edge with the minimal distance from `point` to its orthogonal
12719         // projection onto that edge, if such a projection exists, or the distance to
12720         // the closest vertex on that edge. Returns an object with the `index` of the
12721         // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
12722
12723         function geoChooseEdge(nodes, point, projection, activeID) {
12724           var dist = geoVecLength;
12725           var points = nodes.map(function (n) {
12726             return projection(n.loc);
12727           });
12728           var ids = nodes.map(function (n) {
12729             return n.id;
12730           });
12731           var min = Infinity;
12732           var idx;
12733           var loc;
12734
12735           for (var i = 0; i < points.length - 1; i++) {
12736             if (ids[i] === activeID || ids[i + 1] === activeID) continue;
12737             var o = points[i];
12738             var s = geoVecSubtract(points[i + 1], o);
12739             var v = geoVecSubtract(point, o);
12740             var proj = geoVecDot(v, s) / geoVecDot(s, s);
12741             var p;
12742
12743             if (proj < 0) {
12744               p = o;
12745             } else if (proj > 1) {
12746               p = points[i + 1];
12747             } else {
12748               p = [o[0] + proj * s[0], o[1] + proj * s[1]];
12749             }
12750
12751             var d = dist(p, point);
12752
12753             if (d < min) {
12754               min = d;
12755               idx = i + 1;
12756               loc = projection.invert(p);
12757             }
12758           }
12759
12760           if (idx !== undefined) {
12761             return {
12762               index: idx,
12763               distance: min,
12764               loc: loc
12765             };
12766           } else {
12767             return null;
12768           }
12769         } // Test active (dragged or drawing) segments against inactive segments
12770         // This is used to test e.g. multipolygon rings that cross
12771         // `activeNodes` is the ring containing the activeID being dragged.
12772         // `inactiveNodes` is the other ring to test against
12773
12774         function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
12775           var actives = [];
12776           var inactives = [];
12777           var j, k, n1, n2, segment; // gather active segments (only segments in activeNodes that contain the activeID)
12778
12779           for (j = 0; j < activeNodes.length - 1; j++) {
12780             n1 = activeNodes[j];
12781             n2 = activeNodes[j + 1];
12782             segment = [n1.loc, n2.loc];
12783
12784             if (n1.id === activeID || n2.id === activeID) {
12785               actives.push(segment);
12786             }
12787           } // gather inactive segments
12788
12789
12790           for (j = 0; j < inactiveNodes.length - 1; j++) {
12791             n1 = inactiveNodes[j];
12792             n2 = inactiveNodes[j + 1];
12793             segment = [n1.loc, n2.loc];
12794             inactives.push(segment);
12795           } // test
12796
12797
12798           for (j = 0; j < actives.length; j++) {
12799             for (k = 0; k < inactives.length; k++) {
12800               var p = actives[j];
12801               var q = inactives[k];
12802               var hit = geoLineIntersection(p, q);
12803
12804               if (hit) {
12805                 return true;
12806               }
12807             }
12808           }
12809
12810           return false;
12811         } // Test active (dragged or drawing) segments against inactive segments
12812         // This is used to test whether a way intersects with itself.
12813
12814         function geoHasSelfIntersections(nodes, activeID) {
12815           var actives = [];
12816           var inactives = [];
12817           var j, k; // group active and passive segments along the nodes
12818
12819           for (j = 0; j < nodes.length - 1; j++) {
12820             var n1 = nodes[j];
12821             var n2 = nodes[j + 1];
12822             var segment = [n1.loc, n2.loc];
12823
12824             if (n1.id === activeID || n2.id === activeID) {
12825               actives.push(segment);
12826             } else {
12827               inactives.push(segment);
12828             }
12829           } // test
12830
12831
12832           for (j = 0; j < actives.length; j++) {
12833             for (k = 0; k < inactives.length; k++) {
12834               var p = actives[j];
12835               var q = inactives[k]; // skip if segments share an endpoint
12836
12837               if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
12838                 continue;
12839               }
12840
12841               var hit = geoLineIntersection(p, q);
12842
12843               if (hit) {
12844                 var epsilon = 1e-8; // skip if the hit is at the segment's endpoint
12845
12846                 if (geoVecEqual(p[1], hit, epsilon) || geoVecEqual(p[0], hit, epsilon) || geoVecEqual(q[1], hit, epsilon) || geoVecEqual(q[0], hit, epsilon)) {
12847                   continue;
12848                 } else {
12849                   return true;
12850                 }
12851               }
12852             }
12853           }
12854
12855           return false;
12856         } // Return the intersection point of 2 line segments.
12857         // From https://github.com/pgkelley4/line-segments-intersect
12858         // This uses the vector cross product approach described below:
12859         //  http://stackoverflow.com/a/565282/786339
12860
12861         function geoLineIntersection(a, b) {
12862           var p = [a[0][0], a[0][1]];
12863           var p2 = [a[1][0], a[1][1]];
12864           var q = [b[0][0], b[0][1]];
12865           var q2 = [b[1][0], b[1][1]];
12866           var r = geoVecSubtract(p2, p);
12867           var s = geoVecSubtract(q2, q);
12868           var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
12869           var denominator = geoVecCross(r, s);
12870
12871           if (uNumerator && denominator) {
12872             var u = uNumerator / denominator;
12873             var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
12874
12875             if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
12876               return geoVecInterp(p, p2, t);
12877             }
12878           }
12879
12880           return null;
12881         }
12882         function geoPathIntersections(path1, path2) {
12883           var intersections = [];
12884
12885           for (var i = 0; i < path1.length - 1; i++) {
12886             for (var j = 0; j < path2.length - 1; j++) {
12887               var a = [path1[i], path1[i + 1]];
12888               var b = [path2[j], path2[j + 1]];
12889               var hit = geoLineIntersection(a, b);
12890
12891               if (hit) {
12892                 intersections.push(hit);
12893               }
12894             }
12895           }
12896
12897           return intersections;
12898         }
12899         function geoPathHasIntersections(path1, path2) {
12900           for (var i = 0; i < path1.length - 1; i++) {
12901             for (var j = 0; j < path2.length - 1; j++) {
12902               var a = [path1[i], path1[i + 1]];
12903               var b = [path2[j], path2[j + 1]];
12904               var hit = geoLineIntersection(a, b);
12905
12906               if (hit) {
12907                 return true;
12908               }
12909             }
12910           }
12911
12912           return false;
12913         } // Return whether point is contained in polygon.
12914         //
12915         // `point` should be a 2-item array of coordinates.
12916         // `polygon` should be an array of 2-item arrays of coordinates.
12917         //
12918         // From https://github.com/substack/point-in-polygon.
12919         // ray-casting algorithm based on
12920         // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
12921         //
12922
12923         function geoPointInPolygon(point, polygon) {
12924           var x = point[0];
12925           var y = point[1];
12926           var inside = false;
12927
12928           for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
12929             var xi = polygon[i][0];
12930             var yi = polygon[i][1];
12931             var xj = polygon[j][0];
12932             var yj = polygon[j][1];
12933             var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
12934             if (intersect) inside = !inside;
12935           }
12936
12937           return inside;
12938         }
12939         function geoPolygonContainsPolygon(outer, inner) {
12940           return inner.every(function (point) {
12941             return geoPointInPolygon(point, outer);
12942           });
12943         }
12944         function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
12945           function testPoints(outer, inner) {
12946             return inner.some(function (point) {
12947               return geoPointInPolygon(point, outer);
12948             });
12949           }
12950
12951           return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
12952         } // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
12953         // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
12954
12955         function geoGetSmallestSurroundingRectangle(points) {
12956           var hull = d3_polygonHull(points);
12957           var centroid = d3_polygonCentroid(hull);
12958           var minArea = Infinity;
12959           var ssrExtent = [];
12960           var ssrAngle = 0;
12961           var c1 = hull[0];
12962
12963           for (var i = 0; i <= hull.length - 1; i++) {
12964             var c2 = i === hull.length - 1 ? hull[0] : hull[i + 1];
12965             var angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
12966             var poly = geoRotate(hull, -angle, centroid);
12967             var extent = poly.reduce(function (extent, point) {
12968               return extent.extend(geoExtent(point));
12969             }, geoExtent());
12970             var area = extent.area();
12971
12972             if (area < minArea) {
12973               minArea = area;
12974               ssrExtent = extent;
12975               ssrAngle = angle;
12976             }
12977
12978             c1 = c2;
12979           }
12980
12981           return {
12982             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
12983             angle: ssrAngle
12984           };
12985         }
12986         function geoPathLength(path) {
12987           var length = 0;
12988
12989           for (var i = 0; i < path.length - 1; i++) {
12990             length += geoVecLength(path[i], path[i + 1]);
12991           }
12992
12993           return length;
12994         } // If the given point is at the edge of the padded viewport,
12995         // return a vector that will nudge the viewport in that direction
12996
12997         function geoViewportEdge(point, dimensions) {
12998           var pad = [80, 20, 50, 20]; // top, right, bottom, left
12999
13000           var x = 0;
13001           var y = 0;
13002           if (point[0] > dimensions[0] - pad[1]) x = -10;
13003           if (point[0] < pad[3]) x = 10;
13004           if (point[1] > dimensions[1] - pad[2]) y = -10;
13005           if (point[1] < pad[0]) y = 10;
13006
13007           if (x || y) {
13008             return [x, y];
13009           } else {
13010             return null;
13011           }
13012         }
13013
13014         var noop$1 = {
13015           value: function value() {}
13016         };
13017
13018         function dispatch() {
13019           for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
13020             if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
13021             _[t] = [];
13022           }
13023
13024           return new Dispatch$1(_);
13025         }
13026
13027         function Dispatch$1(_) {
13028           this._ = _;
13029         }
13030
13031         function parseTypenames(typenames, types) {
13032           return typenames.trim().split(/^|\s+/).map(function (t) {
13033             var name = "",
13034                 i = t.indexOf(".");
13035             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13036             if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
13037             return {
13038               type: t,
13039               name: name
13040             };
13041           });
13042         }
13043
13044         Dispatch$1.prototype = dispatch.prototype = {
13045           constructor: Dispatch$1,
13046           on: function on(typename, callback) {
13047             var _ = this._,
13048                 T = parseTypenames(typename + "", _),
13049                 t,
13050                 i = -1,
13051                 n = T.length; // If no callback was specified, return the callback of the given type and name.
13052
13053             if (arguments.length < 2) {
13054               while (++i < n) {
13055                 if ((t = (typename = T[i]).type) && (t = get$3(_[t], typename.name))) return t;
13056               }
13057
13058               return;
13059             } // If a type was specified, set the callback for the given type and name.
13060             // Otherwise, if a null callback was specified, remove callbacks of the given name.
13061
13062
13063             if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
13064
13065             while (++i < n) {
13066               if (t = (typename = T[i]).type) _[t] = set$3(_[t], typename.name, callback);else if (callback == null) for (t in _) {
13067                 _[t] = set$3(_[t], typename.name, null);
13068               }
13069             }
13070
13071             return this;
13072           },
13073           copy: function copy() {
13074             var copy = {},
13075                 _ = this._;
13076
13077             for (var t in _) {
13078               copy[t] = _[t].slice();
13079             }
13080
13081             return new Dispatch$1(copy);
13082           },
13083           call: function call(type, that) {
13084             if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) {
13085               args[i] = arguments[i + 2];
13086             }
13087             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13088
13089             for (t = this._[type], i = 0, n = t.length; i < n; ++i) {
13090               t[i].value.apply(that, args);
13091             }
13092           },
13093           apply: function apply(type, that, args) {
13094             if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13095
13096             for (var t = this._[type], i = 0, n = t.length; i < n; ++i) {
13097               t[i].value.apply(that, args);
13098             }
13099           }
13100         };
13101
13102         function get$3(type, name) {
13103           for (var i = 0, n = type.length, c; i < n; ++i) {
13104             if ((c = type[i]).name === name) {
13105               return c.value;
13106             }
13107           }
13108         }
13109
13110         function set$3(type, name, callback) {
13111           for (var i = 0, n = type.length; i < n; ++i) {
13112             if (type[i].name === name) {
13113               type[i] = noop$1, type = type.slice(0, i).concat(type.slice(i + 1));
13114               break;
13115             }
13116           }
13117
13118           if (callback != null) type.push({
13119             name: name,
13120             value: callback
13121           });
13122           return type;
13123         }
13124
13125         var xhtml = "http://www.w3.org/1999/xhtml";
13126         var namespaces = {
13127           svg: "http://www.w3.org/2000/svg",
13128           xhtml: xhtml,
13129           xlink: "http://www.w3.org/1999/xlink",
13130           xml: "http://www.w3.org/XML/1998/namespace",
13131           xmlns: "http://www.w3.org/2000/xmlns/"
13132         };
13133
13134         function namespace (name) {
13135           var prefix = name += "",
13136               i = prefix.indexOf(":");
13137           if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
13138           return namespaces.hasOwnProperty(prefix) ? {
13139             space: namespaces[prefix],
13140             local: name
13141           } : name; // eslint-disable-line no-prototype-builtins
13142         }
13143
13144         function creatorInherit(name) {
13145           return function () {
13146             var document = this.ownerDocument,
13147                 uri = this.namespaceURI;
13148             return uri === xhtml && document.documentElement.namespaceURI === xhtml ? document.createElement(name) : document.createElementNS(uri, name);
13149           };
13150         }
13151
13152         function creatorFixed(fullname) {
13153           return function () {
13154             return this.ownerDocument.createElementNS(fullname.space, fullname.local);
13155           };
13156         }
13157
13158         function creator (name) {
13159           var fullname = namespace(name);
13160           return (fullname.local ? creatorFixed : creatorInherit)(fullname);
13161         }
13162
13163         function none() {}
13164
13165         function selector (selector) {
13166           return selector == null ? none : function () {
13167             return this.querySelector(selector);
13168           };
13169         }
13170
13171         function selection_select (select) {
13172           if (typeof select !== "function") select = selector(select);
13173
13174           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13175             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
13176               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
13177                 if ("__data__" in node) subnode.__data__ = node.__data__;
13178                 subgroup[i] = subnode;
13179               }
13180             }
13181           }
13182
13183           return new Selection(subgroups, this._parents);
13184         }
13185
13186         function array (x) {
13187           return _typeof(x) === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like
13188           : Array.from(x); // Map, Set, iterable, string, or anything else
13189         }
13190
13191         function empty() {
13192           return [];
13193         }
13194
13195         function selectorAll (selector) {
13196           return selector == null ? empty : function () {
13197             return this.querySelectorAll(selector);
13198           };
13199         }
13200
13201         function arrayAll(select) {
13202           return function () {
13203             var group = select.apply(this, arguments);
13204             return group == null ? [] : array(group);
13205           };
13206         }
13207
13208         function selection_selectAll (select) {
13209           if (typeof select === "function") select = arrayAll(select);else select = selectorAll(select);
13210
13211           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
13212             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
13213               if (node = group[i]) {
13214                 subgroups.push(select.call(node, node.__data__, i, group));
13215                 parents.push(node);
13216               }
13217             }
13218           }
13219
13220           return new Selection(subgroups, parents);
13221         }
13222
13223         var $find$1 = arrayIteration.find;
13224
13225
13226
13227         var FIND = 'find';
13228         var SKIPS_HOLES = true;
13229
13230         var USES_TO_LENGTH$a = arrayMethodUsesToLength(FIND);
13231
13232         // Shouldn't skip holes
13233         if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES = false; });
13234
13235         // `Array.prototype.find` method
13236         // https://tc39.github.io/ecma262/#sec-array.prototype.find
13237         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES || !USES_TO_LENGTH$a }, {
13238           find: function find(callbackfn /* , that = undefined */) {
13239             return $find$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13240           }
13241         });
13242
13243         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
13244         addToUnscopables(FIND);
13245
13246         function matcher (selector) {
13247           return function () {
13248             return this.matches(selector);
13249           };
13250         }
13251         function childMatcher(selector) {
13252           return function (node) {
13253             return node.matches(selector);
13254           };
13255         }
13256
13257         var find$1 = Array.prototype.find;
13258
13259         function childFind(match) {
13260           return function () {
13261             return find$1.call(this.children, match);
13262           };
13263         }
13264
13265         function childFirst() {
13266           return this.firstElementChild;
13267         }
13268
13269         function selection_selectChild (match) {
13270           return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
13271         }
13272
13273         var filter = Array.prototype.filter;
13274
13275         function children() {
13276           return this.children;
13277         }
13278
13279         function childrenFilter(match) {
13280           return function () {
13281             return filter.call(this.children, match);
13282           };
13283         }
13284
13285         function selection_selectChildren (match) {
13286           return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
13287         }
13288
13289         function selection_filter (match) {
13290           if (typeof match !== "function") match = matcher(match);
13291
13292           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
13293             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
13294               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
13295                 subgroup.push(node);
13296               }
13297             }
13298           }
13299
13300           return new Selection(subgroups, this._parents);
13301         }
13302
13303         function sparse (update) {
13304           return new Array(update.length);
13305         }
13306
13307         function selection_enter () {
13308           return new Selection(this._enter || this._groups.map(sparse), this._parents);
13309         }
13310         function EnterNode(parent, datum) {
13311           this.ownerDocument = parent.ownerDocument;
13312           this.namespaceURI = parent.namespaceURI;
13313           this._next = null;
13314           this._parent = parent;
13315           this.__data__ = datum;
13316         }
13317         EnterNode.prototype = {
13318           constructor: EnterNode,
13319           appendChild: function appendChild(child) {
13320             return this._parent.insertBefore(child, this._next);
13321           },
13322           insertBefore: function insertBefore(child, next) {
13323             return this._parent.insertBefore(child, next);
13324           },
13325           querySelector: function querySelector(selector) {
13326             return this._parent.querySelector(selector);
13327           },
13328           querySelectorAll: function querySelectorAll(selector) {
13329             return this._parent.querySelectorAll(selector);
13330           }
13331         };
13332
13333         function constant (x) {
13334           return function () {
13335             return x;
13336           };
13337         }
13338
13339         function bindIndex(parent, group, enter, update, exit, data) {
13340           var i = 0,
13341               node,
13342               groupLength = group.length,
13343               dataLength = data.length; // Put any non-null nodes that fit into update.
13344           // Put any null nodes into enter.
13345           // Put any remaining data into enter.
13346
13347           for (; i < dataLength; ++i) {
13348             if (node = group[i]) {
13349               node.__data__ = data[i];
13350               update[i] = node;
13351             } else {
13352               enter[i] = new EnterNode(parent, data[i]);
13353             }
13354           } // Put any non-null nodes that don’t fit into exit.
13355
13356
13357           for (; i < groupLength; ++i) {
13358             if (node = group[i]) {
13359               exit[i] = node;
13360             }
13361           }
13362         }
13363
13364         function bindKey(parent, group, enter, update, exit, data, key) {
13365           var i,
13366               node,
13367               nodeByKeyValue = new Map(),
13368               groupLength = group.length,
13369               dataLength = data.length,
13370               keyValues = new Array(groupLength),
13371               keyValue; // Compute the key for each node.
13372           // If multiple nodes have the same key, the duplicates are added to exit.
13373
13374           for (i = 0; i < groupLength; ++i) {
13375             if (node = group[i]) {
13376               keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
13377
13378               if (nodeByKeyValue.has(keyValue)) {
13379                 exit[i] = node;
13380               } else {
13381                 nodeByKeyValue.set(keyValue, node);
13382               }
13383             }
13384           } // Compute the key for each datum.
13385           // If there a node associated with this key, join and add it to update.
13386           // If there is not (or the key is a duplicate), add it to enter.
13387
13388
13389           for (i = 0; i < dataLength; ++i) {
13390             keyValue = key.call(parent, data[i], i, data) + "";
13391
13392             if (node = nodeByKeyValue.get(keyValue)) {
13393               update[i] = node;
13394               node.__data__ = data[i];
13395               nodeByKeyValue["delete"](keyValue);
13396             } else {
13397               enter[i] = new EnterNode(parent, data[i]);
13398             }
13399           } // Add any remaining nodes that were not bound to data to exit.
13400
13401
13402           for (i = 0; i < groupLength; ++i) {
13403             if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
13404               exit[i] = node;
13405             }
13406           }
13407         }
13408
13409         function datum(node) {
13410           return node.__data__;
13411         }
13412
13413         function selection_data (value, key) {
13414           if (!arguments.length) return Array.from(this, datum);
13415           var bind = key ? bindKey : bindIndex,
13416               parents = this._parents,
13417               groups = this._groups;
13418           if (typeof value !== "function") value = constant(value);
13419
13420           for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
13421             var parent = parents[j],
13422                 group = groups[j],
13423                 groupLength = group.length,
13424                 data = array(value.call(parent, parent && parent.__data__, j, parents)),
13425                 dataLength = data.length,
13426                 enterGroup = enter[j] = new Array(dataLength),
13427                 updateGroup = update[j] = new Array(dataLength),
13428                 exitGroup = exit[j] = new Array(groupLength);
13429             bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); // Now connect the enter nodes to their following update node, such that
13430             // appendChild can insert the materialized enter node before this node,
13431             // rather than at the end of the parent node.
13432
13433             for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
13434               if (previous = enterGroup[i0]) {
13435                 if (i0 >= i1) i1 = i0 + 1;
13436
13437                 while (!(next = updateGroup[i1]) && ++i1 < dataLength) {
13438                 }
13439
13440                 previous._next = next || null;
13441               }
13442             }
13443           }
13444
13445           update = new Selection(update, parents);
13446           update._enter = enter;
13447           update._exit = exit;
13448           return update;
13449         }
13450
13451         function selection_exit () {
13452           return new Selection(this._exit || this._groups.map(sparse), this._parents);
13453         }
13454
13455         function selection_join (onenter, onupdate, onexit) {
13456           var enter = this.enter(),
13457               update = this,
13458               exit = this.exit();
13459           enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
13460           if (onupdate != null) update = onupdate(update);
13461           if (onexit == null) exit.remove();else onexit(exit);
13462           return enter && update ? enter.merge(update).order() : update;
13463         }
13464
13465         function selection_merge (selection) {
13466           if (!(selection instanceof Selection)) throw new Error("invalid merge");
13467
13468           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) {
13469             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
13470               if (node = group0[i] || group1[i]) {
13471                 merge[i] = node;
13472               }
13473             }
13474           }
13475
13476           for (; j < m0; ++j) {
13477             merges[j] = groups0[j];
13478           }
13479
13480           return new Selection(merges, this._parents);
13481         }
13482
13483         function selection_order () {
13484           for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
13485             for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
13486               if (node = group[i]) {
13487                 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
13488                 next = node;
13489               }
13490             }
13491           }
13492
13493           return this;
13494         }
13495
13496         function selection_sort (compare) {
13497           if (!compare) compare = ascending;
13498
13499           function compareNode(a, b) {
13500             return a && b ? compare(a.__data__, b.__data__) : !a - !b;
13501           }
13502
13503           for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
13504             for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
13505               if (node = group[i]) {
13506                 sortgroup[i] = node;
13507               }
13508             }
13509
13510             sortgroup.sort(compareNode);
13511           }
13512
13513           return new Selection(sortgroups, this._parents).order();
13514         }
13515
13516         function ascending(a, b) {
13517           return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
13518         }
13519
13520         function selection_call () {
13521           var callback = arguments[0];
13522           arguments[0] = this;
13523           callback.apply(null, arguments);
13524           return this;
13525         }
13526
13527         function selection_nodes () {
13528           return Array.from(this);
13529         }
13530
13531         function selection_node () {
13532           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13533             for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
13534               var node = group[i];
13535               if (node) return node;
13536             }
13537           }
13538
13539           return null;
13540         }
13541
13542         function selection_size () {
13543           var size = 0;
13544
13545           var _iterator = _createForOfIteratorHelper(this),
13546               _step;
13547
13548           try {
13549             for (_iterator.s(); !(_step = _iterator.n()).done;) {
13550               var node = _step.value;
13551               ++size;
13552             } // eslint-disable-line no-unused-vars
13553
13554           } catch (err) {
13555             _iterator.e(err);
13556           } finally {
13557             _iterator.f();
13558           }
13559
13560           return size;
13561         }
13562
13563         function selection_empty () {
13564           return !this.node();
13565         }
13566
13567         function selection_each (callback) {
13568           for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
13569             for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
13570               if (node = group[i]) callback.call(node, node.__data__, i, group);
13571             }
13572           }
13573
13574           return this;
13575         }
13576
13577         function attrRemove(name) {
13578           return function () {
13579             this.removeAttribute(name);
13580           };
13581         }
13582
13583         function attrRemoveNS(fullname) {
13584           return function () {
13585             this.removeAttributeNS(fullname.space, fullname.local);
13586           };
13587         }
13588
13589         function attrConstant(name, value) {
13590           return function () {
13591             this.setAttribute(name, value);
13592           };
13593         }
13594
13595         function attrConstantNS(fullname, value) {
13596           return function () {
13597             this.setAttributeNS(fullname.space, fullname.local, value);
13598           };
13599         }
13600
13601         function attrFunction(name, value) {
13602           return function () {
13603             var v = value.apply(this, arguments);
13604             if (v == null) this.removeAttribute(name);else this.setAttribute(name, v);
13605           };
13606         }
13607
13608         function attrFunctionNS(fullname, value) {
13609           return function () {
13610             var v = value.apply(this, arguments);
13611             if (v == null) this.removeAttributeNS(fullname.space, fullname.local);else this.setAttributeNS(fullname.space, fullname.local, v);
13612           };
13613         }
13614
13615         function selection_attr (name, value) {
13616           var fullname = namespace(name);
13617
13618           if (arguments.length < 2) {
13619             var node = this.node();
13620             return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
13621           }
13622
13623           return this.each((value == null ? fullname.local ? attrRemoveNS : attrRemove : typeof value === "function" ? fullname.local ? attrFunctionNS : attrFunction : fullname.local ? attrConstantNS : attrConstant)(fullname, value));
13624         }
13625
13626         function defaultView (node) {
13627           return node.ownerDocument && node.ownerDocument.defaultView || // node is a Node
13628           node.document && node // node is a Window
13629           || node.defaultView; // node is a Document
13630         }
13631
13632         function styleRemove(name) {
13633           return function () {
13634             this.style.removeProperty(name);
13635           };
13636         }
13637
13638         function styleConstant(name, value, priority) {
13639           return function () {
13640             this.style.setProperty(name, value, priority);
13641           };
13642         }
13643
13644         function styleFunction(name, value, priority) {
13645           return function () {
13646             var v = value.apply(this, arguments);
13647             if (v == null) this.style.removeProperty(name);else this.style.setProperty(name, v, priority);
13648           };
13649         }
13650
13651         function selection_style (name, value, priority) {
13652           return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function" ? styleFunction : styleConstant)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
13653         }
13654         function styleValue(node, name) {
13655           return node.style.getPropertyValue(name) || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
13656         }
13657
13658         function propertyRemove(name) {
13659           return function () {
13660             delete this[name];
13661           };
13662         }
13663
13664         function propertyConstant(name, value) {
13665           return function () {
13666             this[name] = value;
13667           };
13668         }
13669
13670         function propertyFunction(name, value) {
13671           return function () {
13672             var v = value.apply(this, arguments);
13673             if (v == null) delete this[name];else this[name] = v;
13674           };
13675         }
13676
13677         function selection_property (name, value) {
13678           return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
13679         }
13680
13681         function classArray(string) {
13682           return string.trim().split(/^|\s+/);
13683         }
13684
13685         function classList(node) {
13686           return node.classList || new ClassList(node);
13687         }
13688
13689         function ClassList(node) {
13690           this._node = node;
13691           this._names = classArray(node.getAttribute("class") || "");
13692         }
13693
13694         ClassList.prototype = {
13695           add: function add(name) {
13696             var i = this._names.indexOf(name);
13697
13698             if (i < 0) {
13699               this._names.push(name);
13700
13701               this._node.setAttribute("class", this._names.join(" "));
13702             }
13703           },
13704           remove: function remove(name) {
13705             var i = this._names.indexOf(name);
13706
13707             if (i >= 0) {
13708               this._names.splice(i, 1);
13709
13710               this._node.setAttribute("class", this._names.join(" "));
13711             }
13712           },
13713           contains: function contains(name) {
13714             return this._names.indexOf(name) >= 0;
13715           }
13716         };
13717
13718         function classedAdd(node, names) {
13719           var list = classList(node),
13720               i = -1,
13721               n = names.length;
13722
13723           while (++i < n) {
13724             list.add(names[i]);
13725           }
13726         }
13727
13728         function classedRemove(node, names) {
13729           var list = classList(node),
13730               i = -1,
13731               n = names.length;
13732
13733           while (++i < n) {
13734             list.remove(names[i]);
13735           }
13736         }
13737
13738         function classedTrue(names) {
13739           return function () {
13740             classedAdd(this, names);
13741           };
13742         }
13743
13744         function classedFalse(names) {
13745           return function () {
13746             classedRemove(this, names);
13747           };
13748         }
13749
13750         function classedFunction(names, value) {
13751           return function () {
13752             (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
13753           };
13754         }
13755
13756         function selection_classed (name, value) {
13757           var names = classArray(name + "");
13758
13759           if (arguments.length < 2) {
13760             var list = classList(this.node()),
13761                 i = -1,
13762                 n = names.length;
13763
13764             while (++i < n) {
13765               if (!list.contains(names[i])) return false;
13766             }
13767
13768             return true;
13769           }
13770
13771           return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
13772         }
13773
13774         function textRemove() {
13775           this.textContent = "";
13776         }
13777
13778         function textConstant(value) {
13779           return function () {
13780             this.textContent = value;
13781           };
13782         }
13783
13784         function textFunction(value) {
13785           return function () {
13786             var v = value.apply(this, arguments);
13787             this.textContent = v == null ? "" : v;
13788           };
13789         }
13790
13791         function selection_text (value) {
13792           return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction : textConstant)(value)) : this.node().textContent;
13793         }
13794
13795         function htmlRemove() {
13796           this.innerHTML = "";
13797         }
13798
13799         function htmlConstant(value) {
13800           return function () {
13801             this.innerHTML = value;
13802           };
13803         }
13804
13805         function htmlFunction(value) {
13806           return function () {
13807             var v = value.apply(this, arguments);
13808             this.innerHTML = v == null ? "" : v;
13809           };
13810         }
13811
13812         function selection_html (value) {
13813           return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
13814         }
13815
13816         function raise() {
13817           if (this.nextSibling) this.parentNode.appendChild(this);
13818         }
13819
13820         function selection_raise () {
13821           return this.each(raise);
13822         }
13823
13824         function lower() {
13825           if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
13826         }
13827
13828         function selection_lower () {
13829           return this.each(lower);
13830         }
13831
13832         function selection_append (name) {
13833           var create = typeof name === "function" ? name : creator(name);
13834           return this.select(function () {
13835             return this.appendChild(create.apply(this, arguments));
13836           });
13837         }
13838
13839         function constantNull() {
13840           return null;
13841         }
13842
13843         function selection_insert (name, before) {
13844           var create = typeof name === "function" ? name : creator(name),
13845               select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
13846           return this.select(function () {
13847             return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
13848           });
13849         }
13850
13851         function remove() {
13852           var parent = this.parentNode;
13853           if (parent) parent.removeChild(this);
13854         }
13855
13856         function selection_remove () {
13857           return this.each(remove);
13858         }
13859
13860         function selection_cloneShallow() {
13861           var clone = this.cloneNode(false),
13862               parent = this.parentNode;
13863           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
13864         }
13865
13866         function selection_cloneDeep() {
13867           var clone = this.cloneNode(true),
13868               parent = this.parentNode;
13869           return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
13870         }
13871
13872         function selection_clone (deep) {
13873           return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
13874         }
13875
13876         function selection_datum (value) {
13877           return arguments.length ? this.property("__data__", value) : this.node().__data__;
13878         }
13879
13880         function contextListener(listener) {
13881           return function (event) {
13882             listener.call(this, event, this.__data__);
13883           };
13884         }
13885
13886         function parseTypenames$1(typenames) {
13887           return typenames.trim().split(/^|\s+/).map(function (t) {
13888             var name = "",
13889                 i = t.indexOf(".");
13890             if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13891             return {
13892               type: t,
13893               name: name
13894             };
13895           });
13896         }
13897
13898         function onRemove(typename) {
13899           return function () {
13900             var on = this.__on;
13901             if (!on) return;
13902
13903             for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
13904               if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
13905                 this.removeEventListener(o.type, o.listener, o.options);
13906               } else {
13907                 on[++i] = o;
13908               }
13909             }
13910
13911             if (++i) on.length = i;else delete this.__on;
13912           };
13913         }
13914
13915         function onAdd(typename, value, options) {
13916           return function () {
13917             var on = this.__on,
13918                 o,
13919                 listener = contextListener(value);
13920             if (on) for (var j = 0, m = on.length; j < m; ++j) {
13921               if ((o = on[j]).type === typename.type && o.name === typename.name) {
13922                 this.removeEventListener(o.type, o.listener, o.options);
13923                 this.addEventListener(o.type, o.listener = listener, o.options = options);
13924                 o.value = value;
13925                 return;
13926               }
13927             }
13928             this.addEventListener(typename.type, listener, options);
13929             o = {
13930               type: typename.type,
13931               name: typename.name,
13932               value: value,
13933               listener: listener,
13934               options: options
13935             };
13936             if (!on) this.__on = [o];else on.push(o);
13937           };
13938         }
13939
13940         function selection_on (typename, value, options) {
13941           var typenames = parseTypenames$1(typename + ""),
13942               i,
13943               n = typenames.length,
13944               t;
13945
13946           if (arguments.length < 2) {
13947             var on = this.node().__on;
13948
13949             if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
13950               for (i = 0, o = on[j]; i < n; ++i) {
13951                 if ((t = typenames[i]).type === o.type && t.name === o.name) {
13952                   return o.value;
13953                 }
13954               }
13955             }
13956             return;
13957           }
13958
13959           on = value ? onAdd : onRemove;
13960
13961           for (i = 0; i < n; ++i) {
13962             this.each(on(typenames[i], value, options));
13963           }
13964
13965           return this;
13966         }
13967
13968         function dispatchEvent$1(node, type, params) {
13969           var window = defaultView(node),
13970               event = window.CustomEvent;
13971
13972           if (typeof event === "function") {
13973             event = new event(type, params);
13974           } else {
13975             event = window.document.createEvent("Event");
13976             if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;else event.initEvent(type, false, false);
13977           }
13978
13979           node.dispatchEvent(event);
13980         }
13981
13982         function dispatchConstant(type, params) {
13983           return function () {
13984             return dispatchEvent$1(this, type, params);
13985           };
13986         }
13987
13988         function dispatchFunction(type, params) {
13989           return function () {
13990             return dispatchEvent$1(this, type, params.apply(this, arguments));
13991           };
13992         }
13993
13994         function selection_dispatch (type, params) {
13995           return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
13996         }
13997
13998         var _marked$2 = /*#__PURE__*/regeneratorRuntime.mark(_callee);
13999
14000         function _callee() {
14001           var groups, j, m, group, i, n, node;
14002           return regeneratorRuntime.wrap(function _callee$(_context) {
14003             while (1) {
14004               switch (_context.prev = _context.next) {
14005                 case 0:
14006                   groups = this._groups, j = 0, m = groups.length;
14007
14008                 case 1:
14009                   if (!(j < m)) {
14010                     _context.next = 13;
14011                     break;
14012                   }
14013
14014                   group = groups[j], i = 0, n = group.length;
14015
14016                 case 3:
14017                   if (!(i < n)) {
14018                     _context.next = 10;
14019                     break;
14020                   }
14021
14022                   if (!(node = group[i])) {
14023                     _context.next = 7;
14024                     break;
14025                   }
14026
14027                   _context.next = 7;
14028                   return node;
14029
14030                 case 7:
14031                   ++i;
14032                   _context.next = 3;
14033                   break;
14034
14035                 case 10:
14036                   ++j;
14037                   _context.next = 1;
14038                   break;
14039
14040                 case 13:
14041                 case "end":
14042                   return _context.stop();
14043               }
14044             }
14045           }, _marked$2, this);
14046         }
14047
14048         var root = [null];
14049         function Selection(groups, parents) {
14050           this._groups = groups;
14051           this._parents = parents;
14052         }
14053
14054         function selection() {
14055           return new Selection([[document.documentElement]], root);
14056         }
14057
14058         function selection_selection() {
14059           return this;
14060         }
14061
14062         Selection.prototype = selection.prototype = _defineProperty({
14063           constructor: Selection,
14064           select: selection_select,
14065           selectAll: selection_selectAll,
14066           selectChild: selection_selectChild,
14067           selectChildren: selection_selectChildren,
14068           filter: selection_filter,
14069           data: selection_data,
14070           enter: selection_enter,
14071           exit: selection_exit,
14072           join: selection_join,
14073           merge: selection_merge,
14074           selection: selection_selection,
14075           order: selection_order,
14076           sort: selection_sort,
14077           call: selection_call,
14078           nodes: selection_nodes,
14079           node: selection_node,
14080           size: selection_size,
14081           empty: selection_empty,
14082           each: selection_each,
14083           attr: selection_attr,
14084           style: selection_style,
14085           property: selection_property,
14086           classed: selection_classed,
14087           text: selection_text,
14088           html: selection_html,
14089           raise: selection_raise,
14090           lower: selection_lower,
14091           append: selection_append,
14092           insert: selection_insert,
14093           remove: selection_remove,
14094           clone: selection_clone,
14095           datum: selection_datum,
14096           on: selection_on,
14097           dispatch: selection_dispatch
14098         }, Symbol.iterator, _callee);
14099
14100         function select (selector) {
14101           return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
14102         }
14103
14104         function sourceEvent (event) {
14105           var sourceEvent;
14106
14107           while (sourceEvent = event.sourceEvent) {
14108             event = sourceEvent;
14109           }
14110
14111           return event;
14112         }
14113
14114         function pointer (event, node) {
14115           event = sourceEvent(event);
14116           if (node === undefined) node = event.currentTarget;
14117
14118           if (node) {
14119             var svg = node.ownerSVGElement || node;
14120
14121             if (svg.createSVGPoint) {
14122               var point = svg.createSVGPoint();
14123               point.x = event.clientX, point.y = event.clientY;
14124               point = point.matrixTransform(node.getScreenCTM().inverse());
14125               return [point.x, point.y];
14126             }
14127
14128             if (node.getBoundingClientRect) {
14129               var rect = node.getBoundingClientRect();
14130               return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
14131             }
14132           }
14133
14134           return [event.pageX, event.pageY];
14135         }
14136
14137         function selectAll (selector) {
14138           return typeof selector === "string" ? new Selection([document.querySelectorAll(selector)], [document.documentElement]) : new Selection([selector == null ? [] : array(selector)], root);
14139         }
14140
14141         function nopropagation(event) {
14142           event.stopImmediatePropagation();
14143         }
14144         function noevent (event) {
14145           event.preventDefault();
14146           event.stopImmediatePropagation();
14147         }
14148
14149         function dragDisable (view) {
14150           var root = view.document.documentElement,
14151               selection = select(view).on("dragstart.drag", noevent, true);
14152
14153           if ("onselectstart" in root) {
14154             selection.on("selectstart.drag", noevent, true);
14155           } else {
14156             root.__noselect = root.style.MozUserSelect;
14157             root.style.MozUserSelect = "none";
14158           }
14159         }
14160         function yesdrag(view, noclick) {
14161           var root = view.document.documentElement,
14162               selection = select(view).on("dragstart.drag", null);
14163
14164           if (noclick) {
14165             selection.on("click.drag", noevent, true);
14166             setTimeout(function () {
14167               selection.on("click.drag", null);
14168             }, 0);
14169           }
14170
14171           if ("onselectstart" in root) {
14172             selection.on("selectstart.drag", null);
14173           } else {
14174             root.style.MozUserSelect = root.__noselect;
14175             delete root.__noselect;
14176           }
14177         }
14178
14179         var constant$1 = (function (x) {
14180           return function () {
14181             return x;
14182           };
14183         });
14184
14185         // `Object.defineProperties` method
14186         // https://tc39.github.io/ecma262/#sec-object.defineproperties
14187         _export({ target: 'Object', stat: true, forced: !descriptors, sham: !descriptors }, {
14188           defineProperties: objectDefineProperties
14189         });
14190
14191         function DragEvent(type, _ref) {
14192           var sourceEvent = _ref.sourceEvent,
14193               subject = _ref.subject,
14194               target = _ref.target,
14195               identifier = _ref.identifier,
14196               active = _ref.active,
14197               x = _ref.x,
14198               y = _ref.y,
14199               dx = _ref.dx,
14200               dy = _ref.dy,
14201               dispatch = _ref.dispatch;
14202           Object.defineProperties(this, {
14203             type: {
14204               value: type,
14205               enumerable: true,
14206               configurable: true
14207             },
14208             sourceEvent: {
14209               value: sourceEvent,
14210               enumerable: true,
14211               configurable: true
14212             },
14213             subject: {
14214               value: subject,
14215               enumerable: true,
14216               configurable: true
14217             },
14218             target: {
14219               value: target,
14220               enumerable: true,
14221               configurable: true
14222             },
14223             identifier: {
14224               value: identifier,
14225               enumerable: true,
14226               configurable: true
14227             },
14228             active: {
14229               value: active,
14230               enumerable: true,
14231               configurable: true
14232             },
14233             x: {
14234               value: x,
14235               enumerable: true,
14236               configurable: true
14237             },
14238             y: {
14239               value: y,
14240               enumerable: true,
14241               configurable: true
14242             },
14243             dx: {
14244               value: dx,
14245               enumerable: true,
14246               configurable: true
14247             },
14248             dy: {
14249               value: dy,
14250               enumerable: true,
14251               configurable: true
14252             },
14253             _: {
14254               value: dispatch
14255             }
14256           });
14257         }
14258
14259         DragEvent.prototype.on = function () {
14260           var value = this._.on.apply(this._, arguments);
14261
14262           return value === this._ ? this : value;
14263         };
14264
14265         function defaultFilter(event) {
14266           return !event.ctrlKey && !event.button;
14267         }
14268
14269         function defaultContainer() {
14270           return this.parentNode;
14271         }
14272
14273         function defaultSubject(event, d) {
14274           return d == null ? {
14275             x: event.x,
14276             y: event.y
14277           } : d;
14278         }
14279
14280         function defaultTouchable() {
14281           return navigator.maxTouchPoints || "ontouchstart" in this;
14282         }
14283
14284         function d3_drag () {
14285           var filter = defaultFilter,
14286               container = defaultContainer,
14287               subject = defaultSubject,
14288               touchable = defaultTouchable,
14289               gestures = {},
14290               listeners = dispatch("start", "drag", "end"),
14291               active = 0,
14292               mousedownx,
14293               mousedowny,
14294               mousemoving,
14295               touchending,
14296               clickDistance2 = 0;
14297
14298           function drag(selection) {
14299             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)");
14300           }
14301
14302           function mousedowned(event, d) {
14303             if (touchending || !filter.call(this, event, d)) return;
14304             var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
14305             if (!gesture) return;
14306             select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
14307             dragDisable(event.view);
14308             nopropagation(event);
14309             mousemoving = false;
14310             mousedownx = event.clientX;
14311             mousedowny = event.clientY;
14312             gesture("start", event);
14313           }
14314
14315           function mousemoved(event) {
14316             noevent(event);
14317
14318             if (!mousemoving) {
14319               var dx = event.clientX - mousedownx,
14320                   dy = event.clientY - mousedowny;
14321               mousemoving = dx * dx + dy * dy > clickDistance2;
14322             }
14323
14324             gestures.mouse("drag", event);
14325           }
14326
14327           function mouseupped(event) {
14328             select(event.view).on("mousemove.drag mouseup.drag", null);
14329             yesdrag(event.view, mousemoving);
14330             noevent(event);
14331             gestures.mouse("end", event);
14332           }
14333
14334           function touchstarted(event, d) {
14335             if (!filter.call(this, event, d)) return;
14336             var touches = event.changedTouches,
14337                 c = container.call(this, event, d),
14338                 n = touches.length,
14339                 i,
14340                 gesture;
14341
14342             for (i = 0; i < n; ++i) {
14343               if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
14344                 nopropagation(event);
14345                 gesture("start", event, touches[i]);
14346               }
14347             }
14348           }
14349
14350           function touchmoved(event) {
14351             var touches = event.changedTouches,
14352                 n = touches.length,
14353                 i,
14354                 gesture;
14355
14356             for (i = 0; i < n; ++i) {
14357               if (gesture = gestures[touches[i].identifier]) {
14358                 noevent(event);
14359                 gesture("drag", event, touches[i]);
14360               }
14361             }
14362           }
14363
14364           function touchended(event) {
14365             var touches = event.changedTouches,
14366                 n = touches.length,
14367                 i,
14368                 gesture;
14369             if (touchending) clearTimeout(touchending);
14370             touchending = setTimeout(function () {
14371               touchending = null;
14372             }, 500); // Ghost clicks are delayed!
14373
14374             for (i = 0; i < n; ++i) {
14375               if (gesture = gestures[touches[i].identifier]) {
14376                 nopropagation(event);
14377                 gesture("end", event, touches[i]);
14378               }
14379             }
14380           }
14381
14382           function beforestart(that, container, event, d, identifier, touch) {
14383             var dispatch = listeners.copy(),
14384                 p = pointer(touch || event, container),
14385                 dx,
14386                 dy,
14387                 s;
14388             if ((s = subject.call(that, new DragEvent("beforestart", {
14389               sourceEvent: event,
14390               target: drag,
14391               identifier: identifier,
14392               active: active,
14393               x: p[0],
14394               y: p[1],
14395               dx: 0,
14396               dy: 0,
14397               dispatch: dispatch
14398             }), d)) == null) return;
14399             dx = s.x - p[0] || 0;
14400             dy = s.y - p[1] || 0;
14401             return function gesture(type, event, touch) {
14402               var p0 = p,
14403                   n;
14404
14405               switch (type) {
14406                 case "start":
14407                   gestures[identifier] = gesture, n = active++;
14408                   break;
14409
14410                 case "end":
14411                   delete gestures[identifier], --active;
14412                 // nobreak
14413
14414                 case "drag":
14415                   p = pointer(touch || event, container), n = active;
14416                   break;
14417               }
14418
14419               dispatch.call(type, that, new DragEvent(type, {
14420                 sourceEvent: event,
14421                 subject: s,
14422                 target: drag,
14423                 identifier: identifier,
14424                 active: n,
14425                 x: p[0] + dx,
14426                 y: p[1] + dy,
14427                 dx: p[0] - p0[0],
14428                 dy: p[1] - p0[1],
14429                 dispatch: dispatch
14430               }), d);
14431             };
14432           }
14433
14434           drag.filter = function (_) {
14435             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$1(!!_), drag) : filter;
14436           };
14437
14438           drag.container = function (_) {
14439             return arguments.length ? (container = typeof _ === "function" ? _ : constant$1(_), drag) : container;
14440           };
14441
14442           drag.subject = function (_) {
14443             return arguments.length ? (subject = typeof _ === "function" ? _ : constant$1(_), drag) : subject;
14444           };
14445
14446           drag.touchable = function (_) {
14447             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$1(!!_), drag) : touchable;
14448           };
14449
14450           drag.on = function () {
14451             var value = listeners.on.apply(listeners, arguments);
14452             return value === listeners ? drag : value;
14453           };
14454
14455           drag.clickDistance = function (_) {
14456             return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
14457           };
14458
14459           return drag;
14460         }
14461
14462         var defineProperty$9 = objectDefineProperty.f;
14463         var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
14464
14465
14466
14467
14468
14469         var setInternalState$8 = internalState.set;
14470
14471
14472
14473         var MATCH$1 = wellKnownSymbol('match');
14474         var NativeRegExp = global_1.RegExp;
14475         var RegExpPrototype$1 = NativeRegExp.prototype;
14476         var re1 = /a/g;
14477         var re2 = /a/g;
14478
14479         // "new" should create a new object, old webkit bug
14480         var CORRECT_NEW = new NativeRegExp(re1) !== re1;
14481
14482         var UNSUPPORTED_Y$2 = regexpStickyHelpers.UNSUPPORTED_Y;
14483
14484         var FORCED$b = descriptors && isForced_1('RegExp', (!CORRECT_NEW || UNSUPPORTED_Y$2 || fails(function () {
14485           re2[MATCH$1] = false;
14486           // RegExp constructor can alter flags and IsRegExp works correct with @@match
14487           return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
14488         })));
14489
14490         // `RegExp` constructor
14491         // https://tc39.github.io/ecma262/#sec-regexp-constructor
14492         if (FORCED$b) {
14493           var RegExpWrapper = function RegExp(pattern, flags) {
14494             var thisIsRegExp = this instanceof RegExpWrapper;
14495             var patternIsRegExp = isRegexp(pattern);
14496             var flagsAreUndefined = flags === undefined;
14497             var sticky;
14498
14499             if (!thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined) {
14500               return pattern;
14501             }
14502
14503             if (CORRECT_NEW) {
14504               if (patternIsRegExp && !flagsAreUndefined) pattern = pattern.source;
14505             } else if (pattern instanceof RegExpWrapper) {
14506               if (flagsAreUndefined) flags = regexpFlags.call(pattern);
14507               pattern = pattern.source;
14508             }
14509
14510             if (UNSUPPORTED_Y$2) {
14511               sticky = !!flags && flags.indexOf('y') > -1;
14512               if (sticky) flags = flags.replace(/y/g, '');
14513             }
14514
14515             var result = inheritIfRequired(
14516               CORRECT_NEW ? new NativeRegExp(pattern, flags) : NativeRegExp(pattern, flags),
14517               thisIsRegExp ? this : RegExpPrototype$1,
14518               RegExpWrapper
14519             );
14520
14521             if (UNSUPPORTED_Y$2 && sticky) setInternalState$8(result, { sticky: sticky });
14522
14523             return result;
14524           };
14525           var proxy = function (key) {
14526             key in RegExpWrapper || defineProperty$9(RegExpWrapper, key, {
14527               configurable: true,
14528               get: function () { return NativeRegExp[key]; },
14529               set: function (it) { NativeRegExp[key] = it; }
14530             });
14531           };
14532           var keys$2 = getOwnPropertyNames$1(NativeRegExp);
14533           var index = 0;
14534           while (keys$2.length > index) proxy(keys$2[index++]);
14535           RegExpPrototype$1.constructor = RegExpWrapper;
14536           RegExpWrapper.prototype = RegExpPrototype$1;
14537           redefine(global_1, 'RegExp', RegExpWrapper);
14538         }
14539
14540         // https://tc39.github.io/ecma262/#sec-get-regexp-@@species
14541         setSpecies('RegExp');
14542
14543         function define (constructor, factory, prototype) {
14544           constructor.prototype = factory.prototype = prototype;
14545           prototype.constructor = constructor;
14546         }
14547         function extend(parent, definition) {
14548           var prototype = Object.create(parent.prototype);
14549
14550           for (var key in definition) {
14551             prototype[key] = definition[key];
14552           }
14553
14554           return prototype;
14555         }
14556
14557         function Color() {}
14558         var _darker = 0.7;
14559
14560         var _brighter = 1 / _darker;
14561         var reI = "\\s*([+-]?\\d+)\\s*",
14562             reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
14563             reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
14564             reHex = /^#([0-9a-f]{3,8})$/,
14565             reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
14566             reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
14567             reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
14568             reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
14569             reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
14570             reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
14571         var named = {
14572           aliceblue: 0xf0f8ff,
14573           antiquewhite: 0xfaebd7,
14574           aqua: 0x00ffff,
14575           aquamarine: 0x7fffd4,
14576           azure: 0xf0ffff,
14577           beige: 0xf5f5dc,
14578           bisque: 0xffe4c4,
14579           black: 0x000000,
14580           blanchedalmond: 0xffebcd,
14581           blue: 0x0000ff,
14582           blueviolet: 0x8a2be2,
14583           brown: 0xa52a2a,
14584           burlywood: 0xdeb887,
14585           cadetblue: 0x5f9ea0,
14586           chartreuse: 0x7fff00,
14587           chocolate: 0xd2691e,
14588           coral: 0xff7f50,
14589           cornflowerblue: 0x6495ed,
14590           cornsilk: 0xfff8dc,
14591           crimson: 0xdc143c,
14592           cyan: 0x00ffff,
14593           darkblue: 0x00008b,
14594           darkcyan: 0x008b8b,
14595           darkgoldenrod: 0xb8860b,
14596           darkgray: 0xa9a9a9,
14597           darkgreen: 0x006400,
14598           darkgrey: 0xa9a9a9,
14599           darkkhaki: 0xbdb76b,
14600           darkmagenta: 0x8b008b,
14601           darkolivegreen: 0x556b2f,
14602           darkorange: 0xff8c00,
14603           darkorchid: 0x9932cc,
14604           darkred: 0x8b0000,
14605           darksalmon: 0xe9967a,
14606           darkseagreen: 0x8fbc8f,
14607           darkslateblue: 0x483d8b,
14608           darkslategray: 0x2f4f4f,
14609           darkslategrey: 0x2f4f4f,
14610           darkturquoise: 0x00ced1,
14611           darkviolet: 0x9400d3,
14612           deeppink: 0xff1493,
14613           deepskyblue: 0x00bfff,
14614           dimgray: 0x696969,
14615           dimgrey: 0x696969,
14616           dodgerblue: 0x1e90ff,
14617           firebrick: 0xb22222,
14618           floralwhite: 0xfffaf0,
14619           forestgreen: 0x228b22,
14620           fuchsia: 0xff00ff,
14621           gainsboro: 0xdcdcdc,
14622           ghostwhite: 0xf8f8ff,
14623           gold: 0xffd700,
14624           goldenrod: 0xdaa520,
14625           gray: 0x808080,
14626           green: 0x008000,
14627           greenyellow: 0xadff2f,
14628           grey: 0x808080,
14629           honeydew: 0xf0fff0,
14630           hotpink: 0xff69b4,
14631           indianred: 0xcd5c5c,
14632           indigo: 0x4b0082,
14633           ivory: 0xfffff0,
14634           khaki: 0xf0e68c,
14635           lavender: 0xe6e6fa,
14636           lavenderblush: 0xfff0f5,
14637           lawngreen: 0x7cfc00,
14638           lemonchiffon: 0xfffacd,
14639           lightblue: 0xadd8e6,
14640           lightcoral: 0xf08080,
14641           lightcyan: 0xe0ffff,
14642           lightgoldenrodyellow: 0xfafad2,
14643           lightgray: 0xd3d3d3,
14644           lightgreen: 0x90ee90,
14645           lightgrey: 0xd3d3d3,
14646           lightpink: 0xffb6c1,
14647           lightsalmon: 0xffa07a,
14648           lightseagreen: 0x20b2aa,
14649           lightskyblue: 0x87cefa,
14650           lightslategray: 0x778899,
14651           lightslategrey: 0x778899,
14652           lightsteelblue: 0xb0c4de,
14653           lightyellow: 0xffffe0,
14654           lime: 0x00ff00,
14655           limegreen: 0x32cd32,
14656           linen: 0xfaf0e6,
14657           magenta: 0xff00ff,
14658           maroon: 0x800000,
14659           mediumaquamarine: 0x66cdaa,
14660           mediumblue: 0x0000cd,
14661           mediumorchid: 0xba55d3,
14662           mediumpurple: 0x9370db,
14663           mediumseagreen: 0x3cb371,
14664           mediumslateblue: 0x7b68ee,
14665           mediumspringgreen: 0x00fa9a,
14666           mediumturquoise: 0x48d1cc,
14667           mediumvioletred: 0xc71585,
14668           midnightblue: 0x191970,
14669           mintcream: 0xf5fffa,
14670           mistyrose: 0xffe4e1,
14671           moccasin: 0xffe4b5,
14672           navajowhite: 0xffdead,
14673           navy: 0x000080,
14674           oldlace: 0xfdf5e6,
14675           olive: 0x808000,
14676           olivedrab: 0x6b8e23,
14677           orange: 0xffa500,
14678           orangered: 0xff4500,
14679           orchid: 0xda70d6,
14680           palegoldenrod: 0xeee8aa,
14681           palegreen: 0x98fb98,
14682           paleturquoise: 0xafeeee,
14683           palevioletred: 0xdb7093,
14684           papayawhip: 0xffefd5,
14685           peachpuff: 0xffdab9,
14686           peru: 0xcd853f,
14687           pink: 0xffc0cb,
14688           plum: 0xdda0dd,
14689           powderblue: 0xb0e0e6,
14690           purple: 0x800080,
14691           rebeccapurple: 0x663399,
14692           red: 0xff0000,
14693           rosybrown: 0xbc8f8f,
14694           royalblue: 0x4169e1,
14695           saddlebrown: 0x8b4513,
14696           salmon: 0xfa8072,
14697           sandybrown: 0xf4a460,
14698           seagreen: 0x2e8b57,
14699           seashell: 0xfff5ee,
14700           sienna: 0xa0522d,
14701           silver: 0xc0c0c0,
14702           skyblue: 0x87ceeb,
14703           slateblue: 0x6a5acd,
14704           slategray: 0x708090,
14705           slategrey: 0x708090,
14706           snow: 0xfffafa,
14707           springgreen: 0x00ff7f,
14708           steelblue: 0x4682b4,
14709           tan: 0xd2b48c,
14710           teal: 0x008080,
14711           thistle: 0xd8bfd8,
14712           tomato: 0xff6347,
14713           turquoise: 0x40e0d0,
14714           violet: 0xee82ee,
14715           wheat: 0xf5deb3,
14716           white: 0xffffff,
14717           whitesmoke: 0xf5f5f5,
14718           yellow: 0xffff00,
14719           yellowgreen: 0x9acd32
14720         };
14721         define(Color, color, {
14722           copy: function copy(channels) {
14723             return Object.assign(new this.constructor(), this, channels);
14724           },
14725           displayable: function displayable() {
14726             return this.rgb().displayable();
14727           },
14728           hex: color_formatHex,
14729           // Deprecated! Use color.formatHex.
14730           formatHex: color_formatHex,
14731           formatHsl: color_formatHsl,
14732           formatRgb: color_formatRgb,
14733           toString: color_formatRgb
14734         });
14735
14736         function color_formatHex() {
14737           return this.rgb().formatHex();
14738         }
14739
14740         function color_formatHsl() {
14741           return hslConvert(this).formatHsl();
14742         }
14743
14744         function color_formatRgb() {
14745           return this.rgb().formatRgb();
14746         }
14747
14748         function color(format) {
14749           var m, l;
14750           format = (format + "").trim().toLowerCase();
14751           return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
14752           : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
14753           : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
14754           : 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
14755           : null // invalid hex
14756           ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
14757           : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
14758           : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
14759           : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
14760           : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
14761           : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
14762           : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
14763           : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
14764         }
14765
14766         function rgbn(n) {
14767           return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
14768         }
14769
14770         function rgba(r, g, b, a) {
14771           if (a <= 0) r = g = b = NaN;
14772           return new Rgb(r, g, b, a);
14773         }
14774
14775         function rgbConvert(o) {
14776           if (!(o instanceof Color)) o = color(o);
14777           if (!o) return new Rgb();
14778           o = o.rgb();
14779           return new Rgb(o.r, o.g, o.b, o.opacity);
14780         }
14781         function rgb(r, g, b, opacity) {
14782           return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
14783         }
14784         function Rgb(r, g, b, opacity) {
14785           this.r = +r;
14786           this.g = +g;
14787           this.b = +b;
14788           this.opacity = +opacity;
14789         }
14790         define(Rgb, rgb, extend(Color, {
14791           brighter: function brighter(k) {
14792             k = k == null ? _brighter : Math.pow(_brighter, k);
14793             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
14794           },
14795           darker: function darker(k) {
14796             k = k == null ? _darker : Math.pow(_darker, k);
14797             return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
14798           },
14799           rgb: function rgb() {
14800             return this;
14801           },
14802           displayable: function displayable() {
14803             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;
14804           },
14805           hex: rgb_formatHex,
14806           // Deprecated! Use color.formatHex.
14807           formatHex: rgb_formatHex,
14808           formatRgb: rgb_formatRgb,
14809           toString: rgb_formatRgb
14810         }));
14811
14812         function rgb_formatHex() {
14813           return "#" + hex$2(this.r) + hex$2(this.g) + hex$2(this.b);
14814         }
14815
14816         function rgb_formatRgb() {
14817           var a = this.opacity;
14818           a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
14819           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 + ")");
14820         }
14821
14822         function hex$2(value) {
14823           value = Math.max(0, Math.min(255, Math.round(value) || 0));
14824           return (value < 16 ? "0" : "") + value.toString(16);
14825         }
14826
14827         function hsla(h, s, l, a) {
14828           if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
14829           return new Hsl(h, s, l, a);
14830         }
14831
14832         function hslConvert(o) {
14833           if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
14834           if (!(o instanceof Color)) o = color(o);
14835           if (!o) return new Hsl();
14836           if (o instanceof Hsl) return o;
14837           o = o.rgb();
14838           var r = o.r / 255,
14839               g = o.g / 255,
14840               b = o.b / 255,
14841               min = Math.min(r, g, b),
14842               max = Math.max(r, g, b),
14843               h = NaN,
14844               s = max - min,
14845               l = (max + min) / 2;
14846
14847           if (s) {
14848             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;
14849             s /= l < 0.5 ? max + min : 2 - max - min;
14850             h *= 60;
14851           } else {
14852             s = l > 0 && l < 1 ? 0 : h;
14853           }
14854
14855           return new Hsl(h, s, l, o.opacity);
14856         }
14857         function hsl(h, s, l, opacity) {
14858           return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
14859         }
14860
14861         function Hsl(h, s, l, opacity) {
14862           this.h = +h;
14863           this.s = +s;
14864           this.l = +l;
14865           this.opacity = +opacity;
14866         }
14867
14868         define(Hsl, hsl, extend(Color, {
14869           brighter: function brighter(k) {
14870             k = k == null ? _brighter : Math.pow(_brighter, k);
14871             return new Hsl(this.h, this.s, this.l * k, this.opacity);
14872           },
14873           darker: function darker(k) {
14874             k = k == null ? _darker : Math.pow(_darker, k);
14875             return new Hsl(this.h, this.s, this.l * k, this.opacity);
14876           },
14877           rgb: function rgb() {
14878             var h = this.h % 360 + (this.h < 0) * 360,
14879                 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
14880                 l = this.l,
14881                 m2 = l + (l < 0.5 ? l : 1 - l) * s,
14882                 m1 = 2 * l - m2;
14883             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);
14884           },
14885           displayable: function displayable() {
14886             return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
14887           },
14888           formatHsl: function formatHsl() {
14889             var a = this.opacity;
14890             a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
14891             return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
14892           }
14893         }));
14894         /* From FvD 13.37, CSS Color Module Level 3 */
14895
14896         function hsl2rgb(h, m1, m2) {
14897           return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
14898         }
14899
14900         var constant$2 = (function (x) {
14901           return function () {
14902             return x;
14903           };
14904         });
14905
14906         function linear(a, d) {
14907           return function (t) {
14908             return a + t * d;
14909           };
14910         }
14911
14912         function exponential(a, b, y) {
14913           return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
14914             return Math.pow(a + t * b, y);
14915           };
14916         }
14917         function gamma(y) {
14918           return (y = +y) === 1 ? nogamma : function (a, b) {
14919             return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a);
14920           };
14921         }
14922         function nogamma(a, b) {
14923           var d = b - a;
14924           return d ? linear(a, d) : constant$2(isNaN(a) ? b : a);
14925         }
14926
14927         var d3_interpolateRgb = (function rgbGamma(y) {
14928           var color = gamma(y);
14929
14930           function rgb$1(start, end) {
14931             var r = color((start = rgb(start)).r, (end = rgb(end)).r),
14932                 g = color(start.g, end.g),
14933                 b = color(start.b, end.b),
14934                 opacity = nogamma(start.opacity, end.opacity);
14935             return function (t) {
14936               start.r = r(t);
14937               start.g = g(t);
14938               start.b = b(t);
14939               start.opacity = opacity(t);
14940               return start + "";
14941             };
14942           }
14943
14944           rgb$1.gamma = rgbGamma;
14945           return rgb$1;
14946         })(1);
14947
14948         function numberArray (a, b) {
14949           if (!b) b = [];
14950           var n = a ? Math.min(b.length, a.length) : 0,
14951               c = b.slice(),
14952               i;
14953           return function (t) {
14954             for (i = 0; i < n; ++i) {
14955               c[i] = a[i] * (1 - t) + b[i] * t;
14956             }
14957
14958             return c;
14959           };
14960         }
14961         function isNumberArray(x) {
14962           return ArrayBuffer.isView(x) && !(x instanceof DataView);
14963         }
14964
14965         function genericArray(a, b) {
14966           var nb = b ? b.length : 0,
14967               na = a ? Math.min(nb, a.length) : 0,
14968               x = new Array(na),
14969               c = new Array(nb),
14970               i;
14971
14972           for (i = 0; i < na; ++i) {
14973             x[i] = interpolate(a[i], b[i]);
14974           }
14975
14976           for (; i < nb; ++i) {
14977             c[i] = b[i];
14978           }
14979
14980           return function (t) {
14981             for (i = 0; i < na; ++i) {
14982               c[i] = x[i](t);
14983             }
14984
14985             return c;
14986           };
14987         }
14988
14989         function date (a, b) {
14990           var d = new Date();
14991           return a = +a, b = +b, function (t) {
14992             return d.setTime(a * (1 - t) + b * t), d;
14993           };
14994         }
14995
14996         function d3_interpolateNumber (a, b) {
14997           return a = +a, b = +b, function (t) {
14998             return a * (1 - t) + b * t;
14999           };
15000         }
15001
15002         function object (a, b) {
15003           var i = {},
15004               c = {},
15005               k;
15006           if (a === null || _typeof(a) !== "object") a = {};
15007           if (b === null || _typeof(b) !== "object") b = {};
15008
15009           for (k in b) {
15010             if (k in a) {
15011               i[k] = interpolate(a[k], b[k]);
15012             } else {
15013               c[k] = b[k];
15014             }
15015           }
15016
15017           return function (t) {
15018             for (k in i) {
15019               c[k] = i[k](t);
15020             }
15021
15022             return c;
15023           };
15024         }
15025
15026         var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
15027             reB = new RegExp(reA.source, "g");
15028
15029         function zero(b) {
15030           return function () {
15031             return b;
15032           };
15033         }
15034
15035         function one(b) {
15036           return function (t) {
15037             return b(t) + "";
15038           };
15039         }
15040
15041         function interpolateString (a, b) {
15042           var bi = reA.lastIndex = reB.lastIndex = 0,
15043               // scan index for next number in b
15044           am,
15045               // current match in a
15046           bm,
15047               // current match in b
15048           bs,
15049               // string preceding current number in b, if any
15050           i = -1,
15051               // index in s
15052           s = [],
15053               // string constants and placeholders
15054           q = []; // number interpolators
15055           // Coerce inputs to strings.
15056
15057           a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
15058
15059           while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
15060             if ((bs = bm.index) > bi) {
15061               // a string precedes the next number in b
15062               bs = b.slice(bi, bs);
15063               if (s[i]) s[i] += bs; // coalesce with previous string
15064               else s[++i] = bs;
15065             }
15066
15067             if ((am = am[0]) === (bm = bm[0])) {
15068               // numbers in a & b match
15069               if (s[i]) s[i] += bm; // coalesce with previous string
15070               else s[++i] = bm;
15071             } else {
15072               // interpolate non-matching numbers
15073               s[++i] = null;
15074               q.push({
15075                 i: i,
15076                 x: d3_interpolateNumber(am, bm)
15077               });
15078             }
15079
15080             bi = reB.lastIndex;
15081           } // Add remains of b.
15082
15083
15084           if (bi < b.length) {
15085             bs = b.slice(bi);
15086             if (s[i]) s[i] += bs; // coalesce with previous string
15087             else s[++i] = bs;
15088           } // Special optimization for only a single match.
15089           // Otherwise, interpolate each of the numbers and rejoin the string.
15090
15091
15092           return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
15093             for (var i = 0, o; i < b; ++i) {
15094               s[(o = q[i]).i] = o.x(t);
15095             }
15096
15097             return s.join("");
15098           });
15099         }
15100
15101         function interpolate (a, b) {
15102           var t = _typeof(b),
15103               c;
15104
15105           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);
15106         }
15107
15108         function interpolateRound (a, b) {
15109           return a = +a, b = +b, function (t) {
15110             return Math.round(a * (1 - t) + b * t);
15111           };
15112         }
15113
15114         var degrees$1 = 180 / Math.PI;
15115         var identity$1 = {
15116           translateX: 0,
15117           translateY: 0,
15118           rotate: 0,
15119           skewX: 0,
15120           scaleX: 1,
15121           scaleY: 1
15122         };
15123         function decompose (a, b, c, d, e, f) {
15124           var scaleX, scaleY, skewX;
15125           if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
15126           if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
15127           if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
15128           if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
15129           return {
15130             translateX: e,
15131             translateY: f,
15132             rotate: Math.atan2(b, a) * degrees$1,
15133             skewX: Math.atan(skewX) * degrees$1,
15134             scaleX: scaleX,
15135             scaleY: scaleY
15136           };
15137         }
15138
15139         var svgNode;
15140         /* eslint-disable no-undef */
15141
15142         function parseCss(value) {
15143           var m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
15144           return m.isIdentity ? identity$1 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
15145         }
15146         function parseSvg(value) {
15147           if (value == null) return identity$1;
15148           if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
15149           svgNode.setAttribute("transform", value);
15150           if (!(value = svgNode.transform.baseVal.consolidate())) return identity$1;
15151           value = value.matrix;
15152           return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
15153         }
15154
15155         function interpolateTransform(parse, pxComma, pxParen, degParen) {
15156           function pop(s) {
15157             return s.length ? s.pop() + " " : "";
15158           }
15159
15160           function translate(xa, ya, xb, yb, s, q) {
15161             if (xa !== xb || ya !== yb) {
15162               var i = s.push("translate(", null, pxComma, null, pxParen);
15163               q.push({
15164                 i: i - 4,
15165                 x: d3_interpolateNumber(xa, xb)
15166               }, {
15167                 i: i - 2,
15168                 x: d3_interpolateNumber(ya, yb)
15169               });
15170             } else if (xb || yb) {
15171               s.push("translate(" + xb + pxComma + yb + pxParen);
15172             }
15173           }
15174
15175           function rotate(a, b, s, q) {
15176             if (a !== b) {
15177               if (a - b > 180) b += 360;else if (b - a > 180) a += 360; // shortest path
15178
15179               q.push({
15180                 i: s.push(pop(s) + "rotate(", null, degParen) - 2,
15181                 x: d3_interpolateNumber(a, b)
15182               });
15183             } else if (b) {
15184               s.push(pop(s) + "rotate(" + b + degParen);
15185             }
15186           }
15187
15188           function skewX(a, b, s, q) {
15189             if (a !== b) {
15190               q.push({
15191                 i: s.push(pop(s) + "skewX(", null, degParen) - 2,
15192                 x: d3_interpolateNumber(a, b)
15193               });
15194             } else if (b) {
15195               s.push(pop(s) + "skewX(" + b + degParen);
15196             }
15197           }
15198
15199           function scale(xa, ya, xb, yb, s, q) {
15200             if (xa !== xb || ya !== yb) {
15201               var i = s.push(pop(s) + "scale(", null, ",", null, ")");
15202               q.push({
15203                 i: i - 4,
15204                 x: d3_interpolateNumber(xa, xb)
15205               }, {
15206                 i: i - 2,
15207                 x: d3_interpolateNumber(ya, yb)
15208               });
15209             } else if (xb !== 1 || yb !== 1) {
15210               s.push(pop(s) + "scale(" + xb + "," + yb + ")");
15211             }
15212           }
15213
15214           return function (a, b) {
15215             var s = [],
15216                 // string constants and placeholders
15217             q = []; // number interpolators
15218
15219             a = parse(a), b = parse(b);
15220             translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
15221             rotate(a.rotate, b.rotate, s, q);
15222             skewX(a.skewX, b.skewX, s, q);
15223             scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
15224             a = b = null; // gc
15225
15226             return function (t) {
15227               var i = -1,
15228                   n = q.length,
15229                   o;
15230
15231               while (++i < n) {
15232                 s[(o = q[i]).i] = o.x(t);
15233               }
15234
15235               return s.join("");
15236             };
15237           };
15238         }
15239
15240         var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
15241         var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
15242
15243         var epsilon2$1 = 1e-12;
15244
15245         function cosh(x) {
15246           return ((x = Math.exp(x)) + 1 / x) / 2;
15247         }
15248
15249         function sinh(x) {
15250           return ((x = Math.exp(x)) - 1 / x) / 2;
15251         }
15252
15253         function tanh(x) {
15254           return ((x = Math.exp(2 * x)) - 1) / (x + 1);
15255         }
15256
15257         var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
15258           // p0 = [ux0, uy0, w0]
15259           // p1 = [ux1, uy1, w1]
15260           function zoom(p0, p1) {
15261             var ux0 = p0[0],
15262                 uy0 = p0[1],
15263                 w0 = p0[2],
15264                 ux1 = p1[0],
15265                 uy1 = p1[1],
15266                 w1 = p1[2],
15267                 dx = ux1 - ux0,
15268                 dy = uy1 - uy0,
15269                 d2 = dx * dx + dy * dy,
15270                 i,
15271                 S; // Special case for u0 ≅ u1.
15272
15273             if (d2 < epsilon2$1) {
15274               S = Math.log(w1 / w0) / rho;
15275
15276               i = function i(t) {
15277                 return [ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S)];
15278               };
15279             } // General case.
15280             else {
15281                 var d1 = Math.sqrt(d2),
15282                     b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
15283                     b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
15284                     r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
15285                     r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
15286                 S = (r1 - r0) / rho;
15287
15288                 i = function i(t) {
15289                   var s = t * S,
15290                       coshr0 = cosh(r0),
15291                       u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
15292                   return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0)];
15293                 };
15294               }
15295
15296             i.duration = S * 1000 * rho / Math.SQRT2;
15297             return i;
15298           }
15299
15300           zoom.rho = function (_) {
15301             var _1 = Math.max(1e-3, +_),
15302                 _2 = _1 * _1,
15303                 _4 = _2 * _2;
15304
15305             return zoomRho(_1, _2, _4);
15306           };
15307
15308           return zoom;
15309         })(Math.SQRT2, 2, 4);
15310
15311         function d3_quantize (interpolator, n) {
15312           var samples = new Array(n);
15313
15314           for (var i = 0; i < n; ++i) {
15315             samples[i] = interpolator(i / (n - 1));
15316           }
15317
15318           return samples;
15319         }
15320
15321         // `Function.prototype.bind` method
15322         // https://tc39.github.io/ecma262/#sec-function.prototype.bind
15323         _export({ target: 'Function', proto: true }, {
15324           bind: functionBind
15325         });
15326
15327         var frame = 0,
15328             // is an animation frame pending?
15329         timeout = 0,
15330             // is a timeout pending?
15331         interval = 0,
15332             // are any timers active?
15333         pokeDelay = 1000,
15334             // how frequently we check for clock skew
15335         taskHead,
15336             taskTail,
15337             clockLast = 0,
15338             clockNow = 0,
15339             clockSkew = 0,
15340             clock = (typeof performance === "undefined" ? "undefined" : _typeof(performance)) === "object" && performance.now ? performance : Date,
15341             setFrame = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function (f) {
15342           setTimeout(f, 17);
15343         };
15344         function now() {
15345           return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
15346         }
15347
15348         function clearNow() {
15349           clockNow = 0;
15350         }
15351
15352         function Timer() {
15353           this._call = this._time = this._next = null;
15354         }
15355         Timer.prototype = timer.prototype = {
15356           constructor: Timer,
15357           restart: function restart(callback, delay, time) {
15358             if (typeof callback !== "function") throw new TypeError("callback is not a function");
15359             time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
15360
15361             if (!this._next && taskTail !== this) {
15362               if (taskTail) taskTail._next = this;else taskHead = this;
15363               taskTail = this;
15364             }
15365
15366             this._call = callback;
15367             this._time = time;
15368             sleep();
15369           },
15370           stop: function stop() {
15371             if (this._call) {
15372               this._call = null;
15373               this._time = Infinity;
15374               sleep();
15375             }
15376           }
15377         };
15378         function timer(callback, delay, time) {
15379           var t = new Timer();
15380           t.restart(callback, delay, time);
15381           return t;
15382         }
15383         function timerFlush() {
15384           now(); // Get the current time, if not already set.
15385
15386           ++frame; // Pretend we’ve set an alarm, if we haven’t already.
15387
15388           var t = taskHead,
15389               e;
15390
15391           while (t) {
15392             if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
15393             t = t._next;
15394           }
15395
15396           --frame;
15397         }
15398
15399         function wake() {
15400           clockNow = (clockLast = clock.now()) + clockSkew;
15401           frame = timeout = 0;
15402
15403           try {
15404             timerFlush();
15405           } finally {
15406             frame = 0;
15407             nap();
15408             clockNow = 0;
15409           }
15410         }
15411
15412         function poke() {
15413           var now = clock.now(),
15414               delay = now - clockLast;
15415           if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
15416         }
15417
15418         function nap() {
15419           var t0,
15420               t1 = taskHead,
15421               t2,
15422               time = Infinity;
15423
15424           while (t1) {
15425             if (t1._call) {
15426               if (time > t1._time) time = t1._time;
15427               t0 = t1, t1 = t1._next;
15428             } else {
15429               t2 = t1._next, t1._next = null;
15430               t1 = t0 ? t0._next = t2 : taskHead = t2;
15431             }
15432           }
15433
15434           taskTail = t0;
15435           sleep(time);
15436         }
15437
15438         function sleep(time) {
15439           if (frame) return; // Soonest alarm already set, or will be.
15440
15441           if (timeout) timeout = clearTimeout(timeout);
15442           var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
15443
15444           if (delay > 24) {
15445             if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
15446             if (interval) interval = clearInterval(interval);
15447           } else {
15448             if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
15449             frame = 1, setFrame(wake);
15450           }
15451         }
15452
15453         function d3_timeout (callback, delay, time) {
15454           var t = new Timer();
15455           delay = delay == null ? 0 : +delay;
15456           t.restart(function (elapsed) {
15457             t.stop();
15458             callback(elapsed + delay);
15459           }, delay, time);
15460           return t;
15461         }
15462
15463         var emptyOn = dispatch("start", "end", "cancel", "interrupt");
15464         var emptyTween = [];
15465         var CREATED = 0;
15466         var SCHEDULED = 1;
15467         var STARTING = 2;
15468         var STARTED = 3;
15469         var RUNNING = 4;
15470         var ENDING = 5;
15471         var ENDED = 6;
15472         function schedule (node, name, id, index, group, timing) {
15473           var schedules = node.__transition;
15474           if (!schedules) node.__transition = {};else if (id in schedules) return;
15475           create(node, id, {
15476             name: name,
15477             index: index,
15478             // For context during callback.
15479             group: group,
15480             // For context during callback.
15481             on: emptyOn,
15482             tween: emptyTween,
15483             time: timing.time,
15484             delay: timing.delay,
15485             duration: timing.duration,
15486             ease: timing.ease,
15487             timer: null,
15488             state: CREATED
15489           });
15490         }
15491         function init(node, id) {
15492           var schedule = get$4(node, id);
15493           if (schedule.state > CREATED) throw new Error("too late; already scheduled");
15494           return schedule;
15495         }
15496         function set$4(node, id) {
15497           var schedule = get$4(node, id);
15498           if (schedule.state > STARTED) throw new Error("too late; already running");
15499           return schedule;
15500         }
15501         function get$4(node, id) {
15502           var schedule = node.__transition;
15503           if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
15504           return schedule;
15505         }
15506
15507         function create(node, id, self) {
15508           var schedules = node.__transition,
15509               tween; // Initialize the self timer when the transition is created.
15510           // Note the actual delay is not known until the first callback!
15511
15512           schedules[id] = self;
15513           self.timer = timer(schedule, 0, self.time);
15514
15515           function schedule(elapsed) {
15516             self.state = SCHEDULED;
15517             self.timer.restart(start, self.delay, self.time); // If the elapsed delay is less than our first sleep, start immediately.
15518
15519             if (self.delay <= elapsed) start(elapsed - self.delay);
15520           }
15521
15522           function start(elapsed) {
15523             var i, j, n, o; // If the state is not SCHEDULED, then we previously errored on start.
15524
15525             if (self.state !== SCHEDULED) return stop();
15526
15527             for (i in schedules) {
15528               o = schedules[i];
15529               if (o.name !== self.name) continue; // While this element already has a starting transition during this frame,
15530               // defer starting an interrupting transition until that transition has a
15531               // chance to tick (and possibly end); see d3/d3-transition#54!
15532
15533               if (o.state === STARTED) return d3_timeout(start); // Interrupt the active transition, if any.
15534
15535               if (o.state === RUNNING) {
15536                 o.state = ENDED;
15537                 o.timer.stop();
15538                 o.on.call("interrupt", node, node.__data__, o.index, o.group);
15539                 delete schedules[i];
15540               } // Cancel any pre-empted transitions.
15541               else if (+i < id) {
15542                   o.state = ENDED;
15543                   o.timer.stop();
15544                   o.on.call("cancel", node, node.__data__, o.index, o.group);
15545                   delete schedules[i];
15546                 }
15547             } // Defer the first tick to end of the current frame; see d3/d3#1576.
15548             // Note the transition may be canceled after start and before the first tick!
15549             // Note this must be scheduled before the start event; see d3/d3-transition#16!
15550             // Assuming this is successful, subsequent callbacks go straight to tick.
15551
15552
15553             d3_timeout(function () {
15554               if (self.state === STARTED) {
15555                 self.state = RUNNING;
15556                 self.timer.restart(tick, self.delay, self.time);
15557                 tick(elapsed);
15558               }
15559             }); // Dispatch the start event.
15560             // Note this must be done before the tween are initialized.
15561
15562             self.state = STARTING;
15563             self.on.call("start", node, node.__data__, self.index, self.group);
15564             if (self.state !== STARTING) return; // interrupted
15565
15566             self.state = STARTED; // Initialize the tween, deleting null tween.
15567
15568             tween = new Array(n = self.tween.length);
15569
15570             for (i = 0, j = -1; i < n; ++i) {
15571               if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
15572                 tween[++j] = o;
15573               }
15574             }
15575
15576             tween.length = j + 1;
15577           }
15578
15579           function tick(elapsed) {
15580             var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
15581                 i = -1,
15582                 n = tween.length;
15583
15584             while (++i < n) {
15585               tween[i].call(node, t);
15586             } // Dispatch the end event.
15587
15588
15589             if (self.state === ENDING) {
15590               self.on.call("end", node, node.__data__, self.index, self.group);
15591               stop();
15592             }
15593           }
15594
15595           function stop() {
15596             self.state = ENDED;
15597             self.timer.stop();
15598             delete schedules[id];
15599
15600             for (var i in schedules) {
15601               return;
15602             } // eslint-disable-line no-unused-vars
15603
15604
15605             delete node.__transition;
15606           }
15607         }
15608
15609         function interrupt (node, name) {
15610           var schedules = node.__transition,
15611               schedule,
15612               active,
15613               empty = true,
15614               i;
15615           if (!schedules) return;
15616           name = name == null ? null : name + "";
15617
15618           for (i in schedules) {
15619             if ((schedule = schedules[i]).name !== name) {
15620               empty = false;
15621               continue;
15622             }
15623
15624             active = schedule.state > STARTING && schedule.state < ENDING;
15625             schedule.state = ENDED;
15626             schedule.timer.stop();
15627             schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
15628             delete schedules[i];
15629           }
15630
15631           if (empty) delete node.__transition;
15632         }
15633
15634         function selection_interrupt (name) {
15635           return this.each(function () {
15636             interrupt(this, name);
15637           });
15638         }
15639
15640         function tweenRemove(id, name) {
15641           var tween0, tween1;
15642           return function () {
15643             var schedule = set$4(this, id),
15644                 tween = schedule.tween; // If this node shared tween with the previous node,
15645             // just assign the updated shared tween and we’re done!
15646             // Otherwise, copy-on-write.
15647
15648             if (tween !== tween0) {
15649               tween1 = tween0 = tween;
15650
15651               for (var i = 0, n = tween1.length; i < n; ++i) {
15652                 if (tween1[i].name === name) {
15653                   tween1 = tween1.slice();
15654                   tween1.splice(i, 1);
15655                   break;
15656                 }
15657               }
15658             }
15659
15660             schedule.tween = tween1;
15661           };
15662         }
15663
15664         function tweenFunction(id, name, value) {
15665           var tween0, tween1;
15666           if (typeof value !== "function") throw new Error();
15667           return function () {
15668             var schedule = set$4(this, id),
15669                 tween = schedule.tween; // If this node shared tween with the previous node,
15670             // just assign the updated shared tween and we’re done!
15671             // Otherwise, copy-on-write.
15672
15673             if (tween !== tween0) {
15674               tween1 = (tween0 = tween).slice();
15675
15676               for (var t = {
15677                 name: name,
15678                 value: value
15679               }, i = 0, n = tween1.length; i < n; ++i) {
15680                 if (tween1[i].name === name) {
15681                   tween1[i] = t;
15682                   break;
15683                 }
15684               }
15685
15686               if (i === n) tween1.push(t);
15687             }
15688
15689             schedule.tween = tween1;
15690           };
15691         }
15692
15693         function transition_tween (name, value) {
15694           var id = this._id;
15695           name += "";
15696
15697           if (arguments.length < 2) {
15698             var tween = get$4(this.node(), id).tween;
15699
15700             for (var i = 0, n = tween.length, t; i < n; ++i) {
15701               if ((t = tween[i]).name === name) {
15702                 return t.value;
15703               }
15704             }
15705
15706             return null;
15707           }
15708
15709           return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
15710         }
15711         function tweenValue(transition, name, value) {
15712           var id = transition._id;
15713           transition.each(function () {
15714             var schedule = set$4(this, id);
15715             (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
15716           });
15717           return function (node) {
15718             return get$4(node, id).value[name];
15719           };
15720         }
15721
15722         function interpolate$1 (a, b) {
15723           var c;
15724           return (typeof b === "number" ? d3_interpolateNumber : b instanceof color ? d3_interpolateRgb : (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString)(a, b);
15725         }
15726
15727         function attrRemove$1(name) {
15728           return function () {
15729             this.removeAttribute(name);
15730           };
15731         }
15732
15733         function attrRemoveNS$1(fullname) {
15734           return function () {
15735             this.removeAttributeNS(fullname.space, fullname.local);
15736           };
15737         }
15738
15739         function attrConstant$1(name, interpolate, value1) {
15740           var string00,
15741               string1 = value1 + "",
15742               interpolate0;
15743           return function () {
15744             var string0 = this.getAttribute(name);
15745             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15746           };
15747         }
15748
15749         function attrConstantNS$1(fullname, interpolate, value1) {
15750           var string00,
15751               string1 = value1 + "",
15752               interpolate0;
15753           return function () {
15754             var string0 = this.getAttributeNS(fullname.space, fullname.local);
15755             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
15756           };
15757         }
15758
15759         function attrFunction$1(name, interpolate, value) {
15760           var string00, string10, interpolate0;
15761           return function () {
15762             var string0,
15763                 value1 = value(this),
15764                 string1;
15765             if (value1 == null) return void this.removeAttribute(name);
15766             string0 = this.getAttribute(name);
15767             string1 = value1 + "";
15768             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
15769           };
15770         }
15771
15772         function attrFunctionNS$1(fullname, interpolate, value) {
15773           var string00, string10, interpolate0;
15774           return function () {
15775             var string0,
15776                 value1 = value(this),
15777                 string1;
15778             if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
15779             string0 = this.getAttributeNS(fullname.space, fullname.local);
15780             string1 = value1 + "";
15781             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
15782           };
15783         }
15784
15785         function transition_attr (name, value) {
15786           var fullname = namespace(name),
15787               i = fullname === "transform" ? interpolateTransformSvg : interpolate$1;
15788           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));
15789         }
15790
15791         function attrInterpolate(name, i) {
15792           return function (t) {
15793             this.setAttribute(name, i.call(this, t));
15794           };
15795         }
15796
15797         function attrInterpolateNS(fullname, i) {
15798           return function (t) {
15799             this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
15800           };
15801         }
15802
15803         function attrTweenNS(fullname, value) {
15804           var t0, i0;
15805
15806           function tween() {
15807             var i = value.apply(this, arguments);
15808             if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
15809             return t0;
15810           }
15811
15812           tween._value = value;
15813           return tween;
15814         }
15815
15816         function attrTween(name, value) {
15817           var t0, i0;
15818
15819           function tween() {
15820             var i = value.apply(this, arguments);
15821             if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
15822             return t0;
15823           }
15824
15825           tween._value = value;
15826           return tween;
15827         }
15828
15829         function transition_attrTween (name, value) {
15830           var key = "attr." + name;
15831           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
15832           if (value == null) return this.tween(key, null);
15833           if (typeof value !== "function") throw new Error();
15834           var fullname = namespace(name);
15835           return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
15836         }
15837
15838         function delayFunction(id, value) {
15839           return function () {
15840             init(this, id).delay = +value.apply(this, arguments);
15841           };
15842         }
15843
15844         function delayConstant(id, value) {
15845           return value = +value, function () {
15846             init(this, id).delay = value;
15847           };
15848         }
15849
15850         function transition_delay (value) {
15851           var id = this._id;
15852           return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get$4(this.node(), id).delay;
15853         }
15854
15855         function durationFunction(id, value) {
15856           return function () {
15857             set$4(this, id).duration = +value.apply(this, arguments);
15858           };
15859         }
15860
15861         function durationConstant(id, value) {
15862           return value = +value, function () {
15863             set$4(this, id).duration = value;
15864           };
15865         }
15866
15867         function transition_duration (value) {
15868           var id = this._id;
15869           return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get$4(this.node(), id).duration;
15870         }
15871
15872         function easeConstant(id, value) {
15873           if (typeof value !== "function") throw new Error();
15874           return function () {
15875             set$4(this, id).ease = value;
15876           };
15877         }
15878
15879         function transition_ease (value) {
15880           var id = this._id;
15881           return arguments.length ? this.each(easeConstant(id, value)) : get$4(this.node(), id).ease;
15882         }
15883
15884         function easeVarying(id, value) {
15885           return function () {
15886             var v = value.apply(this, arguments);
15887             if (typeof v !== "function") throw new Error();
15888             set$4(this, id).ease = v;
15889           };
15890         }
15891
15892         function transition_easeVarying (value) {
15893           if (typeof value !== "function") throw new Error();
15894           return this.each(easeVarying(this._id, value));
15895         }
15896
15897         function transition_filter (match) {
15898           if (typeof match !== "function") match = matcher(match);
15899
15900           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
15901             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
15902               if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
15903                 subgroup.push(node);
15904               }
15905             }
15906           }
15907
15908           return new Transition(subgroups, this._parents, this._name, this._id);
15909         }
15910
15911         function transition_merge (transition) {
15912           if (transition._id !== this._id) throw new Error();
15913
15914           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) {
15915             for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
15916               if (node = group0[i] || group1[i]) {
15917                 merge[i] = node;
15918               }
15919             }
15920           }
15921
15922           for (; j < m0; ++j) {
15923             merges[j] = groups0[j];
15924           }
15925
15926           return new Transition(merges, this._parents, this._name, this._id);
15927         }
15928
15929         function start(name) {
15930           return (name + "").trim().split(/^|\s+/).every(function (t) {
15931             var i = t.indexOf(".");
15932             if (i >= 0) t = t.slice(0, i);
15933             return !t || t === "start";
15934           });
15935         }
15936
15937         function onFunction(id, name, listener) {
15938           var on0,
15939               on1,
15940               sit = start(name) ? init : set$4;
15941           return function () {
15942             var schedule = sit(this, id),
15943                 on = schedule.on; // If this node shared a dispatch with the previous node,
15944             // just assign the updated shared dispatch and we’re done!
15945             // Otherwise, copy-on-write.
15946
15947             if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
15948             schedule.on = on1;
15949           };
15950         }
15951
15952         function transition_on (name, listener) {
15953           var id = this._id;
15954           return arguments.length < 2 ? get$4(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
15955         }
15956
15957         function removeFunction(id) {
15958           return function () {
15959             var parent = this.parentNode;
15960
15961             for (var i in this.__transition) {
15962               if (+i !== id) return;
15963             }
15964
15965             if (parent) parent.removeChild(this);
15966           };
15967         }
15968
15969         function transition_remove () {
15970           return this.on("end.remove", removeFunction(this._id));
15971         }
15972
15973         function transition_select (select) {
15974           var name = this._name,
15975               id = this._id;
15976           if (typeof select !== "function") select = selector(select);
15977
15978           for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
15979             for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
15980               if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
15981                 if ("__data__" in node) subnode.__data__ = node.__data__;
15982                 subgroup[i] = subnode;
15983                 schedule(subgroup[i], name, id, i, subgroup, get$4(node, id));
15984               }
15985             }
15986           }
15987
15988           return new Transition(subgroups, this._parents, name, id);
15989         }
15990
15991         function transition_selectAll (select) {
15992           var name = this._name,
15993               id = this._id;
15994           if (typeof select !== "function") select = selectorAll(select);
15995
15996           for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
15997             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
15998               if (node = group[i]) {
15999                 for (var children = select.call(node, node.__data__, i, group), child, inherit = get$4(node, id), k = 0, l = children.length; k < l; ++k) {
16000                   if (child = children[k]) {
16001                     schedule(child, name, id, k, children, inherit);
16002                   }
16003                 }
16004
16005                 subgroups.push(children);
16006                 parents.push(node);
16007               }
16008             }
16009           }
16010
16011           return new Transition(subgroups, parents, name, id);
16012         }
16013
16014         var Selection$1 = selection.prototype.constructor;
16015         function transition_selection () {
16016           return new Selection$1(this._groups, this._parents);
16017         }
16018
16019         function styleNull(name, interpolate) {
16020           var string00, string10, interpolate0;
16021           return function () {
16022             var string0 = styleValue(this, name),
16023                 string1 = (this.style.removeProperty(name), styleValue(this, name));
16024             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
16025           };
16026         }
16027
16028         function styleRemove$1(name) {
16029           return function () {
16030             this.style.removeProperty(name);
16031           };
16032         }
16033
16034         function styleConstant$1(name, interpolate, value1) {
16035           var string00,
16036               string1 = value1 + "",
16037               interpolate0;
16038           return function () {
16039             var string0 = styleValue(this, name);
16040             return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16041           };
16042         }
16043
16044         function styleFunction$1(name, interpolate, value) {
16045           var string00, string10, interpolate0;
16046           return function () {
16047             var string0 = styleValue(this, name),
16048                 value1 = value(this),
16049                 string1 = value1 + "";
16050             if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
16051             return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16052           };
16053         }
16054
16055         function styleMaybeRemove(id, name) {
16056           var on0,
16057               on1,
16058               listener0,
16059               key = "style." + name,
16060               event = "end." + key,
16061               remove;
16062           return function () {
16063             var schedule = set$4(this, id),
16064                 on = schedule.on,
16065                 listener = schedule.value[key] == null ? remove || (remove = styleRemove$1(name)) : undefined; // If this node shared a dispatch with the previous node,
16066             // just assign the updated shared dispatch and we’re done!
16067             // Otherwise, copy-on-write.
16068
16069             if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
16070             schedule.on = on1;
16071           };
16072         }
16073
16074         function transition_style (name, value, priority) {
16075           var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$1;
16076           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);
16077         }
16078
16079         function styleInterpolate(name, i, priority) {
16080           return function (t) {
16081             this.style.setProperty(name, i.call(this, t), priority);
16082           };
16083         }
16084
16085         function styleTween(name, value, priority) {
16086           var t, i0;
16087
16088           function tween() {
16089             var i = value.apply(this, arguments);
16090             if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
16091             return t;
16092           }
16093
16094           tween._value = value;
16095           return tween;
16096         }
16097
16098         function transition_styleTween (name, value, priority) {
16099           var key = "style." + (name += "");
16100           if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16101           if (value == null) return this.tween(key, null);
16102           if (typeof value !== "function") throw new Error();
16103           return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
16104         }
16105
16106         function textConstant$1(value) {
16107           return function () {
16108             this.textContent = value;
16109           };
16110         }
16111
16112         function textFunction$1(value) {
16113           return function () {
16114             var value1 = value(this);
16115             this.textContent = value1 == null ? "" : value1;
16116           };
16117         }
16118
16119         function transition_text (value) {
16120           return this.tween("text", typeof value === "function" ? textFunction$1(tweenValue(this, "text", value)) : textConstant$1(value == null ? "" : value + ""));
16121         }
16122
16123         function textInterpolate(i) {
16124           return function (t) {
16125             this.textContent = i.call(this, t);
16126           };
16127         }
16128
16129         function textTween(value) {
16130           var t0, i0;
16131
16132           function tween() {
16133             var i = value.apply(this, arguments);
16134             if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
16135             return t0;
16136           }
16137
16138           tween._value = value;
16139           return tween;
16140         }
16141
16142         function transition_textTween (value) {
16143           var key = "text";
16144           if (arguments.length < 1) return (key = this.tween(key)) && key._value;
16145           if (value == null) return this.tween(key, null);
16146           if (typeof value !== "function") throw new Error();
16147           return this.tween(key, textTween(value));
16148         }
16149
16150         function transition_transition () {
16151           var name = this._name,
16152               id0 = this._id,
16153               id1 = newId();
16154
16155           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16156             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16157               if (node = group[i]) {
16158                 var inherit = get$4(node, id0);
16159                 schedule(node, name, id1, i, group, {
16160                   time: inherit.time + inherit.delay + inherit.duration,
16161                   delay: 0,
16162                   duration: inherit.duration,
16163                   ease: inherit.ease
16164                 });
16165               }
16166             }
16167           }
16168
16169           return new Transition(groups, this._parents, name, id1);
16170         }
16171
16172         function transition_end () {
16173           var on0,
16174               on1,
16175               that = this,
16176               id = that._id,
16177               size = that.size();
16178           return new Promise(function (resolve, reject) {
16179             var cancel = {
16180               value: reject
16181             },
16182                 end = {
16183               value: function value() {
16184                 if (--size === 0) resolve();
16185               }
16186             };
16187             that.each(function () {
16188               var schedule = set$4(this, id),
16189                   on = schedule.on; // If this node shared a dispatch with the previous node,
16190               // just assign the updated shared dispatch and we’re done!
16191               // Otherwise, copy-on-write.
16192
16193               if (on !== on0) {
16194                 on1 = (on0 = on).copy();
16195
16196                 on1._.cancel.push(cancel);
16197
16198                 on1._.interrupt.push(cancel);
16199
16200                 on1._.end.push(end);
16201               }
16202
16203               schedule.on = on1;
16204             }); // The selection was empty, resolve end immediately
16205
16206             if (size === 0) resolve();
16207           });
16208         }
16209
16210         var id$1 = 0;
16211         function Transition(groups, parents, name, id) {
16212           this._groups = groups;
16213           this._parents = parents;
16214           this._name = name;
16215           this._id = id;
16216         }
16217         function transition(name) {
16218           return selection().transition(name);
16219         }
16220         function newId() {
16221           return ++id$1;
16222         }
16223         var selection_prototype = selection.prototype;
16224         Transition.prototype = transition.prototype = _defineProperty({
16225           constructor: Transition,
16226           select: transition_select,
16227           selectAll: transition_selectAll,
16228           filter: transition_filter,
16229           merge: transition_merge,
16230           selection: transition_selection,
16231           transition: transition_transition,
16232           call: selection_prototype.call,
16233           nodes: selection_prototype.nodes,
16234           node: selection_prototype.node,
16235           size: selection_prototype.size,
16236           empty: selection_prototype.empty,
16237           each: selection_prototype.each,
16238           on: transition_on,
16239           attr: transition_attr,
16240           attrTween: transition_attrTween,
16241           style: transition_style,
16242           styleTween: transition_styleTween,
16243           text: transition_text,
16244           textTween: transition_textTween,
16245           remove: transition_remove,
16246           tween: transition_tween,
16247           delay: transition_delay,
16248           duration: transition_duration,
16249           ease: transition_ease,
16250           easeVarying: transition_easeVarying,
16251           end: transition_end
16252         }, Symbol.iterator, selection_prototype[Symbol.iterator]);
16253
16254         var linear$1 = function linear(t) {
16255           return +t;
16256         };
16257
16258         function cubicInOut(t) {
16259           return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
16260         }
16261
16262         var defaultTiming = {
16263           time: null,
16264           // Set on use.
16265           delay: 0,
16266           duration: 250,
16267           ease: cubicInOut
16268         };
16269
16270         function inherit(node, id) {
16271           var timing;
16272
16273           while (!(timing = node.__transition) || !(timing = timing[id])) {
16274             if (!(node = node.parentNode)) {
16275               throw new Error("transition ".concat(id, " not found"));
16276             }
16277           }
16278
16279           return timing;
16280         }
16281
16282         function selection_transition (name) {
16283           var id, timing;
16284
16285           if (name instanceof Transition) {
16286             id = name._id, name = name._name;
16287           } else {
16288             id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
16289           }
16290
16291           for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
16292             for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16293               if (node = group[i]) {
16294                 schedule(node, name, id, i, group, timing || inherit(node, id));
16295               }
16296             }
16297           }
16298
16299           return new Transition(groups, this._parents, name, id);
16300         }
16301
16302         selection.prototype.interrupt = selection_interrupt;
16303         selection.prototype.transition = selection_transition;
16304
16305         var constant$3 = (function (x) {
16306           return function () {
16307             return x;
16308           };
16309         });
16310
16311         function ZoomEvent(type, _ref) {
16312           var sourceEvent = _ref.sourceEvent,
16313               target = _ref.target,
16314               transform = _ref.transform,
16315               dispatch = _ref.dispatch;
16316           Object.defineProperties(this, {
16317             type: {
16318               value: type,
16319               enumerable: true,
16320               configurable: true
16321             },
16322             sourceEvent: {
16323               value: sourceEvent,
16324               enumerable: true,
16325               configurable: true
16326             },
16327             target: {
16328               value: target,
16329               enumerable: true,
16330               configurable: true
16331             },
16332             transform: {
16333               value: transform,
16334               enumerable: true,
16335               configurable: true
16336             },
16337             _: {
16338               value: dispatch
16339             }
16340           });
16341         }
16342
16343         function Transform(k, x, y) {
16344           this.k = k;
16345           this.x = x;
16346           this.y = y;
16347         }
16348         Transform.prototype = {
16349           constructor: Transform,
16350           scale: function scale(k) {
16351             return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
16352           },
16353           translate: function translate(x, y) {
16354             return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
16355           },
16356           apply: function apply(point) {
16357             return [point[0] * this.k + this.x, point[1] * this.k + this.y];
16358           },
16359           applyX: function applyX(x) {
16360             return x * this.k + this.x;
16361           },
16362           applyY: function applyY(y) {
16363             return y * this.k + this.y;
16364           },
16365           invert: function invert(location) {
16366             return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
16367           },
16368           invertX: function invertX(x) {
16369             return (x - this.x) / this.k;
16370           },
16371           invertY: function invertY(y) {
16372             return (y - this.y) / this.k;
16373           },
16374           rescaleX: function rescaleX(x) {
16375             return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
16376           },
16377           rescaleY: function rescaleY(y) {
16378             return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
16379           },
16380           toString: function toString() {
16381             return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
16382           }
16383         };
16384         var identity$2 = new Transform(1, 0, 0);
16385
16386         function nopropagation$1(event) {
16387           event.stopImmediatePropagation();
16388         }
16389         function noevent$1 (event) {
16390           event.preventDefault();
16391           event.stopImmediatePropagation();
16392         }
16393
16394         // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
16395
16396         function defaultFilter$1(event) {
16397           return (!event.ctrlKey || event.type === 'wheel') && !event.button;
16398         }
16399
16400         function defaultExtent() {
16401           var e = this;
16402
16403           if (e instanceof SVGElement) {
16404             e = e.ownerSVGElement || e;
16405
16406             if (e.hasAttribute("viewBox")) {
16407               e = e.viewBox.baseVal;
16408               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
16409             }
16410
16411             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
16412           }
16413
16414           return [[0, 0], [e.clientWidth, e.clientHeight]];
16415         }
16416
16417         function defaultTransform() {
16418           return this.__zoom || identity$2;
16419         }
16420
16421         function defaultWheelDelta(event) {
16422           return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
16423         }
16424
16425         function defaultTouchable$1() {
16426           return navigator.maxTouchPoints || "ontouchstart" in this;
16427         }
16428
16429         function defaultConstrain(transform, extent, translateExtent) {
16430           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
16431               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
16432               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
16433               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
16434           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));
16435         }
16436
16437         function d3_zoom () {
16438           var filter = defaultFilter$1,
16439               extent = defaultExtent,
16440               constrain = defaultConstrain,
16441               wheelDelta = defaultWheelDelta,
16442               touchable = defaultTouchable$1,
16443               scaleExtent = [0, Infinity],
16444               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
16445               duration = 250,
16446               interpolate = interpolateZoom,
16447               listeners = dispatch("start", "zoom", "end"),
16448               touchstarting,
16449               touchfirst,
16450               touchending,
16451               touchDelay = 500,
16452               wheelDelay = 150,
16453               clickDistance2 = 0,
16454               tapDistance = 10;
16455
16456           function zoom(selection) {
16457             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)");
16458           }
16459
16460           zoom.transform = function (collection, transform, point, event) {
16461             var selection = collection.selection ? collection.selection() : collection;
16462             selection.property("__zoom", defaultTransform);
16463
16464             if (collection !== selection) {
16465               schedule(collection, transform, point, event);
16466             } else {
16467               selection.interrupt().each(function () {
16468                 gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
16469               });
16470             }
16471           };
16472
16473           zoom.scaleBy = function (selection, k, p, event) {
16474             zoom.scaleTo(selection, function () {
16475               var k0 = this.__zoom.k,
16476                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16477               return k0 * k1;
16478             }, p, event);
16479           };
16480
16481           zoom.scaleTo = function (selection, k, p, event) {
16482             zoom.transform(selection, function () {
16483               var e = extent.apply(this, arguments),
16484                   t0 = this.__zoom,
16485                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p,
16486                   p1 = t0.invert(p0),
16487                   k1 = typeof k === "function" ? k.apply(this, arguments) : k;
16488               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
16489             }, p, event);
16490           };
16491
16492           zoom.translateBy = function (selection, x, y, event) {
16493             zoom.transform(selection, function () {
16494               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);
16495             }, null, event);
16496           };
16497
16498           zoom.translateTo = function (selection, x, y, p, event) {
16499             zoom.transform(selection, function () {
16500               var e = extent.apply(this, arguments),
16501                   t = this.__zoom,
16502                   p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
16503               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);
16504             }, p, event);
16505           };
16506
16507           function scale(transform, k) {
16508             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
16509             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
16510           }
16511
16512           function translate(transform, p0, p1) {
16513             var x = p0[0] - p1[0] * transform.k,
16514                 y = p0[1] - p1[1] * transform.k;
16515             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
16516           }
16517
16518           function centroid(extent) {
16519             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
16520           }
16521
16522           function schedule(transition, transform, point, event) {
16523             transition.on("start.zoom", function () {
16524               gesture(this, arguments).event(event).start();
16525             }).on("interrupt.zoom end.zoom", function () {
16526               gesture(this, arguments).event(event).end();
16527             }).tween("zoom", function () {
16528               var that = this,
16529                   args = arguments,
16530                   g = gesture(that, args).event(event),
16531                   e = extent.apply(that, args),
16532                   p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
16533                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
16534                   a = that.__zoom,
16535                   b = typeof transform === "function" ? transform.apply(that, args) : transform,
16536                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
16537               return function (t) {
16538                 if (t === 1) t = b; // Avoid rounding error on end.
16539                 else {
16540                     var l = i(t),
16541                         k = w / l[2];
16542                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
16543                   }
16544                 g.zoom(null, t);
16545               };
16546             });
16547           }
16548
16549           function gesture(that, args, clean) {
16550             return !clean && that.__zooming || new Gesture(that, args);
16551           }
16552
16553           function Gesture(that, args) {
16554             this.that = that;
16555             this.args = args;
16556             this.active = 0;
16557             this.sourceEvent = null;
16558             this.extent = extent.apply(that, args);
16559             this.taps = 0;
16560           }
16561
16562           Gesture.prototype = {
16563             event: function event(_event) {
16564               if (_event) this.sourceEvent = _event;
16565               return this;
16566             },
16567             start: function start() {
16568               if (++this.active === 1) {
16569                 this.that.__zooming = this;
16570                 this.emit("start");
16571               }
16572
16573               return this;
16574             },
16575             zoom: function zoom(key, transform) {
16576               if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
16577               if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
16578               if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
16579               this.that.__zoom = transform;
16580               this.emit("zoom");
16581               return this;
16582             },
16583             end: function end() {
16584               if (--this.active === 0) {
16585                 delete this.that.__zooming;
16586                 this.emit("end");
16587               }
16588
16589               return this;
16590             },
16591             emit: function emit(type) {
16592               var d = select(this.that).datum();
16593               listeners.call(type, this.that, new ZoomEvent(type, {
16594                 sourceEvent: this.sourceEvent,
16595                 target: zoom,
16596                 type: type,
16597                 transform: this.that.__zoom,
16598                 dispatch: listeners
16599               }), d);
16600             }
16601           };
16602
16603           function wheeled(event) {
16604             for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
16605               args[_key - 1] = arguments[_key];
16606             }
16607
16608             if (!filter.apply(this, arguments)) return;
16609             var g = gesture(this, args).event(event),
16610                 t = this.__zoom,
16611                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
16612                 p = pointer(event); // If the mouse is in the same location as before, reuse it.
16613             // If there were recent wheel events, reset the wheel idle timeout.
16614
16615             if (g.wheel) {
16616               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
16617                 g.mouse[1] = t.invert(g.mouse[0] = p);
16618               }
16619
16620               clearTimeout(g.wheel);
16621             } // If this wheel event won’t trigger a transform change, ignore it.
16622             else if (t.k === k) return; // Otherwise, capture the mouse point and location at the start.
16623               else {
16624                   g.mouse = [p, t.invert(p)];
16625                   interrupt(this);
16626                   g.start();
16627                 }
16628
16629             noevent$1(event);
16630             g.wheel = setTimeout(wheelidled, wheelDelay);
16631             g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
16632
16633             function wheelidled() {
16634               g.wheel = null;
16635               g.end();
16636             }
16637           }
16638
16639           function mousedowned(event) {
16640             for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
16641               args[_key2 - 1] = arguments[_key2];
16642             }
16643
16644             if (touchending || !filter.apply(this, arguments)) return;
16645             var g = gesture(this, args, true).event(event),
16646                 v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
16647                 p = pointer(event, currentTarget),
16648                 currentTarget = event.currentTarget,
16649                 x0 = event.clientX,
16650                 y0 = event.clientY;
16651             dragDisable(event.view);
16652             nopropagation$1(event);
16653             g.mouse = [p, this.__zoom.invert(p)];
16654             interrupt(this);
16655             g.start();
16656
16657             function mousemoved(event) {
16658               noevent$1(event);
16659
16660               if (!g.moved) {
16661                 var dx = event.clientX - x0,
16662                     dy = event.clientY - y0;
16663                 g.moved = dx * dx + dy * dy > clickDistance2;
16664               }
16665
16666               g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
16667             }
16668
16669             function mouseupped(event) {
16670               v.on("mousemove.zoom mouseup.zoom", null);
16671               yesdrag(event.view, g.moved);
16672               noevent$1(event);
16673               g.event(event).end();
16674             }
16675           }
16676
16677           function dblclicked(event) {
16678             for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
16679               args[_key3 - 1] = arguments[_key3];
16680             }
16681
16682             if (!filter.apply(this, arguments)) return;
16683             var t0 = this.__zoom,
16684                 p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
16685                 p1 = t0.invert(p0),
16686                 k1 = t0.k * (event.shiftKey ? 0.5 : 2),
16687                 t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
16688             noevent$1(event);
16689             if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);else select(this).call(zoom.transform, t1, p0, event);
16690           }
16691
16692           function touchstarted(event) {
16693             for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
16694               args[_key4 - 1] = arguments[_key4];
16695             }
16696
16697             if (!filter.apply(this, arguments)) return;
16698             var touches = event.touches,
16699                 n = touches.length,
16700                 g = gesture(this, args, event.changedTouches.length === n).event(event),
16701                 started,
16702                 i,
16703                 t,
16704                 p;
16705             nopropagation$1(event);
16706
16707             for (i = 0; i < n; ++i) {
16708               t = touches[i], p = pointer(t, this);
16709               p = [p, this.__zoom.invert(p), t.identifier];
16710               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;
16711             }
16712
16713             if (touchstarting) touchstarting = clearTimeout(touchstarting);
16714
16715             if (started) {
16716               if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function () {
16717                 touchstarting = null;
16718               }, touchDelay);
16719               interrupt(this);
16720               g.start();
16721             }
16722           }
16723
16724           function touchmoved(event) {
16725             if (!this.__zooming) return;
16726
16727             for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
16728               args[_key5 - 1] = arguments[_key5];
16729             }
16730
16731             var g = gesture(this, args).event(event),
16732                 touches = event.changedTouches,
16733                 n = touches.length,
16734                 i,
16735                 t,
16736                 p,
16737                 l;
16738             noevent$1(event);
16739
16740             for (i = 0; i < n; ++i) {
16741               t = touches[i], p = pointer(t, this);
16742               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;
16743             }
16744
16745             t = g.that.__zoom;
16746
16747             if (g.touch1) {
16748               var p0 = g.touch0[0],
16749                   l0 = g.touch0[1],
16750                   p1 = g.touch1[0],
16751                   l1 = g.touch1[1],
16752                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
16753                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
16754               t = scale(t, Math.sqrt(dp / dl));
16755               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
16756               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
16757             } else if (g.touch0) p = g.touch0[0], l = g.touch0[1];else return;
16758
16759             g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
16760           }
16761
16762           function touchended(event) {
16763             for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
16764               args[_key6 - 1] = arguments[_key6];
16765             }
16766
16767             if (!this.__zooming) return;
16768             var g = gesture(this, args).event(event),
16769                 touches = event.changedTouches,
16770                 n = touches.length,
16771                 i,
16772                 t;
16773             nopropagation$1(event);
16774             if (touchending) clearTimeout(touchending);
16775             touchending = setTimeout(function () {
16776               touchending = null;
16777             }, touchDelay);
16778
16779             for (i = 0; i < n; ++i) {
16780               t = touches[i];
16781               if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
16782             }
16783
16784             if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
16785             if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);else {
16786               g.end(); // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
16787
16788               if (g.taps === 2) {
16789                 t = pointer(t, this);
16790
16791                 if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
16792                   var p = select(this).on("dblclick.zoom");
16793                   if (p) p.apply(this, arguments);
16794                 }
16795               }
16796             }
16797           }
16798
16799           zoom.wheelDelta = function (_) {
16800             return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant$3(+_), zoom) : wheelDelta;
16801           };
16802
16803           zoom.filter = function (_) {
16804             return arguments.length ? (filter = typeof _ === "function" ? _ : constant$3(!!_), zoom) : filter;
16805           };
16806
16807           zoom.touchable = function (_) {
16808             return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$3(!!_), zoom) : touchable;
16809           };
16810
16811           zoom.extent = function (_) {
16812             return arguments.length ? (extent = typeof _ === "function" ? _ : constant$3([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
16813           };
16814
16815           zoom.scaleExtent = function (_) {
16816             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
16817           };
16818
16819           zoom.translateExtent = function (_) {
16820             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]]];
16821           };
16822
16823           zoom.constrain = function (_) {
16824             return arguments.length ? (constrain = _, zoom) : constrain;
16825           };
16826
16827           zoom.duration = function (_) {
16828             return arguments.length ? (duration = +_, zoom) : duration;
16829           };
16830
16831           zoom.interpolate = function (_) {
16832             return arguments.length ? (interpolate = _, zoom) : interpolate;
16833           };
16834
16835           zoom.on = function () {
16836             var value = listeners.on.apply(listeners, arguments);
16837             return value === listeners ? zoom : value;
16838           };
16839
16840           zoom.clickDistance = function (_) {
16841             return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
16842           };
16843
16844           zoom.tapDistance = function (_) {
16845             return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
16846           };
16847
16848           return zoom;
16849         }
16850
16851         /*
16852             Bypasses features of D3's default projection stream pipeline that are unnecessary:
16853             * Antimeridian clipping
16854             * Spherical rotation
16855             * Resampling
16856         */
16857
16858         function geoRawMercator() {
16859           var project = mercatorRaw;
16860           var k = 512 / Math.PI; // scale
16861
16862           var x = 0;
16863           var y = 0; // translate
16864
16865           var clipExtent = [[0, 0], [0, 0]];
16866
16867           function projection(point) {
16868             point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
16869             return [point[0] * k + x, y - point[1] * k];
16870           }
16871
16872           projection.invert = function (point) {
16873             point = project.invert((point[0] - x) / k, (y - point[1]) / k);
16874             return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
16875           };
16876
16877           projection.scale = function (_) {
16878             if (!arguments.length) return k;
16879             k = +_;
16880             return projection;
16881           };
16882
16883           projection.translate = function (_) {
16884             if (!arguments.length) return [x, y];
16885             x = +_[0];
16886             y = +_[1];
16887             return projection;
16888           };
16889
16890           projection.clipExtent = function (_) {
16891             if (!arguments.length) return clipExtent;
16892             clipExtent = _;
16893             return projection;
16894           };
16895
16896           projection.transform = function (obj) {
16897             if (!arguments.length) return identity$2.translate(x, y).scale(k);
16898             x = +obj.x;
16899             y = +obj.y;
16900             k = +obj.k;
16901             return projection;
16902           };
16903
16904           projection.stream = d3_geoTransform({
16905             point: function point(x, y) {
16906               var vec = projection([x, y]);
16907               this.stream.point(vec[0], vec[1]);
16908             }
16909           }).stream;
16910           return projection;
16911         }
16912
16913         function geoOrthoNormalizedDotProduct(a, b, origin) {
16914           if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
16915             return 1; // coincident points, treat as straight and try to remove
16916           }
16917
16918           return geoVecNormalizedDot(a, b, origin);
16919         }
16920
16921         function geoOrthoFilterDotProduct(dotp, epsilon, lowerThreshold, upperThreshold, allowStraightAngles) {
16922           var val = Math.abs(dotp);
16923
16924           if (val < epsilon) {
16925             return 0; // already orthogonal
16926           } else if (allowStraightAngles && Math.abs(val - 1) < epsilon) {
16927             return 0; // straight angle, which is okay in this case
16928           } else if (val < lowerThreshold || val > upperThreshold) {
16929             return dotp; // can be adjusted
16930           } else {
16931             return null; // ignore vertex
16932           }
16933         }
16934
16935         function geoOrthoCalcScore(points, isClosed, epsilon, threshold) {
16936           var score = 0;
16937           var first = isClosed ? 0 : 1;
16938           var last = isClosed ? points.length : points.length - 1;
16939           var coords = points.map(function (p) {
16940             return p.coord;
16941           });
16942           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
16943           var upperThreshold = Math.cos(threshold * Math.PI / 180);
16944
16945           for (var i = first; i < last; i++) {
16946             var a = coords[(i - 1 + coords.length) % coords.length];
16947             var origin = coords[i];
16948             var b = coords[(i + 1) % coords.length];
16949             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold);
16950             if (dotp === null) continue; // ignore vertex
16951
16952             score = score + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
16953           }
16954
16955           return score;
16956         } // returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner
16957
16958         function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) {
16959           var max = -Infinity;
16960           var first = isClosed ? 0 : 1;
16961           var last = isClosed ? coords.length : coords.length - 1;
16962
16963           for (var i = first; i < last; i++) {
16964             var a = coords[(i - 1 + coords.length) % coords.length];
16965             var origin = coords[i];
16966             var b = coords[(i + 1) % coords.length];
16967             var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
16968             var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
16969             if (angle > 45) angle = 90 - angle;
16970             if (angle >= lessThan) continue;
16971             if (angle > max) max = angle;
16972           }
16973
16974           if (max === -Infinity) return null;
16975           return max;
16976         } // similar to geoOrthoCalcScore, but returns quickly if there is something to do
16977
16978         function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) {
16979           var score = null;
16980           var first = isClosed ? 0 : 1;
16981           var last = isClosed ? coords.length : coords.length - 1;
16982           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
16983           var upperThreshold = Math.cos(threshold * Math.PI / 180);
16984
16985           for (var i = first; i < last; i++) {
16986             var a = coords[(i - 1 + coords.length) % coords.length];
16987             var origin = coords[i];
16988             var b = coords[(i + 1) % coords.length];
16989             var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold, allowStraightAngles);
16990             if (dotp === null) continue; // ignore vertex
16991
16992             if (Math.abs(dotp) > 0) return 1; // something to do
16993
16994             score = 0; // already square
16995           }
16996
16997           return score;
16998         }
16999
17000         var onFreeze = internalMetadata.onFreeze;
17001
17002         var nativeFreeze = Object.freeze;
17003         var FAILS_ON_PRIMITIVES$4 = fails(function () { nativeFreeze(1); });
17004
17005         // `Object.freeze` method
17006         // https://tc39.github.io/ecma262/#sec-object.freeze
17007         _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4, sham: !freezing }, {
17008           freeze: function freeze(it) {
17009             return nativeFreeze && isObject(it) ? nativeFreeze(onFreeze(it)) : it;
17010           }
17011         });
17012
17013         // Returns true if a and b have the same elements at the same indices.
17014         function utilArrayIdentical(a, b) {
17015           // an array is always identical to itself
17016           if (a === b) return true;
17017           var i = a.length;
17018           if (i !== b.length) return false;
17019
17020           while (i--) {
17021             if (a[i] !== b[i]) return false;
17022           }
17023
17024           return true;
17025         } // http://2ality.com/2015/01/es6-set-operations.html
17026         // Difference (a \ b): create a set that contains those elements of set a that are not in set b.
17027         // This operation is also sometimes called minus (-).
17028         // var a = [1,2,3];
17029         // var b = [4,3,2];
17030         // utilArrayDifference(a, b)
17031         //   [1]
17032         // utilArrayDifference(b, a)
17033         //   [4]
17034
17035         function utilArrayDifference(a, b) {
17036           var other = new Set(b);
17037           return Array.from(new Set(a)).filter(function (v) {
17038             return !other.has(v);
17039           });
17040         } // Intersection (a ∩ b): create a set that contains those elements of set a that are also in set b.
17041         // var a = [1,2,3];
17042         // var b = [4,3,2];
17043         // utilArrayIntersection(a, b)
17044         //   [2,3]
17045
17046         function utilArrayIntersection(a, b) {
17047           var other = new Set(b);
17048           return Array.from(new Set(a)).filter(function (v) {
17049             return other.has(v);
17050           });
17051         } // Union (a ∪ b): create a set that contains the elements of both set a and set b.
17052         // var a = [1,2,3];
17053         // var b = [4,3,2];
17054         // utilArrayUnion(a, b)
17055         //   [1,2,3,4]
17056
17057         function utilArrayUnion(a, b) {
17058           var result = new Set(a);
17059           b.forEach(function (v) {
17060             result.add(v);
17061           });
17062           return Array.from(result);
17063         } // Returns an Array with all the duplicates removed
17064         // var a = [1,1,2,3,3];
17065         // utilArrayUniq(a)
17066         //   [1,2,3]
17067
17068         function utilArrayUniq(a) {
17069           return Array.from(new Set(a));
17070         } // Splits array into chunks of given chunk size
17071         // var a = [1,2,3,4,5,6,7];
17072         // utilArrayChunk(a, 3);
17073         //   [[1,2,3],[4,5,6],[7]];
17074
17075         function utilArrayChunk(a, chunkSize) {
17076           if (!chunkSize || chunkSize < 0) return [a.slice()];
17077           var result = new Array(Math.ceil(a.length / chunkSize));
17078           return Array.from(result, function (item, i) {
17079             return a.slice(i * chunkSize, i * chunkSize + chunkSize);
17080           });
17081         } // Flattens two level array into a single level
17082         // var a = [[1,2,3],[4,5,6],[7]];
17083         // utilArrayFlatten(a);
17084         //   [1,2,3,4,5,6,7];
17085
17086         function utilArrayFlatten(a) {
17087           return a.reduce(function (acc, val) {
17088             return acc.concat(val);
17089           }, []);
17090         } // Groups the items of the Array according to the given key
17091         // `key` can be passed as a property or as a key function
17092         //
17093         // var pets = [
17094         //     { type: 'Dog', name: 'Spot' },
17095         //     { type: 'Cat', name: 'Tiger' },
17096         //     { type: 'Dog', name: 'Rover' },
17097         //     { type: 'Cat', name: 'Leo' }
17098         // ];
17099         //
17100         // utilArrayGroupBy(pets, 'type')
17101         //   {
17102         //     'Dog': [{type: 'Dog', name: 'Spot'}, {type: 'Dog', name: 'Rover'}],
17103         //     'Cat': [{type: 'Cat', name: 'Tiger'}, {type: 'Cat', name: 'Leo'}]
17104         //   }
17105         //
17106         // utilArrayGroupBy(pets, function(item) { return item.name.length; })
17107         //   {
17108         //     3: [{type: 'Cat', name: 'Leo'}],
17109         //     4: [{type: 'Dog', name: 'Spot'}],
17110         //     5: [{type: 'Cat', name: 'Tiger'}, {type: 'Dog', name: 'Rover'}]
17111         //   }
17112
17113         function utilArrayGroupBy(a, key) {
17114           return a.reduce(function (acc, item) {
17115             var group = typeof key === 'function' ? key(item) : item[key];
17116             (acc[group] = acc[group] || []).push(item);
17117             return acc;
17118           }, {});
17119         } // Returns an Array with all the duplicates removed
17120         // where uniqueness determined by the given key
17121         // `key` can be passed as a property or as a key function
17122         //
17123         // var pets = [
17124         //     { type: 'Dog', name: 'Spot' },
17125         //     { type: 'Cat', name: 'Tiger' },
17126         //     { type: 'Dog', name: 'Rover' },
17127         //     { type: 'Cat', name: 'Leo' }
17128         // ];
17129         //
17130         // utilArrayUniqBy(pets, 'type')
17131         //   [
17132         //     { type: 'Dog', name: 'Spot' },
17133         //     { type: 'Cat', name: 'Tiger' }
17134         //   ]
17135         //
17136         // utilArrayUniqBy(pets, function(item) { return item.name.length; })
17137         //   [
17138         //     { type: 'Dog', name: 'Spot' },
17139         //     { type: 'Cat', name: 'Tiger' },
17140         //     { type: 'Cat', name: 'Leo' }
17141         //   }
17142
17143         function utilArrayUniqBy(a, key) {
17144           var seen = new Set();
17145           return a.reduce(function (acc, item) {
17146             var val = typeof key === 'function' ? key(item) : item[key];
17147
17148             if (val && !seen.has(val)) {
17149               seen.add(val);
17150               acc.push(item);
17151             }
17152
17153             return acc;
17154           }, []);
17155         }
17156
17157         // @@match logic
17158         fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
17159           return [
17160             // `String.prototype.match` method
17161             // https://tc39.github.io/ecma262/#sec-string.prototype.match
17162             function match(regexp) {
17163               var O = requireObjectCoercible(this);
17164               var matcher = regexp == undefined ? undefined : regexp[MATCH];
17165               return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
17166             },
17167             // `RegExp.prototype[@@match]` method
17168             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@match
17169             function (regexp) {
17170               var res = maybeCallNative(nativeMatch, regexp, this);
17171               if (res.done) return res.value;
17172
17173               var rx = anObject(regexp);
17174               var S = String(this);
17175
17176               if (!rx.global) return regexpExecAbstract(rx, S);
17177
17178               var fullUnicode = rx.unicode;
17179               rx.lastIndex = 0;
17180               var A = [];
17181               var n = 0;
17182               var result;
17183               while ((result = regexpExecAbstract(rx, S)) !== null) {
17184                 var matchStr = String(result[0]);
17185                 A[n] = matchStr;
17186                 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
17187                 n++;
17188               }
17189               return n === 0 ? null : A;
17190             }
17191           ];
17192         });
17193
17194         var remove$1 = removeDiacritics;
17195         var replacementList = [{
17196           base: ' ',
17197           chars: "\xA0"
17198         }, {
17199           base: '0',
17200           chars: "\u07C0"
17201         }, {
17202           base: 'A',
17203           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"
17204         }, {
17205           base: 'AA',
17206           chars: "\uA732"
17207         }, {
17208           base: 'AE',
17209           chars: "\xC6\u01FC\u01E2"
17210         }, {
17211           base: 'AO',
17212           chars: "\uA734"
17213         }, {
17214           base: 'AU',
17215           chars: "\uA736"
17216         }, {
17217           base: 'AV',
17218           chars: "\uA738\uA73A"
17219         }, {
17220           base: 'AY',
17221           chars: "\uA73C"
17222         }, {
17223           base: 'B',
17224           chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"
17225         }, {
17226           base: 'C',
17227           chars: "\u24B8\uFF23\uA73E\u1E08\u0106C\u0108\u010A\u010C\xC7\u0187\u023B"
17228         }, {
17229           base: 'D',
17230           chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"
17231         }, {
17232           base: 'Dh',
17233           chars: "\xD0"
17234         }, {
17235           base: 'DZ',
17236           chars: "\u01F1\u01C4"
17237         }, {
17238           base: 'Dz',
17239           chars: "\u01F2\u01C5"
17240         }, {
17241           base: 'E',
17242           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"
17243         }, {
17244           base: 'F',
17245           chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"
17246         }, {
17247           base: 'G',
17248           chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"
17249         }, {
17250           base: 'H',
17251           chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
17252         }, {
17253           base: 'I',
17254           chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
17255         }, {
17256           base: 'J',
17257           chars: "\u24BF\uFF2A\u0134\u0248\u0237"
17258         }, {
17259           base: 'K',
17260           chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
17261         }, {
17262           base: 'L',
17263           chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
17264         }, {
17265           base: 'LJ',
17266           chars: "\u01C7"
17267         }, {
17268           base: 'Lj',
17269           chars: "\u01C8"
17270         }, {
17271           base: 'M',
17272           chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"
17273         }, {
17274           base: 'N',
17275           chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"
17276         }, {
17277           base: 'NJ',
17278           chars: "\u01CA"
17279         }, {
17280           base: 'Nj',
17281           chars: "\u01CB"
17282         }, {
17283           base: 'O',
17284           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"
17285         }, {
17286           base: 'OE',
17287           chars: "\u0152"
17288         }, {
17289           base: 'OI',
17290           chars: "\u01A2"
17291         }, {
17292           base: 'OO',
17293           chars: "\uA74E"
17294         }, {
17295           base: 'OU',
17296           chars: "\u0222"
17297         }, {
17298           base: 'P',
17299           chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
17300         }, {
17301           base: 'Q',
17302           chars: "\u24C6\uFF31\uA756\uA758\u024A"
17303         }, {
17304           base: 'R',
17305           chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
17306         }, {
17307           base: 'S',
17308           chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
17309         }, {
17310           base: 'T',
17311           chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
17312         }, {
17313           base: 'Th',
17314           chars: "\xDE"
17315         }, {
17316           base: 'TZ',
17317           chars: "\uA728"
17318         }, {
17319           base: 'U',
17320           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"
17321         }, {
17322           base: 'V',
17323           chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
17324         }, {
17325           base: 'VY',
17326           chars: "\uA760"
17327         }, {
17328           base: 'W',
17329           chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
17330         }, {
17331           base: 'X',
17332           chars: "\u24CD\uFF38\u1E8A\u1E8C"
17333         }, {
17334           base: 'Y',
17335           chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
17336         }, {
17337           base: 'Z',
17338           chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
17339         }, {
17340           base: 'a',
17341           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"
17342         }, {
17343           base: 'aa',
17344           chars: "\uA733"
17345         }, {
17346           base: 'ae',
17347           chars: "\xE6\u01FD\u01E3"
17348         }, {
17349           base: 'ao',
17350           chars: "\uA735"
17351         }, {
17352           base: 'au',
17353           chars: "\uA737"
17354         }, {
17355           base: 'av',
17356           chars: "\uA739\uA73B"
17357         }, {
17358           base: 'ay',
17359           chars: "\uA73D"
17360         }, {
17361           base: 'b',
17362           chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"
17363         }, {
17364           base: 'c',
17365           chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\xE7\u1E09\u0188\u023C\uA73F\u2184"
17366         }, {
17367           base: 'd',
17368           chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"
17369         }, {
17370           base: 'dh',
17371           chars: "\xF0"
17372         }, {
17373           base: 'dz',
17374           chars: "\u01F3\u01C6"
17375         }, {
17376           base: 'e',
17377           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"
17378         }, {
17379           base: 'f',
17380           chars: "\u24D5\uFF46\u1E1F\u0192"
17381         }, {
17382           base: 'ff',
17383           chars: "\uFB00"
17384         }, {
17385           base: 'fi',
17386           chars: "\uFB01"
17387         }, {
17388           base: 'fl',
17389           chars: "\uFB02"
17390         }, {
17391           base: 'ffi',
17392           chars: "\uFB03"
17393         }, {
17394           base: 'ffl',
17395           chars: "\uFB04"
17396         }, {
17397           base: 'g',
17398           chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"
17399         }, {
17400           base: 'h',
17401           chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
17402         }, {
17403           base: 'hv',
17404           chars: "\u0195"
17405         }, {
17406           base: 'i',
17407           chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
17408         }, {
17409           base: 'j',
17410           chars: "\u24D9\uFF4A\u0135\u01F0\u0249"
17411         }, {
17412           base: 'k',
17413           chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
17414         }, {
17415           base: 'l',
17416           chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"
17417         }, {
17418           base: 'lj',
17419           chars: "\u01C9"
17420         }, {
17421           base: 'm',
17422           chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
17423         }, {
17424           base: 'n',
17425           chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"
17426         }, {
17427           base: 'nj',
17428           chars: "\u01CC"
17429         }, {
17430           base: 'o',
17431           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"
17432         }, {
17433           base: 'oe',
17434           chars: "\u0153"
17435         }, {
17436           base: 'oi',
17437           chars: "\u01A3"
17438         }, {
17439           base: 'oo',
17440           chars: "\uA74F"
17441         }, {
17442           base: 'ou',
17443           chars: "\u0223"
17444         }, {
17445           base: 'p',
17446           chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"
17447         }, {
17448           base: 'q',
17449           chars: "\u24E0\uFF51\u024B\uA757\uA759"
17450         }, {
17451           base: 'r',
17452           chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
17453         }, {
17454           base: 's',
17455           chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"
17456         }, {
17457           base: 'ss',
17458           chars: "\xDF"
17459         }, {
17460           base: 't',
17461           chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
17462         }, {
17463           base: 'th',
17464           chars: "\xFE"
17465         }, {
17466           base: 'tz',
17467           chars: "\uA729"
17468         }, {
17469           base: 'u',
17470           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"
17471         }, {
17472           base: 'v',
17473           chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
17474         }, {
17475           base: 'vy',
17476           chars: "\uA761"
17477         }, {
17478           base: 'w',
17479           chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
17480         }, {
17481           base: 'x',
17482           chars: "\u24E7\uFF58\u1E8B\u1E8D"
17483         }, {
17484           base: 'y',
17485           chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
17486         }, {
17487           base: 'z',
17488           chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
17489         }];
17490         var diacriticsMap = {};
17491
17492         for (var i = 0; i < replacementList.length; i += 1) {
17493           var chars = replacementList[i].chars;
17494
17495           for (var j$1 = 0; j$1 < chars.length; j$1 += 1) {
17496             diacriticsMap[chars[j$1]] = replacementList[i].base;
17497           }
17498         }
17499
17500         function removeDiacritics(str) {
17501           return str.replace(/[^\u0000-\u007e]/g, function (c) {
17502             return diacriticsMap[c] || c;
17503           });
17504         }
17505
17506         var replacementList_1 = replacementList;
17507         var diacriticsMap_1 = diacriticsMap;
17508         var diacritics = {
17509           remove: remove$1,
17510           replacementList: replacementList_1,
17511           diacriticsMap: diacriticsMap_1
17512         };
17513
17514         var isArabic_1 = createCommonjsModule(function (module, exports) {
17515
17516           Object.defineProperty(exports, "__esModule", {
17517             value: true
17518           });
17519           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
17520           ];
17521
17522           function isArabic(_char) {
17523             if (_char.length > 1) {
17524               // allow the newer chars?
17525               throw new Error('isArabic works on only one-character strings');
17526             }
17527
17528             var code = _char.charCodeAt(0);
17529
17530             for (var i = 0; i < arabicBlocks.length; i++) {
17531               var block = arabicBlocks[i];
17532
17533               if (code >= block[0] && code <= block[1]) {
17534                 return true;
17535               }
17536             }
17537
17538             return false;
17539           }
17540
17541           exports.isArabic = isArabic;
17542
17543           function isMath(_char2) {
17544             if (_char2.length > 2) {
17545               // allow the newer chars?
17546               throw new Error('isMath works on only one-character strings');
17547             }
17548
17549             var code = _char2.charCodeAt(0);
17550
17551             return code >= 0x660 && code <= 0x66C || code >= 0x6F0 && code <= 0x6F9;
17552           }
17553
17554           exports.isMath = isMath;
17555         });
17556
17557         var unicodeArabic = createCommonjsModule(function (module, exports) {
17558
17559           Object.defineProperty(exports, "__esModule", {
17560             value: true
17561           });
17562           var arabicReference = {
17563             "alef": {
17564               "normal": ["\u0627"],
17565               "madda_above": {
17566                 "normal": ["\u0627\u0653", "\u0622"],
17567                 "isolated": "\uFE81",
17568                 "final": "\uFE82"
17569               },
17570               "hamza_above": {
17571                 "normal": ["\u0627\u0654", "\u0623"],
17572                 "isolated": "\uFE83",
17573                 "final": "\uFE84"
17574               },
17575               "hamza_below": {
17576                 "normal": ["\u0627\u0655", "\u0625"],
17577                 "isolated": "\uFE87",
17578                 "final": "\uFE88"
17579               },
17580               "wasla": {
17581                 "normal": "\u0671",
17582                 "isolated": "\uFB50",
17583                 "final": "\uFB51"
17584               },
17585               "wavy_hamza_above": ["\u0672"],
17586               "wavy_hamza_below": ["\u0627\u065F", "\u0673"],
17587               "high_hamza": ["\u0675", "\u0627\u0674"],
17588               "indic_two_above": ["\u0773"],
17589               "indic_three_above": ["\u0774"],
17590               "fathatan": {
17591                 "normal": ["\u0627\u064B"],
17592                 "final": "\uFD3C",
17593                 "isolated": "\uFD3D"
17594               },
17595               "isolated": "\uFE8D",
17596               "final": "\uFE8E"
17597             },
17598             "beh": {
17599               "normal": ["\u0628"],
17600               "dotless": ["\u066E"],
17601               "three_dots_horizontally_below": ["\u0750"],
17602               "dot_below_three_dots_above": ["\u0751"],
17603               "three_dots_pointing_upwards_below": ["\u0752"],
17604               "three_dots_pointing_upwards_below_two_dots_above": ["\u0753"],
17605               "two_dots_below_dot_above": ["\u0754"],
17606               "inverted_small_v_below": ["\u0755"],
17607               "small_v": ["\u0756"],
17608               "small_v_below": ["\u08A0"],
17609               "hamza_above": ["\u08A1"],
17610               "small_meem_above": ["\u08B6"],
17611               "isolated": "\uFE8F",
17612               "final": "\uFE90",
17613               "initial": "\uFE91",
17614               "medial": "\uFE92"
17615             },
17616             "teh marbuta": {
17617               "normal": ["\u0629"],
17618               "isolated": "\uFE93",
17619               "final": "\uFE94"
17620             },
17621             "teh": {
17622               "normal": ["\u062A"],
17623               "ring": ["\u067C"],
17624               "three_dots_above_downwards": ["\u067D"],
17625               "small_teh_above": ["\u08B8"],
17626               "isolated": "\uFE95",
17627               "final": "\uFE96",
17628               "initial": "\uFE97",
17629               "medial": "\uFE98"
17630             },
17631             "theh": {
17632               "normal": ["\u062B"],
17633               "isolated": "\uFE99",
17634               "final": "\uFE9A",
17635               "initial": "\uFE9B",
17636               "medial": "\uFE9C"
17637             },
17638             "jeem": {
17639               "normal": ["\u062C"],
17640               "two_dots_above": ["\u08A2"],
17641               "isolated": "\uFE9D",
17642               "final": "\uFE9E",
17643               "initial": "\uFE9F",
17644               "medial": "\uFEA0"
17645             },
17646             "hah": {
17647               "normal": ["\u062D"],
17648               "hamza_above": ["\u0681"],
17649               "two_dots_vertical_above": ["\u0682"],
17650               "three_dots_above": ["\u0685"],
17651               "two_dots_above": ["\u0757"],
17652               "three_dots_pointing_upwards_below": ["\u0758"],
17653               "small_tah_below": ["\u076E"],
17654               "small_tah_two_dots": ["\u076F"],
17655               "small_tah_above": ["\u0772"],
17656               "indic_four_below": ["\u077C"],
17657               "isolated": "\uFEA1",
17658               "final": "\uFEA2",
17659               "initial": "\uFEA3",
17660               "medial": "\uFEA4"
17661             },
17662             "khah": {
17663               "normal": ["\u062E"],
17664               "isolated": "\uFEA5",
17665               "final": "\uFEA6",
17666               "initial": "\uFEA7",
17667               "medial": "\uFEA8"
17668             },
17669             "dal": {
17670               "normal": ["\u062F"],
17671               "ring": ["\u0689"],
17672               "dot_below": ["\u068A"],
17673               "dot_below_small_tah": ["\u068B"],
17674               "three_dots_above_downwards": ["\u068F"],
17675               "four_dots_above": ["\u0690"],
17676               "inverted_v": ["\u06EE"],
17677               "two_dots_vertically_below_small_tah": ["\u0759"],
17678               "inverted_small_v_below": ["\u075A"],
17679               "three_dots_below": ["\u08AE"],
17680               "isolated": "\uFEA9",
17681               "final": "\uFEAA"
17682             },
17683             "thal": {
17684               "normal": ["\u0630"],
17685               "isolated": "\uFEAB",
17686               "final": "\uFEAC"
17687             },
17688             "reh": {
17689               "normal": ["\u0631"],
17690               "small_v": ["\u0692"],
17691               "ring": ["\u0693"],
17692               "dot_below": ["\u0694"],
17693               "small_v_below": ["\u0695"],
17694               "dot_below_dot_above": ["\u0696"],
17695               "two_dots_above": ["\u0697"],
17696               "four_dots_above": ["\u0699"],
17697               "inverted_v": ["\u06EF"],
17698               "stroke": ["\u075B"],
17699               "two_dots_vertically_above": ["\u076B"],
17700               "hamza_above": ["\u076C"],
17701               "small_tah_two_dots": ["\u0771"],
17702               "loop": ["\u08AA"],
17703               "small_noon_above": ["\u08B9"],
17704               "isolated": "\uFEAD",
17705               "final": "\uFEAE"
17706             },
17707             "zain": {
17708               "normal": ["\u0632"],
17709               "inverted_v_above": ["\u08B2"],
17710               "isolated": "\uFEAF",
17711               "final": "\uFEB0"
17712             },
17713             "seen": {
17714               "normal": ["\u0633"],
17715               "dot_below_dot_above": ["\u069A"],
17716               "three_dots_below": ["\u069B"],
17717               "three_dots_below_three_dots_above": ["\u069C"],
17718               "four_dots_above": ["\u075C"],
17719               "two_dots_vertically_above": ["\u076D"],
17720               "small_tah_two_dots": ["\u0770"],
17721               "indic_four_above": ["\u077D"],
17722               "inverted_v": ["\u077E"],
17723               "isolated": "\uFEB1",
17724               "final": "\uFEB2",
17725               "initial": "\uFEB3",
17726               "medial": "\uFEB4"
17727             },
17728             "sheen": {
17729               "normal": ["\u0634"],
17730               "dot_below": ["\u06FA"],
17731               "isolated": "\uFEB5",
17732               "final": "\uFEB6",
17733               "initial": "\uFEB7",
17734               "medial": "\uFEB8"
17735             },
17736             "sad": {
17737               "normal": ["\u0635"],
17738               "two_dots_below": ["\u069D"],
17739               "three_dots_above": ["\u069E"],
17740               "three_dots_below": ["\u08AF"],
17741               "isolated": "\uFEB9",
17742               "final": "\uFEBA",
17743               "initial": "\uFEBB",
17744               "medial": "\uFEBC"
17745             },
17746             "dad": {
17747               "normal": ["\u0636"],
17748               "dot_below": ["\u06FB"],
17749               "isolated": "\uFEBD",
17750               "final": "\uFEBE",
17751               "initial": "\uFEBF",
17752               "medial": "\uFEC0"
17753             },
17754             "tah": {
17755               "normal": ["\u0637"],
17756               "three_dots_above": ["\u069F"],
17757               "two_dots_above": ["\u08A3"],
17758               "isolated": "\uFEC1",
17759               "final": "\uFEC2",
17760               "initial": "\uFEC3",
17761               "medial": "\uFEC4"
17762             },
17763             "zah": {
17764               "normal": ["\u0638"],
17765               "isolated": "\uFEC5",
17766               "final": "\uFEC6",
17767               "initial": "\uFEC7",
17768               "medial": "\uFEC8"
17769             },
17770             "ain": {
17771               "normal": ["\u0639"],
17772               "three_dots_above": ["\u06A0"],
17773               "two_dots_above": ["\u075D"],
17774               "three_dots_pointing_downwards_above": ["\u075E"],
17775               "two_dots_vertically_above": ["\u075F"],
17776               "three_dots_below": ["\u08B3"],
17777               "isolated": "\uFEC9",
17778               "final": "\uFECA",
17779               "initial": "\uFECB",
17780               "medial": "\uFECC"
17781             },
17782             "ghain": {
17783               "normal": ["\u063A"],
17784               "dot_below": ["\u06FC"],
17785               "isolated": "\uFECD",
17786               "final": "\uFECE",
17787               "initial": "\uFECF",
17788               "medial": "\uFED0"
17789             },
17790             "feh": {
17791               "normal": ["\u0641"],
17792               "dotless": ["\u06A1"],
17793               "dot_moved_below": ["\u06A2"],
17794               "dot_below": ["\u06A3"],
17795               "three_dots_below": ["\u06A5"],
17796               "two_dots_below": ["\u0760"],
17797               "three_dots_pointing_upwards_below": ["\u0761"],
17798               "dot_below_three_dots_above": ["\u08A4"],
17799               "isolated": "\uFED1",
17800               "final": "\uFED2",
17801               "initial": "\uFED3",
17802               "medial": "\uFED4"
17803             },
17804             "qaf": {
17805               "normal": ["\u0642"],
17806               "dotless": ["\u066F"],
17807               "dot_above": ["\u06A7"],
17808               "three_dots_above": ["\u06A8"],
17809               "dot_below": ["\u08A5"],
17810               "isolated": "\uFED5",
17811               "final": "\uFED6",
17812               "initial": "\uFED7",
17813               "medial": "\uFED8"
17814             },
17815             "kaf": {
17816               "normal": ["\u0643"],
17817               "swash": ["\u06AA"],
17818               "ring": ["\u06AB"],
17819               "dot_above": ["\u06AC"],
17820               "three_dots_below": ["\u06AE"],
17821               "two_dots_above": ["\u077F"],
17822               "dot_below": ["\u08B4"],
17823               "isolated": "\uFED9",
17824               "final": "\uFEDA",
17825               "initial": "\uFEDB",
17826               "medial": "\uFEDC"
17827             },
17828             "lam": {
17829               "normal": ["\u0644"],
17830               "small_v": ["\u06B5"],
17831               "dot_above": ["\u06B6"],
17832               "three_dots_above": ["\u06B7"],
17833               "three_dots_below": ["\u06B8"],
17834               "bar": ["\u076A"],
17835               "double_bar": ["\u08A6"],
17836               "isolated": "\uFEDD",
17837               "final": "\uFEDE",
17838               "initial": "\uFEDF",
17839               "medial": "\uFEE0"
17840             },
17841             "meem": {
17842               "normal": ["\u0645"],
17843               "dot_above": ["\u0765"],
17844               "dot_below": ["\u0766"],
17845               "three_dots_above": ["\u08A7"],
17846               "isolated": "\uFEE1",
17847               "final": "\uFEE2",
17848               "initial": "\uFEE3",
17849               "medial": "\uFEE4"
17850             },
17851             "noon": {
17852               "normal": ["\u0646"],
17853               "dot_below": ["\u06B9"],
17854               "ring": ["\u06BC"],
17855               "three_dots_above": ["\u06BD"],
17856               "two_dots_below": ["\u0767"],
17857               "small_tah": ["\u0768"],
17858               "small_v": ["\u0769"],
17859               "isolated": "\uFEE5",
17860               "final": "\uFEE6",
17861               "initial": "\uFEE7",
17862               "medial": "\uFEE8"
17863             },
17864             "heh": {
17865               "normal": ["\u0647"],
17866               "isolated": "\uFEE9",
17867               "final": "\uFEEA",
17868               "initial": "\uFEEB",
17869               "medial": "\uFEEC"
17870             },
17871             "waw": {
17872               "normal": ["\u0648"],
17873               "hamza_above": {
17874                 "normal": ["\u0624", "\u0648\u0654"],
17875                 "isolated": "\uFE85",
17876                 "final": "\uFE86"
17877               },
17878               "high_hamza": ["\u0676", "\u0648\u0674"],
17879               "ring": ["\u06C4"],
17880               "two_dots_above": ["\u06CA"],
17881               "dot_above": ["\u06CF"],
17882               "indic_two_above": ["\u0778"],
17883               "indic_three_above": ["\u0779"],
17884               "dot_within": ["\u08AB"],
17885               "isolated": "\uFEED",
17886               "final": "\uFEEE"
17887             },
17888             "alef_maksura": {
17889               "normal": ["\u0649"],
17890               "hamza_above": ["\u0626", "\u064A\u0654"],
17891               "initial": "\uFBE8",
17892               "medial": "\uFBE9",
17893               "isolated": "\uFEEF",
17894               "final": "\uFEF0"
17895             },
17896             "yeh": {
17897               "normal": ["\u064A"],
17898               "hamza_above": {
17899                 "normal": ["\u0626", "\u0649\u0654"],
17900                 "isolated": "\uFE89",
17901                 "final": "\uFE8A",
17902                 "initial": "\uFE8B",
17903                 "medial": "\uFE8C"
17904               },
17905               "two_dots_below_hamza_above": ["\u08A8"],
17906               "high_hamza": ["\u0678", "\u064A\u0674"],
17907               "tail": ["\u06CD"],
17908               "small_v": ["\u06CE"],
17909               "three_dots_below": ["\u06D1"],
17910               "two_dots_below_dot_above": ["\u08A9"],
17911               "two_dots_below_small_noon_above": ["\u08BA"],
17912               "isolated": "\uFEF1",
17913               "final": "\uFEF2",
17914               "initial": "\uFEF3",
17915               "medial": "\uFEF4"
17916             },
17917             "tteh": {
17918               "normal": ["\u0679"],
17919               "isolated": "\uFB66",
17920               "final": "\uFB67",
17921               "initial": "\uFB68",
17922               "medial": "\uFB69"
17923             },
17924             "tteheh": {
17925               "normal": ["\u067A"],
17926               "isolated": "\uFB5E",
17927               "final": "\uFB5F",
17928               "initial": "\uFB60",
17929               "medial": "\uFB61"
17930             },
17931             "beeh": {
17932               "normal": ["\u067B"],
17933               "isolated": "\uFB52",
17934               "final": "\uFB53",
17935               "initial": "\uFB54",
17936               "medial": "\uFB55"
17937             },
17938             "peh": {
17939               "normal": ["\u067E"],
17940               "small_meem_above": ["\u08B7"],
17941               "isolated": "\uFB56",
17942               "final": "\uFB57",
17943               "initial": "\uFB58",
17944               "medial": "\uFB59"
17945             },
17946             "teheh": {
17947               "normal": ["\u067F"],
17948               "isolated": "\uFB62",
17949               "final": "\uFB63",
17950               "initial": "\uFB64",
17951               "medial": "\uFB65"
17952             },
17953             "beheh": {
17954               "normal": ["\u0680"],
17955               "isolated": "\uFB5A",
17956               "final": "\uFB5B",
17957               "initial": "\uFB5C",
17958               "medial": "\uFB5D"
17959             },
17960             "nyeh": {
17961               "normal": ["\u0683"],
17962               "isolated": "\uFB76",
17963               "final": "\uFB77",
17964               "initial": "\uFB78",
17965               "medial": "\uFB79"
17966             },
17967             "dyeh": {
17968               "normal": ["\u0684"],
17969               "isolated": "\uFB72",
17970               "final": "\uFB73",
17971               "initial": "\uFB74",
17972               "medial": "\uFB75"
17973             },
17974             "tcheh": {
17975               "normal": ["\u0686"],
17976               "dot_above": ["\u06BF"],
17977               "isolated": "\uFB7A",
17978               "final": "\uFB7B",
17979               "initial": "\uFB7C",
17980               "medial": "\uFB7D"
17981             },
17982             "tcheheh": {
17983               "normal": ["\u0687"],
17984               "isolated": "\uFB7E",
17985               "final": "\uFB7F",
17986               "initial": "\uFB80",
17987               "medial": "\uFB81"
17988             },
17989             "ddal": {
17990               "normal": ["\u0688"],
17991               "isolated": "\uFB88",
17992               "final": "\uFB89"
17993             },
17994             "dahal": {
17995               "normal": ["\u068C"],
17996               "isolated": "\uFB84",
17997               "final": "\uFB85"
17998             },
17999             "ddahal": {
18000               "normal": ["\u068D"],
18001               "isolated": "\uFB82",
18002               "final": "\uFB83"
18003             },
18004             "dul": {
18005               "normal": ["\u068F", "\u068E"],
18006               "isolated": "\uFB86",
18007               "final": "\uFB87"
18008             },
18009             "rreh": {
18010               "normal": ["\u0691"],
18011               "isolated": "\uFB8C",
18012               "final": "\uFB8D"
18013             },
18014             "jeh": {
18015               "normal": ["\u0698"],
18016               "isolated": "\uFB8A",
18017               "final": "\uFB8B"
18018             },
18019             "veh": {
18020               "normal": ["\u06A4"],
18021               "isolated": "\uFB6A",
18022               "final": "\uFB6B",
18023               "initial": "\uFB6C",
18024               "medial": "\uFB6D"
18025             },
18026             "peheh": {
18027               "normal": ["\u06A6"],
18028               "isolated": "\uFB6E",
18029               "final": "\uFB6F",
18030               "initial": "\uFB70",
18031               "medial": "\uFB71"
18032             },
18033             "keheh": {
18034               "normal": ["\u06A9"],
18035               "dot_above": ["\u0762"],
18036               "three_dots_above": ["\u0763"],
18037               "three_dots_pointing_upwards_below": ["\u0764"],
18038               "isolated": "\uFB8E",
18039               "final": "\uFB8F",
18040               "initial": "\uFB90",
18041               "medial": "\uFB91"
18042             },
18043             "ng": {
18044               "normal": ["\u06AD"],
18045               "isolated": "\uFBD3",
18046               "final": "\uFBD4",
18047               "initial": "\uFBD5",
18048               "medial": "\uFBD6"
18049             },
18050             "gaf": {
18051               "normal": ["\u06AF"],
18052               "ring": ["\u06B0"],
18053               "two_dots_below": ["\u06B2"],
18054               "three_dots_above": ["\u06B4"],
18055               "inverted_stroke": ["\u08B0"],
18056               "isolated": "\uFB92",
18057               "final": "\uFB93",
18058               "initial": "\uFB94",
18059               "medial": "\uFB95"
18060             },
18061             "ngoeh": {
18062               "normal": ["\u06B1"],
18063               "isolated": "\uFB9A",
18064               "final": "\uFB9B",
18065               "initial": "\uFB9C",
18066               "medial": "\uFB9D"
18067             },
18068             "gueh": {
18069               "normal": ["\u06B3"],
18070               "isolated": "\uFB96",
18071               "final": "\uFB97",
18072               "initial": "\uFB98",
18073               "medial": "\uFB99"
18074             },
18075             "noon ghunna": {
18076               "normal": ["\u06BA"],
18077               "isolated": "\uFB9E",
18078               "final": "\uFB9F"
18079             },
18080             "rnoon": {
18081               "normal": ["\u06BB"],
18082               "isolated": "\uFBA0",
18083               "final": "\uFBA1",
18084               "initial": "\uFBA2",
18085               "medial": "\uFBA3"
18086             },
18087             "heh doachashmee": {
18088               "normal": ["\u06BE"],
18089               "isolated": "\uFBAA",
18090               "final": "\uFBAB",
18091               "initial": "\uFBAC",
18092               "medial": "\uFBAD"
18093             },
18094             "heh goal": {
18095               "normal": ["\u06C1"],
18096               "hamza_above": ["\u06C1\u0654", "\u06C2"],
18097               "isolated": "\uFBA6",
18098               "final": "\uFBA7",
18099               "initial": "\uFBA8",
18100               "medial": "\uFBA9"
18101             },
18102             "teh marbuta goal": {
18103               "normal": ["\u06C3"]
18104             },
18105             "kirghiz oe": {
18106               "normal": ["\u06C5"],
18107               "isolated": "\uFBE0",
18108               "final": "\uFBE1"
18109             },
18110             "oe": {
18111               "normal": ["\u06C6"],
18112               "isolated": "\uFBD9",
18113               "final": "\uFBDA"
18114             },
18115             "u": {
18116               "normal": ["\u06C7"],
18117               "hamza_above": {
18118                 "normal": ["\u0677", "\u06C7\u0674"],
18119                 "isolated": "\uFBDD"
18120               },
18121               "isolated": "\uFBD7",
18122               "final": "\uFBD8"
18123             },
18124             "yu": {
18125               "normal": ["\u06C8"],
18126               "isolated": "\uFBDB",
18127               "final": "\uFBDC"
18128             },
18129             "kirghiz yu": {
18130               "normal": ["\u06C9"],
18131               "isolated": "\uFBE2",
18132               "final": "\uFBE3"
18133             },
18134             "ve": {
18135               "normal": ["\u06CB"],
18136               "isolated": "\uFBDE",
18137               "final": "\uFBDF"
18138             },
18139             "farsi yeh": {
18140               "normal": ["\u06CC"],
18141               "indic_two_above": ["\u0775"],
18142               "indic_three_above": ["\u0776"],
18143               "indic_four_above": ["\u0777"],
18144               "isolated": "\uFBFC",
18145               "final": "\uFBFD",
18146               "initial": "\uFBFE",
18147               "medial": "\uFBFF"
18148             },
18149             "e": {
18150               "normal": ["\u06D0"],
18151               "isolated": "\uFBE4",
18152               "final": "\uFBE5",
18153               "initial": "\uFBE6",
18154               "medial": "\uFBE7"
18155             },
18156             "yeh barree": {
18157               "normal": ["\u06D2"],
18158               "hamza_above": {
18159                 "normal": ["\u06D2\u0654", "\u06D3"],
18160                 "isolated": "\uFBB0",
18161                 "final": "\uFBB1"
18162               },
18163               "indic_two_above": ["\u077A"],
18164               "indic_three_above": ["\u077B"],
18165               "isolated": "\uFBAE",
18166               "final": "\uFBAF"
18167             },
18168             "ae": {
18169               "normal": ["\u06D5"],
18170               "isolated": "\u06D5",
18171               "final": "\uFEEA",
18172               "yeh_above": {
18173                 "normal": ["\u06C0", "\u06D5\u0654"],
18174                 "isolated": "\uFBA4",
18175                 "final": "\uFBA5"
18176               }
18177             },
18178             "rohingya yeh": {
18179               "normal": ["\u08AC"]
18180             },
18181             "low alef": {
18182               "normal": ["\u08AD"]
18183             },
18184             "straight waw": {
18185               "normal": ["\u08B1"]
18186             },
18187             "african feh": {
18188               "normal": ["\u08BB"]
18189             },
18190             "african qaf": {
18191               "normal": ["\u08BC"]
18192             },
18193             "african noon": {
18194               "normal": ["\u08BD"]
18195             }
18196           };
18197           exports["default"] = arabicReference;
18198         });
18199
18200         var unicodeLigatures = createCommonjsModule(function (module, exports) {
18201
18202           Object.defineProperty(exports, "__esModule", {
18203             value: true
18204           });
18205           var ligatureReference = {
18206             "\u0626\u0627": {
18207               "isolated": "\uFBEA",
18208               "final": "\uFBEB"
18209             },
18210             "\u0626\u06D5": {
18211               "isolated": "\uFBEC",
18212               "final": "\uFBED"
18213             },
18214             "\u0626\u0648": {
18215               "isolated": "\uFBEE",
18216               "final": "\uFBEF"
18217             },
18218             "\u0626\u06C7": {
18219               "isolated": "\uFBF0",
18220               "final": "\uFBF1"
18221             },
18222             "\u0626\u06C6": {
18223               "isolated": "\uFBF2",
18224               "final": "\uFBF3"
18225             },
18226             "\u0626\u06C8": {
18227               "isolated": "\uFBF4",
18228               "final": "\uFBF5"
18229             },
18230             "\u0626\u06D0": {
18231               "isolated": "\uFBF6",
18232               "final": "\uFBF7",
18233               "initial": "\uFBF8"
18234             },
18235             "\u0626\u0649": {
18236               "uighur_kirghiz": {
18237                 "isolated": "\uFBF9",
18238                 "final": "\uFBFA",
18239                 "initial": "\uFBFB"
18240               },
18241               "isolated": "\uFC03",
18242               "final": "\uFC68"
18243             },
18244             "\u0626\u062C": {
18245               "isolated": "\uFC00",
18246               "initial": "\uFC97"
18247             },
18248             "\u0626\u062D": {
18249               "isolated": "\uFC01",
18250               "initial": "\uFC98"
18251             },
18252             "\u0626\u0645": {
18253               "isolated": "\uFC02",
18254               "final": "\uFC66",
18255               "initial": "\uFC9A",
18256               "medial": "\uFCDF"
18257             },
18258             "\u0626\u064A": {
18259               "isolated": "\uFC04",
18260               "final": "\uFC69"
18261             },
18262             "\u0628\u062C": {
18263               "isolated": "\uFC05",
18264               "initial": "\uFC9C"
18265             },
18266             "\u0628\u062D": {
18267               "isolated": "\uFC06",
18268               "initial": "\uFC9D"
18269             },
18270             "\u0628\u062E": {
18271               "isolated": "\uFC07",
18272               "initial": "\uFC9E"
18273             },
18274             "\u0628\u0645": {
18275               "isolated": "\uFC08",
18276               "final": "\uFC6C",
18277               "initial": "\uFC9F",
18278               "medial": "\uFCE1"
18279             },
18280             "\u0628\u0649": {
18281               "isolated": "\uFC09",
18282               "final": "\uFC6E"
18283             },
18284             "\u0628\u064A": {
18285               "isolated": "\uFC0A",
18286               "final": "\uFC6F"
18287             },
18288             "\u062A\u062C": {
18289               "isolated": "\uFC0B",
18290               "initial": "\uFCA1"
18291             },
18292             "\u062A\u062D": {
18293               "isolated": "\uFC0C",
18294               "initial": "\uFCA2"
18295             },
18296             "\u062A\u062E": {
18297               "isolated": "\uFC0D",
18298               "initial": "\uFCA3"
18299             },
18300             "\u062A\u0645": {
18301               "isolated": "\uFC0E",
18302               "final": "\uFC72",
18303               "initial": "\uFCA4",
18304               "medial": "\uFCE3"
18305             },
18306             "\u062A\u0649": {
18307               "isolated": "\uFC0F",
18308               "final": "\uFC74"
18309             },
18310             "\u062A\u064A": {
18311               "isolated": "\uFC10",
18312               "final": "\uFC75"
18313             },
18314             "\u062B\u062C": {
18315               "isolated": "\uFC11"
18316             },
18317             "\u062B\u0645": {
18318               "isolated": "\uFC12",
18319               "final": "\uFC78",
18320               "initial": "\uFCA6",
18321               "medial": "\uFCE5"
18322             },
18323             "\u062B\u0649": {
18324               "isolated": "\uFC13",
18325               "final": "\uFC7A"
18326             },
18327             "\u062B\u0648": {
18328               "isolated": "\uFC14"
18329             },
18330             "\u062C\u062D": {
18331               "isolated": "\uFC15",
18332               "initial": "\uFCA7"
18333             },
18334             "\u062C\u0645": {
18335               "isolated": "\uFC16",
18336               "initial": "\uFCA8"
18337             },
18338             "\u062D\u062C": {
18339               "isolated": "\uFC17",
18340               "initial": "\uFCA9"
18341             },
18342             "\u062D\u0645": {
18343               "isolated": "\uFC18",
18344               "initial": "\uFCAA"
18345             },
18346             "\u062E\u062C": {
18347               "isolated": "\uFC19",
18348               "initial": "\uFCAB"
18349             },
18350             "\u062E\u062D": {
18351               "isolated": "\uFC1A"
18352             },
18353             "\u062E\u0645": {
18354               "isolated": "\uFC1B",
18355               "initial": "\uFCAC"
18356             },
18357             "\u0633\u062C": {
18358               "isolated": "\uFC1C",
18359               "initial": "\uFCAD",
18360               "medial": "\uFD34"
18361             },
18362             "\u0633\u062D": {
18363               "isolated": "\uFC1D",
18364               "initial": "\uFCAE",
18365               "medial": "\uFD35"
18366             },
18367             "\u0633\u062E": {
18368               "isolated": "\uFC1E",
18369               "initial": "\uFCAF",
18370               "medial": "\uFD36"
18371             },
18372             "\u0633\u0645": {
18373               "isolated": "\uFC1F",
18374               "initial": "\uFCB0",
18375               "medial": "\uFCE7"
18376             },
18377             "\u0635\u062D": {
18378               "isolated": "\uFC20",
18379               "initial": "\uFCB1"
18380             },
18381             "\u0635\u0645": {
18382               "isolated": "\uFC21",
18383               "initial": "\uFCB3"
18384             },
18385             "\u0636\u062C": {
18386               "isolated": "\uFC22",
18387               "initial": "\uFCB4"
18388             },
18389             "\u0636\u062D": {
18390               "isolated": "\uFC23",
18391               "initial": "\uFCB5"
18392             },
18393             "\u0636\u062E": {
18394               "isolated": "\uFC24",
18395               "initial": "\uFCB6"
18396             },
18397             "\u0636\u0645": {
18398               "isolated": "\uFC25",
18399               "initial": "\uFCB7"
18400             },
18401             "\u0637\u062D": {
18402               "isolated": "\uFC26",
18403               "initial": "\uFCB8"
18404             },
18405             "\u0637\u0645": {
18406               "isolated": "\uFC27",
18407               "initial": "\uFD33",
18408               "medial": "\uFD3A"
18409             },
18410             "\u0638\u0645": {
18411               "isolated": "\uFC28",
18412               "initial": "\uFCB9",
18413               "medial": "\uFD3B"
18414             },
18415             "\u0639\u062C": {
18416               "isolated": "\uFC29",
18417               "initial": "\uFCBA"
18418             },
18419             "\u0639\u0645": {
18420               "isolated": "\uFC2A",
18421               "initial": "\uFCBB"
18422             },
18423             "\u063A\u062C": {
18424               "isolated": "\uFC2B",
18425               "initial": "\uFCBC"
18426             },
18427             "\u063A\u0645": {
18428               "isolated": "\uFC2C",
18429               "initial": "\uFCBD"
18430             },
18431             "\u0641\u062C": {
18432               "isolated": "\uFC2D",
18433               "initial": "\uFCBE"
18434             },
18435             "\u0641\u062D": {
18436               "isolated": "\uFC2E",
18437               "initial": "\uFCBF"
18438             },
18439             "\u0641\u062E": {
18440               "isolated": "\uFC2F",
18441               "initial": "\uFCC0"
18442             },
18443             "\u0641\u0645": {
18444               "isolated": "\uFC30",
18445               "initial": "\uFCC1"
18446             },
18447             "\u0641\u0649": {
18448               "isolated": "\uFC31",
18449               "final": "\uFC7C"
18450             },
18451             "\u0641\u064A": {
18452               "isolated": "\uFC32",
18453               "final": "\uFC7D"
18454             },
18455             "\u0642\u062D": {
18456               "isolated": "\uFC33",
18457               "initial": "\uFCC2"
18458             },
18459             "\u0642\u0645": {
18460               "isolated": "\uFC34",
18461               "initial": "\uFCC3"
18462             },
18463             "\u0642\u0649": {
18464               "isolated": "\uFC35",
18465               "final": "\uFC7E"
18466             },
18467             "\u0642\u064A": {
18468               "isolated": "\uFC36",
18469               "final": "\uFC7F"
18470             },
18471             "\u0643\u0627": {
18472               "isolated": "\uFC37",
18473               "final": "\uFC80"
18474             },
18475             "\u0643\u062C": {
18476               "isolated": "\uFC38",
18477               "initial": "\uFCC4"
18478             },
18479             "\u0643\u062D": {
18480               "isolated": "\uFC39",
18481               "initial": "\uFCC5"
18482             },
18483             "\u0643\u062E": {
18484               "isolated": "\uFC3A",
18485               "initial": "\uFCC6"
18486             },
18487             "\u0643\u0644": {
18488               "isolated": "\uFC3B",
18489               "final": "\uFC81",
18490               "initial": "\uFCC7",
18491               "medial": "\uFCEB"
18492             },
18493             "\u0643\u0645": {
18494               "isolated": "\uFC3C",
18495               "final": "\uFC82",
18496               "initial": "\uFCC8",
18497               "medial": "\uFCEC"
18498             },
18499             "\u0643\u0649": {
18500               "isolated": "\uFC3D",
18501               "final": "\uFC83"
18502             },
18503             "\u0643\u064A": {
18504               "isolated": "\uFC3E",
18505               "final": "\uFC84"
18506             },
18507             "\u0644\u062C": {
18508               "isolated": "\uFC3F",
18509               "initial": "\uFCC9"
18510             },
18511             "\u0644\u062D": {
18512               "isolated": "\uFC40",
18513               "initial": "\uFCCA"
18514             },
18515             "\u0644\u062E": {
18516               "isolated": "\uFC41",
18517               "initial": "\uFCCB"
18518             },
18519             "\u0644\u0645": {
18520               "isolated": "\uFC42",
18521               "final": "\uFC85",
18522               "initial": "\uFCCC",
18523               "medial": "\uFCED"
18524             },
18525             "\u0644\u0649": {
18526               "isolated": "\uFC43",
18527               "final": "\uFC86"
18528             },
18529             "\u0644\u064A": {
18530               "isolated": "\uFC44",
18531               "final": "\uFC87"
18532             },
18533             "\u0645\u062C": {
18534               "isolated": "\uFC45",
18535               "initial": "\uFCCE"
18536             },
18537             "\u0645\u062D": {
18538               "isolated": "\uFC46",
18539               "initial": "\uFCCF"
18540             },
18541             "\u0645\u062E": {
18542               "isolated": "\uFC47",
18543               "initial": "\uFCD0"
18544             },
18545             "\u0645\u0645": {
18546               "isolated": "\uFC48",
18547               "final": "\uFC89",
18548               "initial": "\uFCD1"
18549             },
18550             "\u0645\u0649": {
18551               "isolated": "\uFC49"
18552             },
18553             "\u0645\u064A": {
18554               "isolated": "\uFC4A"
18555             },
18556             "\u0646\u062C": {
18557               "isolated": "\uFC4B",
18558               "initial": "\uFCD2"
18559             },
18560             "\u0646\u062D": {
18561               "isolated": "\uFC4C",
18562               "initial": "\uFCD3"
18563             },
18564             "\u0646\u062E": {
18565               "isolated": "\uFC4D",
18566               "initial": "\uFCD4"
18567             },
18568             "\u0646\u0645": {
18569               "isolated": "\uFC4E",
18570               "final": "\uFC8C",
18571               "initial": "\uFCD5",
18572               "medial": "\uFCEE"
18573             },
18574             "\u0646\u0649": {
18575               "isolated": "\uFC4F",
18576               "final": "\uFC8E"
18577             },
18578             "\u0646\u064A": {
18579               "isolated": "\uFC50",
18580               "final": "\uFC8F"
18581             },
18582             "\u0647\u062C": {
18583               "isolated": "\uFC51",
18584               "initial": "\uFCD7"
18585             },
18586             "\u0647\u0645": {
18587               "isolated": "\uFC52",
18588               "initial": "\uFCD8"
18589             },
18590             "\u0647\u0649": {
18591               "isolated": "\uFC53"
18592             },
18593             "\u0647\u064A": {
18594               "isolated": "\uFC54"
18595             },
18596             "\u064A\u062C": {
18597               "isolated": "\uFC55",
18598               "initial": "\uFCDA"
18599             },
18600             "\u064A\u062D": {
18601               "isolated": "\uFC56",
18602               "initial": "\uFCDB"
18603             },
18604             "\u064A\u062E": {
18605               "isolated": "\uFC57",
18606               "initial": "\uFCDC"
18607             },
18608             "\u064A\u0645": {
18609               "isolated": "\uFC58",
18610               "final": "\uFC93",
18611               "initial": "\uFCDD",
18612               "medial": "\uFCF0"
18613             },
18614             "\u064A\u0649": {
18615               "isolated": "\uFC59",
18616               "final": "\uFC95"
18617             },
18618             "\u064A\u064A": {
18619               "isolated": "\uFC5A",
18620               "final": "\uFC96"
18621             },
18622             "\u0630\u0670": {
18623               "isolated": "\uFC5B"
18624             },
18625             "\u0631\u0670": {
18626               "isolated": "\uFC5C"
18627             },
18628             "\u0649\u0670": {
18629               "isolated": "\uFC5D",
18630               "final": "\uFC90"
18631             },
18632             "\u064C\u0651": {
18633               "isolated": "\uFC5E"
18634             },
18635             "\u064D\u0651": {
18636               "isolated": "\uFC5F"
18637             },
18638             "\u064E\u0651": {
18639               "isolated": "\uFC60"
18640             },
18641             "\u064F\u0651": {
18642               "isolated": "\uFC61"
18643             },
18644             "\u0650\u0651": {
18645               "isolated": "\uFC62"
18646             },
18647             "\u0651\u0670": {
18648               "isolated": "\uFC63"
18649             },
18650             "\u0626\u0631": {
18651               "final": "\uFC64"
18652             },
18653             "\u0626\u0632": {
18654               "final": "\uFC65"
18655             },
18656             "\u0626\u0646": {
18657               "final": "\uFC67"
18658             },
18659             "\u0628\u0631": {
18660               "final": "\uFC6A"
18661             },
18662             "\u0628\u0632": {
18663               "final": "\uFC6B"
18664             },
18665             "\u0628\u0646": {
18666               "final": "\uFC6D"
18667             },
18668             "\u062A\u0631": {
18669               "final": "\uFC70"
18670             },
18671             "\u062A\u0632": {
18672               "final": "\uFC71"
18673             },
18674             "\u062A\u0646": {
18675               "final": "\uFC73"
18676             },
18677             "\u062B\u0631": {
18678               "final": "\uFC76"
18679             },
18680             "\u062B\u0632": {
18681               "final": "\uFC77"
18682             },
18683             "\u062B\u0646": {
18684               "final": "\uFC79"
18685             },
18686             "\u062B\u064A": {
18687               "final": "\uFC7B"
18688             },
18689             "\u0645\u0627": {
18690               "final": "\uFC88"
18691             },
18692             "\u0646\u0631": {
18693               "final": "\uFC8A"
18694             },
18695             "\u0646\u0632": {
18696               "final": "\uFC8B"
18697             },
18698             "\u0646\u0646": {
18699               "final": "\uFC8D"
18700             },
18701             "\u064A\u0631": {
18702               "final": "\uFC91"
18703             },
18704             "\u064A\u0632": {
18705               "final": "\uFC92"
18706             },
18707             "\u064A\u0646": {
18708               "final": "\uFC94"
18709             },
18710             "\u0626\u062E": {
18711               "initial": "\uFC99"
18712             },
18713             "\u0626\u0647": {
18714               "initial": "\uFC9B",
18715               "medial": "\uFCE0"
18716             },
18717             "\u0628\u0647": {
18718               "initial": "\uFCA0",
18719               "medial": "\uFCE2"
18720             },
18721             "\u062A\u0647": {
18722               "initial": "\uFCA5",
18723               "medial": "\uFCE4"
18724             },
18725             "\u0635\u062E": {
18726               "initial": "\uFCB2"
18727             },
18728             "\u0644\u0647": {
18729               "initial": "\uFCCD"
18730             },
18731             "\u0646\u0647": {
18732               "initial": "\uFCD6",
18733               "medial": "\uFCEF"
18734             },
18735             "\u0647\u0670": {
18736               "initial": "\uFCD9"
18737             },
18738             "\u064A\u0647": {
18739               "initial": "\uFCDE",
18740               "medial": "\uFCF1"
18741             },
18742             "\u062B\u0647": {
18743               "medial": "\uFCE6"
18744             },
18745             "\u0633\u0647": {
18746               "medial": "\uFCE8",
18747               "initial": "\uFD31"
18748             },
18749             "\u0634\u0645": {
18750               "medial": "\uFCE9",
18751               "isolated": "\uFD0C",
18752               "final": "\uFD28",
18753               "initial": "\uFD30"
18754             },
18755             "\u0634\u0647": {
18756               "medial": "\uFCEA",
18757               "initial": "\uFD32"
18758             },
18759             "\u0640\u064E\u0651": {
18760               "medial": "\uFCF2"
18761             },
18762             "\u0640\u064F\u0651": {
18763               "medial": "\uFCF3"
18764             },
18765             "\u0640\u0650\u0651": {
18766               "medial": "\uFCF4"
18767             },
18768             "\u0637\u0649": {
18769               "isolated": "\uFCF5",
18770               "final": "\uFD11"
18771             },
18772             "\u0637\u064A": {
18773               "isolated": "\uFCF6",
18774               "final": "\uFD12"
18775             },
18776             "\u0639\u0649": {
18777               "isolated": "\uFCF7",
18778               "final": "\uFD13"
18779             },
18780             "\u0639\u064A": {
18781               "isolated": "\uFCF8",
18782               "final": "\uFD14"
18783             },
18784             "\u063A\u0649": {
18785               "isolated": "\uFCF9",
18786               "final": "\uFD15"
18787             },
18788             "\u063A\u064A": {
18789               "isolated": "\uFCFA",
18790               "final": "\uFD16"
18791             },
18792             "\u0633\u0649": {
18793               "isolated": "\uFCFB"
18794             },
18795             "\u0633\u064A": {
18796               "isolated": "\uFCFC",
18797               "final": "\uFD18"
18798             },
18799             "\u0634\u0649": {
18800               "isolated": "\uFCFD",
18801               "final": "\uFD19"
18802             },
18803             "\u0634\u064A": {
18804               "isolated": "\uFCFE",
18805               "final": "\uFD1A"
18806             },
18807             "\u062D\u0649": {
18808               "isolated": "\uFCFF",
18809               "final": "\uFD1B"
18810             },
18811             "\u062D\u064A": {
18812               "isolated": "\uFD00",
18813               "final": "\uFD1C"
18814             },
18815             "\u062C\u0649": {
18816               "isolated": "\uFD01",
18817               "final": "\uFD1D"
18818             },
18819             "\u062C\u064A": {
18820               "isolated": "\uFD02",
18821               "final": "\uFD1E"
18822             },
18823             "\u062E\u0649": {
18824               "isolated": "\uFD03",
18825               "final": "\uFD1F"
18826             },
18827             "\u062E\u064A": {
18828               "isolated": "\uFD04",
18829               "final": "\uFD20"
18830             },
18831             "\u0635\u0649": {
18832               "isolated": "\uFD05",
18833               "final": "\uFD21"
18834             },
18835             "\u0635\u064A": {
18836               "isolated": "\uFD06",
18837               "final": "\uFD22"
18838             },
18839             "\u0636\u0649": {
18840               "isolated": "\uFD07",
18841               "final": "\uFD23"
18842             },
18843             "\u0636\u064A": {
18844               "isolated": "\uFD08",
18845               "final": "\uFD24"
18846             },
18847             "\u0634\u062C": {
18848               "isolated": "\uFD09",
18849               "final": "\uFD25",
18850               "initial": "\uFD2D",
18851               "medial": "\uFD37"
18852             },
18853             "\u0634\u062D": {
18854               "isolated": "\uFD0A",
18855               "final": "\uFD26",
18856               "initial": "\uFD2E",
18857               "medial": "\uFD38"
18858             },
18859             "\u0634\u062E": {
18860               "isolated": "\uFD0B",
18861               "final": "\uFD27",
18862               "initial": "\uFD2F",
18863               "medial": "\uFD39"
18864             },
18865             "\u0634\u0631": {
18866               "isolated": "\uFD0D",
18867               "final": "\uFD29"
18868             },
18869             "\u0633\u0631": {
18870               "isolated": "\uFD0E",
18871               "final": "\uFD2A"
18872             },
18873             "\u0635\u0631": {
18874               "isolated": "\uFD0F",
18875               "final": "\uFD2B"
18876             },
18877             "\u0636\u0631": {
18878               "isolated": "\uFD10",
18879               "final": "\uFD2C"
18880             },
18881             "\u0633\u0639": {
18882               "final": "\uFD17"
18883             },
18884             "\u062A\u062C\u0645": {
18885               "initial": "\uFD50"
18886             },
18887             "\u062A\u062D\u062C": {
18888               "final": "\uFD51",
18889               "initial": "\uFD52"
18890             },
18891             "\u062A\u062D\u0645": {
18892               "initial": "\uFD53"
18893             },
18894             "\u062A\u062E\u0645": {
18895               "initial": "\uFD54"
18896             },
18897             "\u062A\u0645\u062C": {
18898               "initial": "\uFD55"
18899             },
18900             "\u062A\u0645\u062D": {
18901               "initial": "\uFD56"
18902             },
18903             "\u062A\u0645\u062E": {
18904               "initial": "\uFD57"
18905             },
18906             "\u062C\u0645\u062D": {
18907               "final": "\uFD58",
18908               "initial": "\uFD59"
18909             },
18910             "\u062D\u0645\u064A": {
18911               "final": "\uFD5A"
18912             },
18913             "\u062D\u0645\u0649": {
18914               "final": "\uFD5B"
18915             },
18916             "\u0633\u062D\u062C": {
18917               "initial": "\uFD5C"
18918             },
18919             "\u0633\u062C\u062D": {
18920               "initial": "\uFD5D"
18921             },
18922             "\u0633\u062C\u0649": {
18923               "final": "\uFD5E"
18924             },
18925             "\u0633\u0645\u062D": {
18926               "final": "\uFD5F",
18927               "initial": "\uFD60"
18928             },
18929             "\u0633\u0645\u062C": {
18930               "initial": "\uFD61"
18931             },
18932             "\u0633\u0645\u0645": {
18933               "final": "\uFD62",
18934               "initial": "\uFD63"
18935             },
18936             "\u0635\u062D\u062D": {
18937               "final": "\uFD64",
18938               "initial": "\uFD65"
18939             },
18940             "\u0635\u0645\u0645": {
18941               "final": "\uFD66",
18942               "initial": "\uFDC5"
18943             },
18944             "\u0634\u062D\u0645": {
18945               "final": "\uFD67",
18946               "initial": "\uFD68"
18947             },
18948             "\u0634\u062C\u064A": {
18949               "final": "\uFD69"
18950             },
18951             "\u0634\u0645\u062E": {
18952               "final": "\uFD6A",
18953               "initial": "\uFD6B"
18954             },
18955             "\u0634\u0645\u0645": {
18956               "final": "\uFD6C",
18957               "initial": "\uFD6D"
18958             },
18959             "\u0636\u062D\u0649": {
18960               "final": "\uFD6E"
18961             },
18962             "\u0636\u062E\u0645": {
18963               "final": "\uFD6F",
18964               "initial": "\uFD70"
18965             },
18966             "\u0636\u0645\u062D": {
18967               "final": "\uFD71"
18968             },
18969             "\u0637\u0645\u062D": {
18970               "initial": "\uFD72"
18971             },
18972             "\u0637\u0645\u0645": {
18973               "initial": "\uFD73"
18974             },
18975             "\u0637\u0645\u064A": {
18976               "final": "\uFD74"
18977             },
18978             "\u0639\u062C\u0645": {
18979               "final": "\uFD75",
18980               "initial": "\uFDC4"
18981             },
18982             "\u0639\u0645\u0645": {
18983               "final": "\uFD76",
18984               "initial": "\uFD77"
18985             },
18986             "\u0639\u0645\u0649": {
18987               "final": "\uFD78"
18988             },
18989             "\u063A\u0645\u0645": {
18990               "final": "\uFD79"
18991             },
18992             "\u063A\u0645\u064A": {
18993               "final": "\uFD7A"
18994             },
18995             "\u063A\u0645\u0649": {
18996               "final": "\uFD7B"
18997             },
18998             "\u0641\u062E\u0645": {
18999               "final": "\uFD7C",
19000               "initial": "\uFD7D"
19001             },
19002             "\u0642\u0645\u062D": {
19003               "final": "\uFD7E",
19004               "initial": "\uFDB4"
19005             },
19006             "\u0642\u0645\u0645": {
19007               "final": "\uFD7F"
19008             },
19009             "\u0644\u062D\u0645": {
19010               "final": "\uFD80",
19011               "initial": "\uFDB5"
19012             },
19013             "\u0644\u062D\u064A": {
19014               "final": "\uFD81"
19015             },
19016             "\u0644\u062D\u0649": {
19017               "final": "\uFD82"
19018             },
19019             "\u0644\u062C\u062C": {
19020               "initial": "\uFD83",
19021               "final": "\uFD84"
19022             },
19023             "\u0644\u062E\u0645": {
19024               "final": "\uFD85",
19025               "initial": "\uFD86"
19026             },
19027             "\u0644\u0645\u062D": {
19028               "final": "\uFD87",
19029               "initial": "\uFD88"
19030             },
19031             "\u0645\u062D\u062C": {
19032               "initial": "\uFD89"
19033             },
19034             "\u0645\u062D\u0645": {
19035               "initial": "\uFD8A"
19036             },
19037             "\u0645\u062D\u064A": {
19038               "final": "\uFD8B"
19039             },
19040             "\u0645\u062C\u062D": {
19041               "initial": "\uFD8C"
19042             },
19043             "\u0645\u062C\u0645": {
19044               "initial": "\uFD8D"
19045             },
19046             "\u0645\u062E\u062C": {
19047               "initial": "\uFD8E"
19048             },
19049             "\u0645\u062E\u0645": {
19050               "initial": "\uFD8F"
19051             },
19052             "\u0645\u062C\u062E": {
19053               "initial": "\uFD92"
19054             },
19055             "\u0647\u0645\u062C": {
19056               "initial": "\uFD93"
19057             },
19058             "\u0647\u0645\u0645": {
19059               "initial": "\uFD94"
19060             },
19061             "\u0646\u062D\u0645": {
19062               "initial": "\uFD95"
19063             },
19064             "\u0646\u062D\u0649": {
19065               "final": "\uFD96"
19066             },
19067             "\u0646\u062C\u0645": {
19068               "final": "\uFD97",
19069               "initial": "\uFD98"
19070             },
19071             "\u0646\u062C\u0649": {
19072               "final": "\uFD99"
19073             },
19074             "\u0646\u0645\u064A": {
19075               "final": "\uFD9A"
19076             },
19077             "\u0646\u0645\u0649": {
19078               "final": "\uFD9B"
19079             },
19080             "\u064A\u0645\u0645": {
19081               "final": "\uFD9C",
19082               "initial": "\uFD9D"
19083             },
19084             "\u0628\u062E\u064A": {
19085               "final": "\uFD9E"
19086             },
19087             "\u062A\u062C\u064A": {
19088               "final": "\uFD9F"
19089             },
19090             "\u062A\u062C\u0649": {
19091               "final": "\uFDA0"
19092             },
19093             "\u062A\u062E\u064A": {
19094               "final": "\uFDA1"
19095             },
19096             "\u062A\u062E\u0649": {
19097               "final": "\uFDA2"
19098             },
19099             "\u062A\u0645\u064A": {
19100               "final": "\uFDA3"
19101             },
19102             "\u062A\u0645\u0649": {
19103               "final": "\uFDA4"
19104             },
19105             "\u062C\u0645\u064A": {
19106               "final": "\uFDA5"
19107             },
19108             "\u062C\u062D\u0649": {
19109               "final": "\uFDA6"
19110             },
19111             "\u062C\u0645\u0649": {
19112               "final": "\uFDA7"
19113             },
19114             "\u0633\u062E\u0649": {
19115               "final": "\uFDA8"
19116             },
19117             "\u0635\u062D\u064A": {
19118               "final": "\uFDA9"
19119             },
19120             "\u0634\u062D\u064A": {
19121               "final": "\uFDAA"
19122             },
19123             "\u0636\u062D\u064A": {
19124               "final": "\uFDAB"
19125             },
19126             "\u0644\u062C\u064A": {
19127               "final": "\uFDAC"
19128             },
19129             "\u0644\u0645\u064A": {
19130               "final": "\uFDAD"
19131             },
19132             "\u064A\u062D\u064A": {
19133               "final": "\uFDAE"
19134             },
19135             "\u064A\u062C\u064A": {
19136               "final": "\uFDAF"
19137             },
19138             "\u064A\u0645\u064A": {
19139               "final": "\uFDB0"
19140             },
19141             "\u0645\u0645\u064A": {
19142               "final": "\uFDB1"
19143             },
19144             "\u0642\u0645\u064A": {
19145               "final": "\uFDB2"
19146             },
19147             "\u0646\u062D\u064A": {
19148               "final": "\uFDB3"
19149             },
19150             "\u0639\u0645\u064A": {
19151               "final": "\uFDB6"
19152             },
19153             "\u0643\u0645\u064A": {
19154               "final": "\uFDB7"
19155             },
19156             "\u0646\u062C\u062D": {
19157               "initial": "\uFDB8",
19158               "final": "\uFDBD"
19159             },
19160             "\u0645\u062E\u064A": {
19161               "final": "\uFDB9"
19162             },
19163             "\u0644\u062C\u0645": {
19164               "initial": "\uFDBA",
19165               "final": "\uFDBC"
19166             },
19167             "\u0643\u0645\u0645": {
19168               "final": "\uFDBB",
19169               "initial": "\uFDC3"
19170             },
19171             "\u062C\u062D\u064A": {
19172               "final": "\uFDBE"
19173             },
19174             "\u062D\u062C\u064A": {
19175               "final": "\uFDBF"
19176             },
19177             "\u0645\u062C\u064A": {
19178               "final": "\uFDC0"
19179             },
19180             "\u0641\u0645\u064A": {
19181               "final": "\uFDC1"
19182             },
19183             "\u0628\u062D\u064A": {
19184               "final": "\uFDC2"
19185             },
19186             "\u0633\u062E\u064A": {
19187               "final": "\uFDC6"
19188             },
19189             "\u0646\u062C\u064A": {
19190               "final": "\uFDC7"
19191             },
19192             "\u0644\u0622": {
19193               "isolated": "\uFEF5",
19194               "final": "\uFEF6"
19195             },
19196             "\u0644\u0623": {
19197               "isolated": "\uFEF7",
19198               "final": "\uFEF8"
19199             },
19200             "\u0644\u0625": {
19201               "isolated": "\uFEF9",
19202               "final": "\uFEFA"
19203             },
19204             "\u0644\u0627": {
19205               "isolated": "\uFEFB",
19206               "final": "\uFEFC"
19207             },
19208             "words": {
19209               "\u0635\u0644\u06D2": "\uFDF0",
19210               "\u0642\u0644\u06D2": "\uFDF1",
19211               "\u0627\u0644\u0644\u0647": "\uFDF2",
19212               "\u0627\u0643\u0628\u0631": "\uFDF3",
19213               "\u0645\u062D\u0645\u062F": "\uFDF4",
19214               "\u0635\u0644\u0639\u0645": "\uFDF5",
19215               "\u0631\u0633\u0648\u0644": "\uFDF6",
19216               "\u0639\u0644\u064A\u0647": "\uFDF7",
19217               "\u0648\u0633\u0644\u0645": "\uFDF8",
19218               "\u0635\u0644\u0649": "\uFDF9",
19219               "\u0635\u0644\u0649\u0627\u0644\u0644\u0647\u0639\u0644\u064A\u0647\u0648\u0633\u0644\u0645": "\uFDFA",
19220               "\u062C\u0644\u062C\u0644\u0627\u0644\u0647": "\uFDFB",
19221               "\u0631\u06CC\u0627\u0644": "\uFDFC"
19222             }
19223           };
19224           exports["default"] = ligatureReference;
19225         });
19226
19227         var reference = createCommonjsModule(function (module, exports) {
19228
19229           Object.defineProperty(exports, "__esModule", {
19230             value: true
19231           });
19232           var letterList = Object.keys(unicodeArabic["default"]);
19233           exports.letterList = letterList;
19234           var ligatureList = Object.keys(unicodeLigatures["default"]);
19235           exports.ligatureList = ligatureList;
19236           var ligatureWordList = Object.keys(unicodeLigatures["default"].words);
19237           exports.ligatureWordList = ligatureWordList;
19238           var lams = "\u0644\u06B5\u06B6\u06B7\u06B8";
19239           exports.lams = lams;
19240           var alefs = "\u0627\u0622\u0623\u0625\u0671\u0672\u0673\u0675\u0773\u0774";
19241           exports.alefs = alefs; // for (var l = 1; l < lams.length; l++) {
19242           //   console.log('-');
19243           //   for (var a = 0; a < alefs.length; a++) {
19244           //     console.log(a + ': ' + lams[l] + alefs[a]);
19245           //   }
19246           // }
19247
19248           var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
19249           exports.tashkeel = tashkeel;
19250
19251           function addToTashkeel(start, finish) {
19252             for (var i = start; i <= finish; i++) {
19253               exports.tashkeel = tashkeel += String.fromCharCode(i);
19254             }
19255           }
19256
19257           addToTashkeel(0x0610, 0x061A);
19258           addToTashkeel(0x064B, 0x065F);
19259           addToTashkeel(0x06D6, 0x06DC);
19260           addToTashkeel(0x06E0, 0x06E4);
19261           addToTashkeel(0x06EA, 0x06ED);
19262           addToTashkeel(0x08D3, 0x08E1);
19263           addToTashkeel(0x08E3, 0x08FF);
19264           addToTashkeel(0xFE70, 0xFE7F);
19265           var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
19266           exports.lineBreakers = lineBreakers;
19267
19268           function addToLineBreakers(start, finish) {
19269             for (var i = start; i <= finish; i++) {
19270               exports.lineBreakers = lineBreakers += String.fromCharCode(i);
19271             }
19272           }
19273
19274           addToLineBreakers(0x0600, 0x061F); // it's OK to include tashkeel in this range as it is ignored
19275
19276           addToLineBreakers(0x0621, 0x0625);
19277           addToLineBreakers(0x062F, 0x0632);
19278           addToLineBreakers(0x0660, 0x066D); // numerals, math
19279
19280           addToLineBreakers(0x0671, 0x0677);
19281           addToLineBreakers(0x0688, 0x0699);
19282           addToLineBreakers(0x06C3, 0x06CB);
19283           addToLineBreakers(0x06D2, 0x06F9);
19284           addToLineBreakers(0x0759, 0x075B);
19285           addToLineBreakers(0x08AA, 0x08AE);
19286           addToLineBreakers(0xFB50, 0xFDFD); // presentation forms look like they could connect, but never do
19287           // Presentation Forms A includes diacritics but they are meant to stand alone
19288
19289           addToLineBreakers(0xFE80, 0xFEFC); // presentation forms look like they could connect, but never do
19290           // numerals, math
19291
19292           addToLineBreakers(0x10E60, 0x10E7F);
19293           addToLineBreakers(0x1EC70, 0x1ECBF);
19294           addToLineBreakers(0x1EE00, 0x1EEFF);
19295         });
19296
19297         var GlyphSplitter_1 = createCommonjsModule(function (module, exports) {
19298
19299           Object.defineProperty(exports, "__esModule", {
19300             value: true
19301           });
19302
19303           function GlyphSplitter(word) {
19304             var letters = [];
19305             var lastLetter = '';
19306             word.split('').forEach(function (letter) {
19307               if (isArabic_1.isArabic(letter)) {
19308                 if (reference.tashkeel.indexOf(letter) > -1) {
19309                   letters[letters.length - 1] += letter;
19310                 } else if (lastLetter.length && (reference.lams.indexOf(lastLetter) === 0 && reference.alefs.indexOf(letter) > -1 || reference.lams.indexOf(lastLetter) > 0 && reference.alefs.indexOf(letter) === 0)) {
19311                   // valid LA forms
19312                   letters[letters.length - 1] += letter;
19313                 } else {
19314                   letters.push(letter);
19315                 }
19316               } else {
19317                 letters.push(letter);
19318               }
19319
19320               if (reference.tashkeel.indexOf(letter) === -1) {
19321                 lastLetter = letter;
19322               }
19323             });
19324             return letters;
19325           }
19326
19327           exports.GlyphSplitter = GlyphSplitter;
19328         });
19329
19330         var BaselineSplitter_1 = createCommonjsModule(function (module, exports) {
19331
19332           Object.defineProperty(exports, "__esModule", {
19333             value: true
19334           });
19335
19336           function BaselineSplitter(word) {
19337             var letters = [];
19338             var lastLetter = '';
19339             word.split('').forEach(function (letter) {
19340               if (isArabic_1.isArabic(letter) && isArabic_1.isArabic(lastLetter)) {
19341                 if (lastLetter.length && reference.tashkeel.indexOf(letter) > -1) {
19342                   letters[letters.length - 1] += letter;
19343                 } else if (reference.lineBreakers.indexOf(lastLetter) > -1) {
19344                   letters.push(letter);
19345                 } else {
19346                   letters[letters.length - 1] += letter;
19347                 }
19348               } else {
19349                 letters.push(letter);
19350               }
19351
19352               if (reference.tashkeel.indexOf(letter) === -1) {
19353                 // don't allow tashkeel to hide line break
19354                 lastLetter = letter;
19355               }
19356             });
19357             return letters;
19358           }
19359
19360           exports.BaselineSplitter = BaselineSplitter;
19361         });
19362
19363         var Normalization = createCommonjsModule(function (module, exports) {
19364
19365           Object.defineProperty(exports, "__esModule", {
19366             value: true
19367           });
19368
19369           function Normal(word, breakPresentationForm) {
19370             // default is to turn initial/isolated/medial/final presentation form to generic
19371             if (typeof breakPresentationForm === 'undefined') {
19372               breakPresentationForm = true;
19373             }
19374
19375             var returnable = '';
19376             word.split('').forEach(function (letter) {
19377               if (!isArabic_1.isArabic(letter)) {
19378                 returnable += letter;
19379                 return;
19380               }
19381
19382               for (var w = 0; w < reference.letterList.length; w++) {
19383                 // ok so we are checking this potential lettertron
19384                 var letterForms = unicodeArabic["default"][reference.letterList[w]];
19385                 var versions = Object.keys(letterForms);
19386
19387                 for (var v = 0; v < versions.length; v++) {
19388                   var localVersion = letterForms[versions[v]];
19389
19390                   if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19391                     // look at this embedded object
19392                     var embeddedForms = Object.keys(localVersion);
19393
19394                     for (var ef = 0; ef < embeddedForms.length; ef++) {
19395                       var form = localVersion[embeddedForms[ef]];
19396
19397                       if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19398                         // match
19399                         // console.log('embedded match');
19400                         if (form === letter) {
19401                           // match exact
19402                           if (breakPresentationForm && localVersion['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(embeddedForms[ef]) > -1) {
19403                             // replace presentation form
19404                             // console.log('keeping normal form of the letter');
19405                             if (_typeof(localVersion['normal']) === 'object') {
19406                               returnable += localVersion['normal'][0];
19407                             } else {
19408                               returnable += localVersion['normal'];
19409                             }
19410
19411                             return;
19412                           } // console.log('keeping this letter');
19413
19414
19415                           returnable += letter;
19416                           return;
19417                         } else if (_typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19418                           // match
19419                           returnable += form[0]; // console.log('added the first letter from the same array');
19420
19421                           return;
19422                         }
19423                       }
19424                     }
19425                   } else if (localVersion === letter) {
19426                     // match exact
19427                     if (breakPresentationForm && letterForms['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(versions[v]) > -1) {
19428                       // replace presentation form
19429                       // console.log('keeping normal form of the letter');
19430                       if (_typeof(letterForms['normal']) === 'object') {
19431                         returnable += letterForms['normal'][0];
19432                       } else {
19433                         returnable += letterForms['normal'];
19434                       }
19435
19436                       return;
19437                     } // console.log('keeping this letter');
19438
19439
19440                     returnable += letter;
19441                     return;
19442                   } else if (_typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19443                     // match
19444                     returnable += localVersion[0]; // console.log('added the first letter from the same array');
19445
19446                     return;
19447                   }
19448                 }
19449               } // try ligatures
19450
19451
19452               for (var v2 = 0; v2 < reference.ligatureList.length; v2++) {
19453                 var normalForm = reference.ligatureList[v2];
19454
19455                 if (normalForm !== 'words') {
19456                   var ligForms = Object.keys(unicodeLigatures["default"][normalForm]);
19457
19458                   for (var f = 0; f < ligForms.length; f++) {
19459                     if (unicodeLigatures["default"][normalForm][ligForms[f]] === letter) {
19460                       returnable += normalForm;
19461                       return;
19462                     }
19463                   }
19464                 }
19465               } // try words ligatures
19466
19467
19468               for (var v3 = 0; v3 < reference.ligatureWordList.length; v3++) {
19469                 var _normalForm = reference.ligatureWordList[v3];
19470
19471                 if (unicodeLigatures["default"].words[_normalForm] === letter) {
19472                   returnable += _normalForm;
19473                   return;
19474                 }
19475               }
19476
19477               returnable += letter; // console.log('kept the letter')
19478             });
19479             return returnable;
19480           }
19481
19482           exports.Normal = Normal;
19483         });
19484
19485         var CharShaper_1 = createCommonjsModule(function (module, exports) {
19486
19487           Object.defineProperty(exports, "__esModule", {
19488             value: true
19489           });
19490
19491           function CharShaper(letter, form) {
19492             if (!isArabic_1.isArabic(letter)) {
19493               // fail not Arabic
19494               throw new Error('Not Arabic');
19495             }
19496
19497             if (letter === "\u0621") {
19498               // hamza alone
19499               return "\u0621";
19500             }
19501
19502             for (var w = 0; w < reference.letterList.length; w++) {
19503               // ok so we are checking this potential lettertron
19504               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19505               var versions = Object.keys(letterForms);
19506
19507               for (var v = 0; v < versions.length; v++) {
19508                 var localVersion = letterForms[versions[v]];
19509
19510                 if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19511                   if (versions.indexOf(form) > -1) {
19512                     return letterForms[form];
19513                   }
19514                 } else if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19515                   // check embedded
19516                   var embeddedVersions = Object.keys(localVersion);
19517
19518                   for (var ev = 0; ev < embeddedVersions.length; ev++) {
19519                     if (localVersion[embeddedVersions[ev]] === letter || _typeof(localVersion[embeddedVersions[ev]]) === 'object' && localVersion[embeddedVersions[ev]].indexOf && localVersion[embeddedVersions[ev]].indexOf(letter) > -1) {
19520                       if (embeddedVersions.indexOf(form) > -1) {
19521                         return localVersion[form];
19522                       }
19523                     }
19524                   }
19525                 }
19526               }
19527             }
19528           }
19529
19530           exports.CharShaper = CharShaper;
19531         });
19532
19533         var WordShaper_1 = createCommonjsModule(function (module, exports) {
19534
19535           Object.defineProperty(exports, "__esModule", {
19536             value: true
19537           });
19538
19539           function WordShaper(word) {
19540             var state = 'initial';
19541             var output = '';
19542
19543             for (var w = 0; w < word.length; w++) {
19544               var nextLetter = ' ';
19545
19546               for (var nxw = w + 1; nxw < word.length; nxw++) {
19547                 if (!isArabic_1.isArabic(word[nxw])) {
19548                   break;
19549                 }
19550
19551                 if (reference.tashkeel.indexOf(word[nxw]) === -1) {
19552                   nextLetter = word[nxw];
19553                   break;
19554                 }
19555               }
19556
19557               if (!isArabic_1.isArabic(word[w]) || isArabic_1.isMath(word[w])) {
19558                 // space or other non-Arabic
19559                 output += word[w];
19560                 state = 'initial';
19561               } else if (reference.tashkeel.indexOf(word[w]) > -1) {
19562                 // tashkeel - add without changing state
19563                 output += word[w];
19564               } else if (nextLetter === ' ' || // last Arabic letter in this word
19565               reference.lineBreakers.indexOf(word[w]) > -1) {
19566                 // the current letter is known to break lines
19567                 output += CharShaper_1.CharShaper(word[w], state === 'initial' ? 'isolated' : 'final');
19568                 state = 'initial';
19569               } else if (reference.lams.indexOf(word[w]) > -1 && reference.alefs.indexOf(nextLetter) > -1) {
19570                 // LA letters - advance an additional letter after this
19571                 output += unicodeLigatures["default"][word[w] + nextLetter][state === 'initial' ? 'isolated' : 'final'];
19572
19573                 while (word[w] !== nextLetter) {
19574                   w++;
19575                 }
19576
19577                 state = 'initial';
19578               } else {
19579                 output += CharShaper_1.CharShaper(word[w], state);
19580                 state = 'medial';
19581               }
19582             }
19583
19584             return output;
19585           }
19586
19587           exports.WordShaper = WordShaper;
19588         });
19589
19590         var ParentLetter_1 = createCommonjsModule(function (module, exports) {
19591
19592           Object.defineProperty(exports, "__esModule", {
19593             value: true
19594           });
19595
19596           function ParentLetter(letter) {
19597             if (!isArabic_1.isArabic(letter)) {
19598               throw new Error('Not an Arabic letter');
19599             }
19600
19601             for (var w = 0; w < reference.letterList.length; w++) {
19602               // ok so we are checking this potential lettertron
19603               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19604               var versions = Object.keys(letterForms);
19605
19606               for (var v = 0; v < versions.length; v++) {
19607                 var localVersion = letterForms[versions[v]];
19608
19609                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19610                   // look at this embedded object
19611                   var embeddedForms = Object.keys(localVersion);
19612
19613                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19614                     var form = localVersion[embeddedForms[ef]];
19615
19616                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19617                       // match
19618                       return localVersion;
19619                     }
19620                   }
19621                 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19622                   // match
19623                   return letterForms;
19624                 }
19625               }
19626
19627               return null;
19628             }
19629           }
19630
19631           exports.ParentLetter = ParentLetter;
19632
19633           function GrandparentLetter(letter) {
19634             if (!isArabic_1.isArabic(letter)) {
19635               throw new Error('Not an Arabic letter');
19636             }
19637
19638             for (var w = 0; w < reference.letterList.length; w++) {
19639               // ok so we are checking this potential lettertron
19640               var letterForms = unicodeArabic["default"][reference.letterList[w]];
19641               var versions = Object.keys(letterForms);
19642
19643               for (var v = 0; v < versions.length; v++) {
19644                 var localVersion = letterForms[versions[v]];
19645
19646                 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
19647                   // look at this embedded object
19648                   var embeddedForms = Object.keys(localVersion);
19649
19650                   for (var ef = 0; ef < embeddedForms.length; ef++) {
19651                     var form = localVersion[embeddedForms[ef]];
19652
19653                     if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
19654                       // match
19655                       return letterForms;
19656                     }
19657                   }
19658                 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
19659                   // match
19660                   return letterForms;
19661                 }
19662               }
19663
19664               return null;
19665             }
19666           }
19667
19668           exports.GrandparentLetter = GrandparentLetter;
19669         });
19670
19671         var lib = createCommonjsModule(function (module, exports) {
19672
19673           Object.defineProperty(exports, "__esModule", {
19674             value: true
19675           });
19676           exports.isArabic = isArabic_1.isArabic;
19677           exports.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
19678           exports.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
19679           exports.Normal = Normalization.Normal;
19680           exports.CharShaper = CharShaper_1.CharShaper;
19681           exports.WordShaper = WordShaper_1.WordShaper;
19682           exports.ParentLetter = ParentLetter_1.ParentLetter;
19683           exports.GrandparentLetter = ParentLetter_1.GrandparentLetter;
19684         });
19685
19686         var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u07BF\u08A0–\u08BF]/;
19687         function fixRTLTextForSvg(inputText) {
19688           var ret = '',
19689               rtlBuffer = [];
19690           var arabicRegex = /[\u0600-\u06FF]/g;
19691           var arabicDiacritics = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06ED]/g;
19692           var arabicMath = /[\u0660-\u066C\u06F0-\u06F9]+/g;
19693           var thaanaVowel = /[\u07A6-\u07B0]/;
19694           var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/; // Arabic word shaping
19695
19696           if (arabicRegex.test(inputText)) {
19697             inputText = lib.WordShaper(inputText);
19698           }
19699
19700           for (var n = 0; n < inputText.length; n++) {
19701             var c = inputText[n];
19702
19703             if (arabicMath.test(c)) {
19704               // Arabic numbers go LTR
19705               ret += rtlBuffer.reverse().join('');
19706               rtlBuffer = [c];
19707             } else {
19708               if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
19709                 ret += rtlBuffer.reverse().join('');
19710                 rtlBuffer = [];
19711               }
19712
19713               if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
19714                 rtlBuffer[rtlBuffer.length - 1] += c;
19715               } else if (rtlRegex.test(c) // include Arabic presentation forms
19716               || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
19717                 rtlBuffer.push(c);
19718               } else if (c === ' ' && rtlBuffer.length) {
19719                 // whitespace within RTL text
19720                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
19721               } else {
19722                 // non-RTL character
19723                 ret += rtlBuffer.reverse().join('') + c;
19724                 rtlBuffer = [];
19725               }
19726             }
19727           }
19728
19729           ret += rtlBuffer.reverse().join('');
19730           return ret;
19731         }
19732
19733         var propertyIsEnumerable = objectPropertyIsEnumerable.f;
19734
19735         // `Object.{ entries, values }` methods implementation
19736         var createMethod$5 = function (TO_ENTRIES) {
19737           return function (it) {
19738             var O = toIndexedObject(it);
19739             var keys = objectKeys(O);
19740             var length = keys.length;
19741             var i = 0;
19742             var result = [];
19743             var key;
19744             while (length > i) {
19745               key = keys[i++];
19746               if (!descriptors || propertyIsEnumerable.call(O, key)) {
19747                 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
19748               }
19749             }
19750             return result;
19751           };
19752         };
19753
19754         var objectToArray = {
19755           // `Object.entries` method
19756           // https://tc39.github.io/ecma262/#sec-object.entries
19757           entries: createMethod$5(true),
19758           // `Object.values` method
19759           // https://tc39.github.io/ecma262/#sec-object.values
19760           values: createMethod$5(false)
19761         };
19762
19763         var $values = objectToArray.values;
19764
19765         // `Object.values` method
19766         // https://tc39.github.io/ecma262/#sec-object.values
19767         _export({ target: 'Object', stat: true }, {
19768           values: function values(O) {
19769             return $values(O);
19770           }
19771         });
19772
19773         // https://github.com/openstreetmap/iD/issues/772
19774         // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
19775         var _storage;
19776
19777         try {
19778           _storage = localStorage;
19779         } catch (e) {} // eslint-disable-line no-empty
19780
19781
19782         _storage = _storage || function () {
19783           var s = {};
19784           return {
19785             getItem: function getItem(k) {
19786               return s[k];
19787             },
19788             setItem: function setItem(k, v) {
19789               return s[k] = v;
19790             },
19791             removeItem: function removeItem(k) {
19792               return delete s[k];
19793             }
19794           };
19795         }(); //
19796         // corePreferences is an interface for persisting basic key-value strings
19797         // within and between iD sessions on the same site.
19798         //
19799
19800
19801         function corePreferences(k, v) {
19802           try {
19803             if (arguments.length === 1) return _storage.getItem(k);else if (v === null) _storage.removeItem(k);else _storage.setItem(k, v);
19804           } catch (e) {
19805             /* eslint-disable no-console */
19806             if (typeof console !== 'undefined') {
19807               console.error('localStorage quota exceeded');
19808             }
19809             /* eslint-enable no-console */
19810
19811           }
19812         }
19813
19814         function responseText(response) {
19815           if (!response.ok) throw new Error(response.status + " " + response.statusText);
19816           return response.text();
19817         }
19818
19819         function d3_text (input, init) {
19820           return fetch(input, init).then(responseText);
19821         }
19822
19823         function responseJson(response) {
19824           if (!response.ok) throw new Error(response.status + " " + response.statusText);
19825           if (response.status === 204 || response.status === 205) return;
19826           return response.json();
19827         }
19828
19829         function d3_json (input, init) {
19830           return fetch(input, init).then(responseJson);
19831         }
19832
19833         function parser(type) {
19834           return function (input, init) {
19835             return d3_text(input, init).then(function (text) {
19836               return new DOMParser().parseFromString(text, type);
19837             });
19838           };
19839         }
19840
19841         var d3_xml = parser("application/xml");
19842         var svg = parser("image/svg+xml");
19843
19844         var _mainFileFetcher = coreFileFetcher(); // singleton
19845         // coreFileFetcher asynchronously fetches data from JSON files
19846         //
19847
19848         function coreFileFetcher() {
19849           var _this = {};
19850           var _inflight = {};
19851           var _fileMap = {
19852             'address_formats': 'data/address_formats.min.json',
19853             'deprecated': 'data/deprecated.min.json',
19854             'discarded': 'data/discarded.min.json',
19855             'imagery': 'data/imagery.min.json',
19856             'intro_graph': 'data/intro_graph.min.json',
19857             'keepRight': 'data/keepRight.min.json',
19858             'languages': 'data/languages.min.json',
19859             'locales': 'data/locales.min.json',
19860             'nsi_brands': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@4/dist/brands.min.json',
19861             'nsi_filters': 'https://cdn.jsdelivr.net/npm/name-suggestion-index@4/dist/filters.min.json',
19862             'oci_features': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/features.min.json',
19863             'oci_resources': 'https://cdn.jsdelivr.net/npm/osm-community-index@2/dist/resources.min.json',
19864             'preset_categories': 'data/preset_categories.min.json',
19865             'preset_defaults': 'data/preset_defaults.min.json',
19866             'preset_fields': 'data/preset_fields.min.json',
19867             'preset_presets': 'data/preset_presets.min.json',
19868             'phone_formats': 'data/phone_formats.min.json',
19869             'qa_data': 'data/qa_data.min.json',
19870             'shortcuts': 'data/shortcuts.min.json',
19871             'territory_languages': 'data/territory_languages.min.json',
19872             'wmf_sitematrix': 'https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json'
19873           };
19874           var _cachedData = {}; // expose the cache; useful for tests
19875
19876           _this.cache = function () {
19877             return _cachedData;
19878           }; // Returns a Promise to fetch data
19879           // (resolved with the data if we have it already)
19880
19881
19882           _this.get = function (which) {
19883             if (_cachedData[which]) {
19884               return Promise.resolve(_cachedData[which]);
19885             }
19886
19887             var file = _fileMap[which];
19888
19889             var url = file && _this.asset(file);
19890
19891             if (!url) {
19892               return Promise.reject("Unknown data file for \"".concat(which, "\""));
19893             }
19894
19895             var prom = _inflight[url];
19896
19897             if (!prom) {
19898               _inflight[url] = prom = d3_json(url).then(function (result) {
19899                 delete _inflight[url];
19900
19901                 if (!result) {
19902                   throw new Error("No data loaded for \"".concat(which, "\""));
19903                 }
19904
19905                 _cachedData[which] = result;
19906                 return result;
19907               })["catch"](function (err) {
19908                 delete _inflight[url];
19909                 throw err;
19910               });
19911             }
19912
19913             return prom;
19914           }; // Accessor for the file map
19915
19916
19917           _this.fileMap = function (val) {
19918             if (!arguments.length) return _fileMap;
19919             _fileMap = val;
19920             return _this;
19921           };
19922
19923           var _assetPath = '';
19924
19925           _this.assetPath = function (val) {
19926             if (!arguments.length) return _assetPath;
19927             _assetPath = val;
19928             return _this;
19929           };
19930
19931           var _assetMap = {};
19932
19933           _this.assetMap = function (val) {
19934             if (!arguments.length) return _assetMap;
19935             _assetMap = val;
19936             return _this;
19937           };
19938
19939           _this.asset = function (val) {
19940             if (/^http(s)?:\/\//i.test(val)) return val;
19941             var filename = _assetPath + val;
19942             return _assetMap[filename] || filename;
19943           };
19944
19945           return _this;
19946         }
19947
19948         var $findIndex$1 = arrayIteration.findIndex;
19949
19950
19951
19952         var FIND_INDEX = 'findIndex';
19953         var SKIPS_HOLES$1 = true;
19954
19955         var USES_TO_LENGTH$b = arrayMethodUsesToLength(FIND_INDEX);
19956
19957         // Shouldn't skip holes
19958         if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES$1 = false; });
19959
19960         // `Array.prototype.findIndex` method
19961         // https://tc39.github.io/ecma262/#sec-array.prototype.findindex
19962         _export({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 || !USES_TO_LENGTH$b }, {
19963           findIndex: function findIndex(callbackfn /* , that = undefined */) {
19964             return $findIndex$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
19965           }
19966         });
19967
19968         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
19969         addToUnscopables(FIND_INDEX);
19970
19971         var $includes$1 = arrayIncludes.includes;
19972
19973
19974
19975         var USES_TO_LENGTH$c = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });
19976
19977         // `Array.prototype.includes` method
19978         // https://tc39.github.io/ecma262/#sec-array.prototype.includes
19979         _export({ target: 'Array', proto: true, forced: !USES_TO_LENGTH$c }, {
19980           includes: function includes(el /* , fromIndex = 0 */) {
19981             return $includes$1(this, el, arguments.length > 1 ? arguments[1] : undefined);
19982           }
19983         });
19984
19985         // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
19986         addToUnscopables('includes');
19987
19988         var notARegexp = function (it) {
19989           if (isRegexp(it)) {
19990             throw TypeError("The method doesn't accept regular expressions");
19991           } return it;
19992         };
19993
19994         var MATCH$2 = wellKnownSymbol('match');
19995
19996         var correctIsRegexpLogic = function (METHOD_NAME) {
19997           var regexp = /./;
19998           try {
19999             '/./'[METHOD_NAME](regexp);
20000           } catch (error1) {
20001             try {
20002               regexp[MATCH$2] = false;
20003               return '/./'[METHOD_NAME](regexp);
20004             } catch (error2) { /* empty */ }
20005           } return false;
20006         };
20007
20008         // `String.prototype.includes` method
20009         // https://tc39.github.io/ecma262/#sec-string.prototype.includes
20010         _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {
20011           includes: function includes(searchString /* , position = 0 */) {
20012             return !!~String(requireObjectCoercible(this))
20013               .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
20014           }
20015         });
20016
20017         var _detected;
20018
20019         function utilDetect(refresh) {
20020           if (_detected && !refresh) return _detected;
20021           _detected = {};
20022           var ua = navigator.userAgent;
20023           var m = null;
20024           /* Browser */
20025
20026           m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
20027
20028           if (m !== null) {
20029             _detected.browser = m[1];
20030             _detected.version = m[2];
20031           }
20032
20033           if (!_detected.browser) {
20034             m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
20035
20036             if (m !== null) {
20037               _detected.browser = 'msie';
20038               _detected.version = m[1];
20039             }
20040           }
20041
20042           if (!_detected.browser) {
20043             m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
20044
20045             if (m !== null) {
20046               _detected.browser = 'Opera';
20047               _detected.version = m[2];
20048             }
20049           }
20050
20051           if (!_detected.browser) {
20052             m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
20053
20054             if (m !== null) {
20055               _detected.browser = m[1];
20056               _detected.version = m[2];
20057               m = ua.match(/version\/([\.\d]+)/i);
20058               if (m !== null) _detected.version = m[1];
20059             }
20060           }
20061
20062           if (!_detected.browser) {
20063             _detected.browser = navigator.appName;
20064             _detected.version = navigator.appVersion;
20065           } // keep major.minor version only..
20066
20067
20068           _detected.version = _detected.version.split(/\W/).slice(0, 2).join('.'); // detect other browser capabilities
20069           // Legacy Opera has incomplete svg style support. See #715
20070
20071           _detected.opera = _detected.browser.toLowerCase() === 'opera' && parseFloat(_detected.version) < 15;
20072
20073           if (_detected.browser.toLowerCase() === 'msie') {
20074             _detected.ie = true;
20075             _detected.browser = 'Internet Explorer';
20076             _detected.support = parseFloat(_detected.version) >= 11;
20077           } else {
20078             _detected.ie = false;
20079             _detected.support = true;
20080           }
20081
20082           _detected.filedrop = window.FileReader && 'ondrop' in window;
20083           _detected.download = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
20084           _detected.cssfilters = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
20085           /* Platform */
20086
20087           if (/Win/.test(ua)) {
20088             _detected.os = 'win';
20089             _detected.platform = 'Windows';
20090           } else if (/Mac/.test(ua)) {
20091             _detected.os = 'mac';
20092             _detected.platform = 'Macintosh';
20093           } else if (/X11/.test(ua) || /Linux/.test(ua)) {
20094             _detected.os = 'linux';
20095             _detected.platform = 'Linux';
20096           } else {
20097             _detected.os = 'win';
20098             _detected.platform = 'Unknown';
20099           }
20100
20101           _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
20102           // so assume any "mac" with multitouch is actually iOS
20103           navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
20104           /* Locale */
20105           // An array of locales requested by the browser in priority order.
20106
20107           _detected.browserLocales = Array.from(new Set( // remove duplicates
20108           [navigator.language].concat(navigator.languages || []).concat([// old property for backwards compatibility
20109           navigator.userLanguage]) // remove any undefined values
20110           .filter(Boolean)));
20111           /* Host */
20112
20113           var loc = window.top.location;
20114           var origin = loc.origin;
20115
20116           if (!origin) {
20117             // for unpatched IE11
20118             origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port : '');
20119           }
20120
20121           _detected.host = origin + loc.pathname;
20122           return _detected;
20123         }
20124
20125         var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
20126         var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
20127         var defineProperty$a = objectDefineProperty.f;
20128         var trim$2 = stringTrim.trim;
20129
20130         var NUMBER = 'Number';
20131         var NativeNumber = global_1[NUMBER];
20132         var NumberPrototype = NativeNumber.prototype;
20133
20134         // Opera ~12 has broken Object#toString
20135         var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER;
20136
20137         // `ToNumber` abstract operation
20138         // https://tc39.github.io/ecma262/#sec-tonumber
20139         var toNumber = function (argument) {
20140           var it = toPrimitive(argument, false);
20141           var first, third, radix, maxCode, digits, length, index, code;
20142           if (typeof it == 'string' && it.length > 2) {
20143             it = trim$2(it);
20144             first = it.charCodeAt(0);
20145             if (first === 43 || first === 45) {
20146               third = it.charCodeAt(2);
20147               if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
20148             } else if (first === 48) {
20149               switch (it.charCodeAt(1)) {
20150                 case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
20151                 case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
20152                 default: return +it;
20153               }
20154               digits = it.slice(2);
20155               length = digits.length;
20156               for (index = 0; index < length; index++) {
20157                 code = digits.charCodeAt(index);
20158                 // parseInt parses a string to a first unavailable symbol
20159                 // but ToNumber should return NaN if a string contains unavailable symbols
20160                 if (code < 48 || code > maxCode) return NaN;
20161               } return parseInt(digits, radix);
20162             }
20163           } return +it;
20164         };
20165
20166         // `Number` constructor
20167         // https://tc39.github.io/ecma262/#sec-number-constructor
20168         if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
20169           var NumberWrapper = function Number(value) {
20170             var it = arguments.length < 1 ? 0 : value;
20171             var dummy = this;
20172             return dummy instanceof NumberWrapper
20173               // check on 1..constructor(foo) case
20174               && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER)
20175                 ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it);
20176           };
20177           for (var keys$3 = descriptors ? getOwnPropertyNames$2(NativeNumber) : (
20178             // ES3:
20179             'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
20180             // ES2015 (in case, if modules with ES2015 Number statics required before):
20181             'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
20182             'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger'
20183           ).split(','), j$2 = 0, key$1; keys$3.length > j$2; j$2++) {
20184             if (has(NativeNumber, key$1 = keys$3[j$2]) && !has(NumberWrapper, key$1)) {
20185               defineProperty$a(NumberWrapper, key$1, getOwnPropertyDescriptor$3(NativeNumber, key$1));
20186             }
20187           }
20188           NumberWrapper.prototype = NumberPrototype;
20189           NumberPrototype.constructor = NumberWrapper;
20190           redefine(global_1, NUMBER, NumberWrapper);
20191         }
20192
20193         // `Number.MAX_SAFE_INTEGER` constant
20194         // https://tc39.github.io/ecma262/#sec-number.max_safe_integer
20195         _export({ target: 'Number', stat: true }, {
20196           MAX_SAFE_INTEGER: 0x1FFFFFFFFFFFFF
20197         });
20198
20199         var aesJs = createCommonjsModule(function (module, exports) {
20200           /*! MIT License. Copyright 2015-2018 Richard Moore <me@ricmoo.com>. See LICENSE.txt. */
20201           (function (root) {
20202
20203             function checkInt(value) {
20204               return parseInt(value) === value;
20205             }
20206
20207             function checkInts(arrayish) {
20208               if (!checkInt(arrayish.length)) {
20209                 return false;
20210               }
20211
20212               for (var i = 0; i < arrayish.length; i++) {
20213                 if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
20214                   return false;
20215                 }
20216               }
20217
20218               return true;
20219             }
20220
20221             function coerceArray(arg, copy) {
20222               // ArrayBuffer view
20223               if (arg.buffer && arg.name === 'Uint8Array') {
20224                 if (copy) {
20225                   if (arg.slice) {
20226                     arg = arg.slice();
20227                   } else {
20228                     arg = Array.prototype.slice.call(arg);
20229                   }
20230                 }
20231
20232                 return arg;
20233               } // It's an array; check it is a valid representation of a byte
20234
20235
20236               if (Array.isArray(arg)) {
20237                 if (!checkInts(arg)) {
20238                   throw new Error('Array contains invalid value: ' + arg);
20239                 }
20240
20241                 return new Uint8Array(arg);
20242               } // Something else, but behaves like an array (maybe a Buffer? Arguments?)
20243
20244
20245               if (checkInt(arg.length) && checkInts(arg)) {
20246                 return new Uint8Array(arg);
20247               }
20248
20249               throw new Error('unsupported array-like object');
20250             }
20251
20252             function createArray(length) {
20253               return new Uint8Array(length);
20254             }
20255
20256             function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
20257               if (sourceStart != null || sourceEnd != null) {
20258                 if (sourceArray.slice) {
20259                   sourceArray = sourceArray.slice(sourceStart, sourceEnd);
20260                 } else {
20261                   sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
20262                 }
20263               }
20264
20265               targetArray.set(sourceArray, targetStart);
20266             }
20267
20268             var convertUtf8 = function () {
20269               function toBytes(text) {
20270                 var result = [],
20271                     i = 0;
20272                 text = encodeURI(text);
20273
20274                 while (i < text.length) {
20275                   var c = text.charCodeAt(i++); // if it is a % sign, encode the following 2 bytes as a hex value
20276
20277                   if (c === 37) {
20278                     result.push(parseInt(text.substr(i, 2), 16));
20279                     i += 2; // otherwise, just the actual byte
20280                   } else {
20281                     result.push(c);
20282                   }
20283                 }
20284
20285                 return coerceArray(result);
20286               }
20287
20288               function fromBytes(bytes) {
20289                 var result = [],
20290                     i = 0;
20291
20292                 while (i < bytes.length) {
20293                   var c = bytes[i];
20294
20295                   if (c < 128) {
20296                     result.push(String.fromCharCode(c));
20297                     i++;
20298                   } else if (c > 191 && c < 224) {
20299                     result.push(String.fromCharCode((c & 0x1f) << 6 | bytes[i + 1] & 0x3f));
20300                     i += 2;
20301                   } else {
20302                     result.push(String.fromCharCode((c & 0x0f) << 12 | (bytes[i + 1] & 0x3f) << 6 | bytes[i + 2] & 0x3f));
20303                     i += 3;
20304                   }
20305                 }
20306
20307                 return result.join('');
20308               }
20309
20310               return {
20311                 toBytes: toBytes,
20312                 fromBytes: fromBytes
20313               };
20314             }();
20315
20316             var convertHex = function () {
20317               function toBytes(text) {
20318                 var result = [];
20319
20320                 for (var i = 0; i < text.length; i += 2) {
20321                   result.push(parseInt(text.substr(i, 2), 16));
20322                 }
20323
20324                 return result;
20325               } // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
20326
20327
20328               var Hex = '0123456789abcdef';
20329
20330               function fromBytes(bytes) {
20331                 var result = [];
20332
20333                 for (var i = 0; i < bytes.length; i++) {
20334                   var v = bytes[i];
20335                   result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
20336                 }
20337
20338                 return result.join('');
20339               }
20340
20341               return {
20342                 toBytes: toBytes,
20343                 fromBytes: fromBytes
20344               };
20345             }(); // Number of rounds by keysize
20346
20347
20348             var numberOfRounds = {
20349               16: 10,
20350               24: 12,
20351               32: 14
20352             }; // Round constant words
20353
20354             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)
20355
20356             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];
20357             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
20358
20359             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];
20360             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];
20361             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];
20362             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
20363
20364             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];
20365             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];
20366             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];
20367             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
20368
20369             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];
20370             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];
20371             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];
20372             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];
20373
20374             function convertToInt32(bytes) {
20375               var result = [];
20376
20377               for (var i = 0; i < bytes.length; i += 4) {
20378                 result.push(bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]);
20379               }
20380
20381               return result;
20382             }
20383
20384             var AES = function AES(key) {
20385               if (!(this instanceof AES)) {
20386                 throw Error('AES must be instanitated with `new`');
20387               }
20388
20389               Object.defineProperty(this, 'key', {
20390                 value: coerceArray(key, true)
20391               });
20392
20393               this._prepare();
20394             };
20395
20396             AES.prototype._prepare = function () {
20397               var rounds = numberOfRounds[this.key.length];
20398
20399               if (rounds == null) {
20400                 throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
20401               } // encryption round keys
20402
20403
20404               this._Ke = []; // decryption round keys
20405
20406               this._Kd = [];
20407
20408               for (var i = 0; i <= rounds; i++) {
20409                 this._Ke.push([0, 0, 0, 0]);
20410
20411                 this._Kd.push([0, 0, 0, 0]);
20412               }
20413
20414               var roundKeyCount = (rounds + 1) * 4;
20415               var KC = this.key.length / 4; // convert the key into ints
20416
20417               var tk = convertToInt32(this.key); // copy values into round key arrays
20418
20419               var index;
20420
20421               for (var i = 0; i < KC; i++) {
20422                 index = i >> 2;
20423                 this._Ke[index][i % 4] = tk[i];
20424                 this._Kd[rounds - index][i % 4] = tk[i];
20425               } // key expansion (fips-197 section 5.2)
20426
20427
20428               var rconpointer = 0;
20429               var t = KC,
20430                   tt;
20431
20432               while (t < roundKeyCount) {
20433                 tt = tk[KC - 1];
20434                 tk[0] ^= S[tt >> 16 & 0xFF] << 24 ^ S[tt >> 8 & 0xFF] << 16 ^ S[tt & 0xFF] << 8 ^ S[tt >> 24 & 0xFF] ^ rcon[rconpointer] << 24;
20435                 rconpointer += 1; // key expansion (for non-256 bit)
20436
20437                 if (KC != 8) {
20438                   for (var i = 1; i < KC; i++) {
20439                     tk[i] ^= tk[i - 1];
20440                   } // key expansion for 256-bit keys is "slightly different" (fips-197)
20441
20442                 } else {
20443                   for (var i = 1; i < KC / 2; i++) {
20444                     tk[i] ^= tk[i - 1];
20445                   }
20446
20447                   tt = tk[KC / 2 - 1];
20448                   tk[KC / 2] ^= S[tt & 0xFF] ^ S[tt >> 8 & 0xFF] << 8 ^ S[tt >> 16 & 0xFF] << 16 ^ S[tt >> 24 & 0xFF] << 24;
20449
20450                   for (var i = KC / 2 + 1; i < KC; i++) {
20451                     tk[i] ^= tk[i - 1];
20452                   }
20453                 } // copy values into round key arrays
20454
20455
20456                 var i = 0,
20457                     r,
20458                     c;
20459
20460                 while (i < KC && t < roundKeyCount) {
20461                   r = t >> 2;
20462                   c = t % 4;
20463                   this._Ke[r][c] = tk[i];
20464                   this._Kd[rounds - r][c] = tk[i++];
20465                   t++;
20466                 }
20467               } // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
20468
20469
20470               for (var r = 1; r < rounds; r++) {
20471                 for (var c = 0; c < 4; c++) {
20472                   tt = this._Kd[r][c];
20473                   this._Kd[r][c] = U1[tt >> 24 & 0xFF] ^ U2[tt >> 16 & 0xFF] ^ U3[tt >> 8 & 0xFF] ^ U4[tt & 0xFF];
20474                 }
20475               }
20476             };
20477
20478             AES.prototype.encrypt = function (plaintext) {
20479               if (plaintext.length != 16) {
20480                 throw new Error('invalid plaintext size (must be 16 bytes)');
20481               }
20482
20483               var rounds = this._Ke.length - 1;
20484               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
20485
20486               var t = convertToInt32(plaintext);
20487
20488               for (var i = 0; i < 4; i++) {
20489                 t[i] ^= this._Ke[0][i];
20490               } // apply round transforms
20491
20492
20493               for (var r = 1; r < rounds; r++) {
20494                 for (var i = 0; i < 4; i++) {
20495                   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];
20496                 }
20497
20498                 t = a.slice();
20499               } // the last round is special
20500
20501
20502               var result = createArray(16),
20503                   tt;
20504
20505               for (var i = 0; i < 4; i++) {
20506                 tt = this._Ke[rounds][i];
20507                 result[4 * i] = (S[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
20508                 result[4 * i + 1] = (S[t[(i + 1) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
20509                 result[4 * i + 2] = (S[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
20510                 result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
20511               }
20512
20513               return result;
20514             };
20515
20516             AES.prototype.decrypt = function (ciphertext) {
20517               if (ciphertext.length != 16) {
20518                 throw new Error('invalid ciphertext size (must be 16 bytes)');
20519               }
20520
20521               var rounds = this._Kd.length - 1;
20522               var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
20523
20524               var t = convertToInt32(ciphertext);
20525
20526               for (var i = 0; i < 4; i++) {
20527                 t[i] ^= this._Kd[0][i];
20528               } // apply round transforms
20529
20530
20531               for (var r = 1; r < rounds; r++) {
20532                 for (var i = 0; i < 4; i++) {
20533                   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];
20534                 }
20535
20536                 t = a.slice();
20537               } // the last round is special
20538
20539
20540               var result = createArray(16),
20541                   tt;
20542
20543               for (var i = 0; i < 4; i++) {
20544                 tt = this._Kd[rounds][i];
20545                 result[4 * i] = (Si[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
20546                 result[4 * i + 1] = (Si[t[(i + 3) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
20547                 result[4 * i + 2] = (Si[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
20548                 result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
20549               }
20550
20551               return result;
20552             };
20553             /**
20554              *  Mode Of Operation - Electonic Codebook (ECB)
20555              */
20556
20557
20558             var ModeOfOperationECB = function ModeOfOperationECB(key) {
20559               if (!(this instanceof ModeOfOperationECB)) {
20560                 throw Error('AES must be instanitated with `new`');
20561               }
20562
20563               this.description = "Electronic Code Block";
20564               this.name = "ecb";
20565               this._aes = new AES(key);
20566             };
20567
20568             ModeOfOperationECB.prototype.encrypt = function (plaintext) {
20569               plaintext = coerceArray(plaintext);
20570
20571               if (plaintext.length % 16 !== 0) {
20572                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
20573               }
20574
20575               var ciphertext = createArray(plaintext.length);
20576               var block = createArray(16);
20577
20578               for (var i = 0; i < plaintext.length; i += 16) {
20579                 copyArray(plaintext, block, 0, i, i + 16);
20580                 block = this._aes.encrypt(block);
20581                 copyArray(block, ciphertext, i);
20582               }
20583
20584               return ciphertext;
20585             };
20586
20587             ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
20588               ciphertext = coerceArray(ciphertext);
20589
20590               if (ciphertext.length % 16 !== 0) {
20591                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
20592               }
20593
20594               var plaintext = createArray(ciphertext.length);
20595               var block = createArray(16);
20596
20597               for (var i = 0; i < ciphertext.length; i += 16) {
20598                 copyArray(ciphertext, block, 0, i, i + 16);
20599                 block = this._aes.decrypt(block);
20600                 copyArray(block, plaintext, i);
20601               }
20602
20603               return plaintext;
20604             };
20605             /**
20606              *  Mode Of Operation - Cipher Block Chaining (CBC)
20607              */
20608
20609
20610             var ModeOfOperationCBC = function ModeOfOperationCBC(key, iv) {
20611               if (!(this instanceof ModeOfOperationCBC)) {
20612                 throw Error('AES must be instanitated with `new`');
20613               }
20614
20615               this.description = "Cipher Block Chaining";
20616               this.name = "cbc";
20617
20618               if (!iv) {
20619                 iv = createArray(16);
20620               } else if (iv.length != 16) {
20621                 throw new Error('invalid initialation vector size (must be 16 bytes)');
20622               }
20623
20624               this._lastCipherblock = coerceArray(iv, true);
20625               this._aes = new AES(key);
20626             };
20627
20628             ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
20629               plaintext = coerceArray(plaintext);
20630
20631               if (plaintext.length % 16 !== 0) {
20632                 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
20633               }
20634
20635               var ciphertext = createArray(plaintext.length);
20636               var block = createArray(16);
20637
20638               for (var i = 0; i < plaintext.length; i += 16) {
20639                 copyArray(plaintext, block, 0, i, i + 16);
20640
20641                 for (var j = 0; j < 16; j++) {
20642                   block[j] ^= this._lastCipherblock[j];
20643                 }
20644
20645                 this._lastCipherblock = this._aes.encrypt(block);
20646                 copyArray(this._lastCipherblock, ciphertext, i);
20647               }
20648
20649               return ciphertext;
20650             };
20651
20652             ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
20653               ciphertext = coerceArray(ciphertext);
20654
20655               if (ciphertext.length % 16 !== 0) {
20656                 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
20657               }
20658
20659               var plaintext = createArray(ciphertext.length);
20660               var block = createArray(16);
20661
20662               for (var i = 0; i < ciphertext.length; i += 16) {
20663                 copyArray(ciphertext, block, 0, i, i + 16);
20664                 block = this._aes.decrypt(block);
20665
20666                 for (var j = 0; j < 16; j++) {
20667                   plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
20668                 }
20669
20670                 copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
20671               }
20672
20673               return plaintext;
20674             };
20675             /**
20676              *  Mode Of Operation - Cipher Feedback (CFB)
20677              */
20678
20679
20680             var ModeOfOperationCFB = function ModeOfOperationCFB(key, iv, segmentSize) {
20681               if (!(this instanceof ModeOfOperationCFB)) {
20682                 throw Error('AES must be instanitated with `new`');
20683               }
20684
20685               this.description = "Cipher Feedback";
20686               this.name = "cfb";
20687
20688               if (!iv) {
20689                 iv = createArray(16);
20690               } else if (iv.length != 16) {
20691                 throw new Error('invalid initialation vector size (must be 16 size)');
20692               }
20693
20694               if (!segmentSize) {
20695                 segmentSize = 1;
20696               }
20697
20698               this.segmentSize = segmentSize;
20699               this._shiftRegister = coerceArray(iv, true);
20700               this._aes = new AES(key);
20701             };
20702
20703             ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
20704               if (plaintext.length % this.segmentSize != 0) {
20705                 throw new Error('invalid plaintext size (must be segmentSize bytes)');
20706               }
20707
20708               var encrypted = coerceArray(plaintext, true);
20709               var xorSegment;
20710
20711               for (var i = 0; i < encrypted.length; i += this.segmentSize) {
20712                 xorSegment = this._aes.encrypt(this._shiftRegister);
20713
20714                 for (var j = 0; j < this.segmentSize; j++) {
20715                   encrypted[i + j] ^= xorSegment[j];
20716                 } // Shift the register
20717
20718
20719                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
20720                 copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
20721               }
20722
20723               return encrypted;
20724             };
20725
20726             ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
20727               if (ciphertext.length % this.segmentSize != 0) {
20728                 throw new Error('invalid ciphertext size (must be segmentSize bytes)');
20729               }
20730
20731               var plaintext = coerceArray(ciphertext, true);
20732               var xorSegment;
20733
20734               for (var i = 0; i < plaintext.length; i += this.segmentSize) {
20735                 xorSegment = this._aes.encrypt(this._shiftRegister);
20736
20737                 for (var j = 0; j < this.segmentSize; j++) {
20738                   plaintext[i + j] ^= xorSegment[j];
20739                 } // Shift the register
20740
20741
20742                 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
20743                 copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
20744               }
20745
20746               return plaintext;
20747             };
20748             /**
20749              *  Mode Of Operation - Output Feedback (OFB)
20750              */
20751
20752
20753             var ModeOfOperationOFB = function ModeOfOperationOFB(key, iv) {
20754               if (!(this instanceof ModeOfOperationOFB)) {
20755                 throw Error('AES must be instanitated with `new`');
20756               }
20757
20758               this.description = "Output Feedback";
20759               this.name = "ofb";
20760
20761               if (!iv) {
20762                 iv = createArray(16);
20763               } else if (iv.length != 16) {
20764                 throw new Error('invalid initialation vector size (must be 16 bytes)');
20765               }
20766
20767               this._lastPrecipher = coerceArray(iv, true);
20768               this._lastPrecipherIndex = 16;
20769               this._aes = new AES(key);
20770             };
20771
20772             ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
20773               var encrypted = coerceArray(plaintext, true);
20774
20775               for (var i = 0; i < encrypted.length; i++) {
20776                 if (this._lastPrecipherIndex === 16) {
20777                   this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
20778                   this._lastPrecipherIndex = 0;
20779                 }
20780
20781                 encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
20782               }
20783
20784               return encrypted;
20785             }; // Decryption is symetric
20786
20787
20788             ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
20789             /**
20790              *  Counter object for CTR common mode of operation
20791              */
20792
20793             var Counter = function Counter(initialValue) {
20794               if (!(this instanceof Counter)) {
20795                 throw Error('Counter must be instanitated with `new`');
20796               } // We allow 0, but anything false-ish uses the default 1
20797
20798
20799               if (initialValue !== 0 && !initialValue) {
20800                 initialValue = 1;
20801               }
20802
20803               if (typeof initialValue === 'number') {
20804                 this._counter = createArray(16);
20805                 this.setValue(initialValue);
20806               } else {
20807                 this.setBytes(initialValue);
20808               }
20809             };
20810
20811             Counter.prototype.setValue = function (value) {
20812               if (typeof value !== 'number' || parseInt(value) != value) {
20813                 throw new Error('invalid counter value (must be an integer)');
20814               } // We cannot safely handle numbers beyond the safe range for integers
20815
20816
20817               if (value > Number.MAX_SAFE_INTEGER) {
20818                 throw new Error('integer value out of safe range');
20819               }
20820
20821               for (var index = 15; index >= 0; --index) {
20822                 this._counter[index] = value % 256;
20823                 value = parseInt(value / 256);
20824               }
20825             };
20826
20827             Counter.prototype.setBytes = function (bytes) {
20828               bytes = coerceArray(bytes, true);
20829
20830               if (bytes.length != 16) {
20831                 throw new Error('invalid counter bytes size (must be 16 bytes)');
20832               }
20833
20834               this._counter = bytes;
20835             };
20836
20837             Counter.prototype.increment = function () {
20838               for (var i = 15; i >= 0; i--) {
20839                 if (this._counter[i] === 255) {
20840                   this._counter[i] = 0;
20841                 } else {
20842                   this._counter[i]++;
20843                   break;
20844                 }
20845               }
20846             };
20847             /**
20848              *  Mode Of Operation - Counter (CTR)
20849              */
20850
20851
20852             var ModeOfOperationCTR = function ModeOfOperationCTR(key, counter) {
20853               if (!(this instanceof ModeOfOperationCTR)) {
20854                 throw Error('AES must be instanitated with `new`');
20855               }
20856
20857               this.description = "Counter";
20858               this.name = "ctr";
20859
20860               if (!(counter instanceof Counter)) {
20861                 counter = new Counter(counter);
20862               }
20863
20864               this._counter = counter;
20865               this._remainingCounter = null;
20866               this._remainingCounterIndex = 16;
20867               this._aes = new AES(key);
20868             };
20869
20870             ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
20871               var encrypted = coerceArray(plaintext, true);
20872
20873               for (var i = 0; i < encrypted.length; i++) {
20874                 if (this._remainingCounterIndex === 16) {
20875                   this._remainingCounter = this._aes.encrypt(this._counter._counter);
20876                   this._remainingCounterIndex = 0;
20877
20878                   this._counter.increment();
20879                 }
20880
20881                 encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
20882               }
20883
20884               return encrypted;
20885             }; // Decryption is symetric
20886
20887
20888             ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; ///////////////////////
20889             // Padding
20890             // See:https://tools.ietf.org/html/rfc2315
20891
20892             function pkcs7pad(data) {
20893               data = coerceArray(data, true);
20894               var padder = 16 - data.length % 16;
20895               var result = createArray(data.length + padder);
20896               copyArray(data, result);
20897
20898               for (var i = data.length; i < result.length; i++) {
20899                 result[i] = padder;
20900               }
20901
20902               return result;
20903             }
20904
20905             function pkcs7strip(data) {
20906               data = coerceArray(data, true);
20907
20908               if (data.length < 16) {
20909                 throw new Error('PKCS#7 invalid length');
20910               }
20911
20912               var padder = data[data.length - 1];
20913
20914               if (padder > 16) {
20915                 throw new Error('PKCS#7 padding byte out of range');
20916               }
20917
20918               var length = data.length - padder;
20919
20920               for (var i = 0; i < padder; i++) {
20921                 if (data[length + i] !== padder) {
20922                   throw new Error('PKCS#7 invalid padding byte');
20923                 }
20924               }
20925
20926               var result = createArray(length);
20927               copyArray(data, result, 0, 0, length);
20928               return result;
20929             } ///////////////////////
20930             // Exporting
20931             // The block cipher
20932
20933
20934             var aesjs = {
20935               AES: AES,
20936               Counter: Counter,
20937               ModeOfOperation: {
20938                 ecb: ModeOfOperationECB,
20939                 cbc: ModeOfOperationCBC,
20940                 cfb: ModeOfOperationCFB,
20941                 ofb: ModeOfOperationOFB,
20942                 ctr: ModeOfOperationCTR
20943               },
20944               utils: {
20945                 hex: convertHex,
20946                 utf8: convertUtf8
20947               },
20948               padding: {
20949                 pkcs7: {
20950                   pad: pkcs7pad,
20951                   strip: pkcs7strip
20952                 }
20953               },
20954               _arrayTest: {
20955                 coerceArray: coerceArray,
20956                 createArray: createArray,
20957                 copyArray: copyArray
20958               }
20959             }; // node.js
20960
20961             {
20962               module.exports = aesjs; // RequireJS/AMD
20963               // http://www.requirejs.org/docs/api.html
20964               // https://github.com/amdjs/amdjs-api/wiki/AMD
20965             }
20966           })();
20967         });
20968
20969         // We can use keys that are 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes).
20970         // To generate a random key:  window.crypto.getRandomValues(new Uint8Array(16));
20971         // This default signing key is built into iD and can be used to mask/unmask sensitive values.
20972
20973         var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
20974         function utilAesEncrypt(text, key) {
20975           key = key || DEFAULT_128;
20976           var textBytes = aesJs.utils.utf8.toBytes(text);
20977           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
20978           var encryptedBytes = aesCtr.encrypt(textBytes);
20979           var encryptedHex = aesJs.utils.hex.fromBytes(encryptedBytes);
20980           return encryptedHex;
20981         }
20982         function utilAesDecrypt(encryptedHex, key) {
20983           key = key || DEFAULT_128;
20984           var encryptedBytes = aesJs.utils.hex.toBytes(encryptedHex);
20985           var aesCtr = new aesJs.ModeOfOperation.ctr(key);
20986           var decryptedBytes = aesCtr.decrypt(encryptedBytes);
20987           var text = aesJs.utils.utf8.fromBytes(decryptedBytes);
20988           return text;
20989         }
20990
20991         function utilCleanTags(tags) {
20992           var out = {};
20993
20994           for (var k in tags) {
20995             if (!k) continue;
20996             var v = tags[k];
20997
20998             if (v !== undefined) {
20999               out[k] = cleanValue(k, v);
21000             }
21001           }
21002
21003           return out;
21004
21005           function cleanValue(k, v) {
21006             function keepSpaces(k) {
21007               return /_hours|_times|:conditional$/.test(k);
21008             }
21009
21010             function skip(k) {
21011               return /^(description|note|fixme)$/.test(k);
21012             }
21013
21014             if (skip(k)) return v;
21015             var cleaned = v.split(';').map(function (s) {
21016               return s.trim();
21017             }).join(keepSpaces(k) ? '; ' : ';'); // The code below is not intended to validate websites and emails.
21018             // It is only intended to prevent obvious copy-paste errors. (#2323)
21019             // clean website- and email-like tags
21020
21021             if (k.indexOf('website') !== -1 || k.indexOf('email') !== -1 || cleaned.indexOf('http') === 0) {
21022               cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
21023             }
21024
21025             return cleaned;
21026           }
21027         }
21028
21029         // Like selection.property('value', ...), but avoids no-op value sets,
21030         // which can result in layout/repaint thrashing in some situations.
21031         function utilGetSetValue(selection, value) {
21032           function d3_selection_value(value) {
21033             function valueNull() {
21034               delete this.value;
21035             }
21036
21037             function valueConstant() {
21038               if (this.value !== value) {
21039                 this.value = value;
21040               }
21041             }
21042
21043             function valueFunction() {
21044               var x = value.apply(this, arguments);
21045
21046               if (x === null || x === undefined) {
21047                 delete this.value;
21048               } else if (this.value !== x) {
21049                 this.value = x;
21050               }
21051             }
21052
21053             return value === null || value === undefined ? valueNull : typeof value === 'function' ? valueFunction : valueConstant;
21054           }
21055
21056           if (arguments.length === 1) {
21057             return selection.property('value');
21058           }
21059
21060           return selection.each(d3_selection_value(value));
21061         }
21062
21063         function utilKeybinding(namespace) {
21064           var _keybindings = {};
21065
21066           function testBindings(d3_event, isCapturing) {
21067             var didMatch = false;
21068             var bindings = Object.keys(_keybindings).map(function (id) {
21069               return _keybindings[id];
21070             });
21071             var i, binding; // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
21072             // so we don't strictly match on the shift key, but we prioritize
21073             // shifted keybindings first, and fallback to unshifted only if no match.
21074             // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
21075             // priority match shifted keybindings first
21076
21077             for (i = 0; i < bindings.length; i++) {
21078               binding = bindings[i];
21079               if (!binding.event.modifiers.shiftKey) continue; // no shift
21080
21081               if (!!binding.capture !== isCapturing) continue;
21082
21083               if (matches(d3_event, binding, true)) {
21084                 binding.callback(d3_event);
21085                 didMatch = true; // match a max of one binding per event
21086
21087                 break;
21088               }
21089             }
21090
21091             if (didMatch) return; // then unshifted keybindings
21092
21093             for (i = 0; i < bindings.length; i++) {
21094               binding = bindings[i];
21095               if (binding.event.modifiers.shiftKey) continue; // shift
21096
21097               if (!!binding.capture !== isCapturing) continue;
21098
21099               if (matches(d3_event, binding, false)) {
21100                 binding.callback(d3_event);
21101                 break;
21102               }
21103             }
21104
21105             function matches(d3_event, binding, testShift) {
21106               var event = d3_event;
21107               var isMatch = false;
21108               var tryKeyCode = true; // Prefer a match on `KeyboardEvent.key`
21109
21110               if (event.key !== undefined) {
21111                 tryKeyCode = event.key.charCodeAt(0) > 255; // outside ISO-Latin-1
21112
21113                 isMatch = true;
21114
21115                 if (binding.event.key === undefined) {
21116                   isMatch = false;
21117                 } else if (Array.isArray(binding.event.key)) {
21118                   if (binding.event.key.map(function (s) {
21119                     return s.toLowerCase();
21120                   }).indexOf(event.key.toLowerCase()) === -1) isMatch = false;
21121                 } else {
21122                   if (event.key.toLowerCase() !== binding.event.key.toLowerCase()) isMatch = false;
21123                 }
21124               } // Fallback match on `KeyboardEvent.keyCode`, can happen if:
21125               // - browser doesn't support `KeyboardEvent.key`
21126               // - `KeyboardEvent.key` is outside ISO-Latin-1 range (cyrillic?)
21127
21128
21129               if (!isMatch && tryKeyCode) {
21130                 isMatch = event.keyCode === binding.event.keyCode;
21131               }
21132
21133               if (!isMatch) return false; // test modifier keys
21134
21135               if (!(event.ctrlKey && event.altKey)) {
21136                 // if both are set, assume AltGr and skip it - #4096
21137                 if (event.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
21138                 if (event.altKey !== binding.event.modifiers.altKey) return false;
21139               }
21140
21141               if (event.metaKey !== binding.event.modifiers.metaKey) return false;
21142               if (testShift && event.shiftKey !== binding.event.modifiers.shiftKey) return false;
21143               return true;
21144             }
21145           }
21146
21147           function capture(d3_event) {
21148             testBindings(d3_event, true);
21149           }
21150
21151           function bubble(d3_event) {
21152             var tagName = select(d3_event.target).node().tagName;
21153
21154             if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
21155               return;
21156             }
21157
21158             testBindings(d3_event, false);
21159           }
21160
21161           function keybinding(selection) {
21162             selection = selection || select(document);
21163             selection.on('keydown.capture.' + namespace, capture, true);
21164             selection.on('keydown.bubble.' + namespace, bubble, false);
21165             return keybinding;
21166           } // was: keybinding.off()
21167
21168
21169           keybinding.unbind = function (selection) {
21170             _keybindings = [];
21171             selection = selection || select(document);
21172             selection.on('keydown.capture.' + namespace, null);
21173             selection.on('keydown.bubble.' + namespace, null);
21174             return keybinding;
21175           };
21176
21177           keybinding.clear = function () {
21178             _keybindings = {};
21179             return keybinding;
21180           }; // Remove one or more keycode bindings.
21181
21182
21183           keybinding.off = function (codes, capture) {
21184             var arr = utilArrayUniq([].concat(codes));
21185
21186             for (var i = 0; i < arr.length; i++) {
21187               var id = arr[i] + (capture ? '-capture' : '-bubble');
21188               delete _keybindings[id];
21189             }
21190
21191             return keybinding;
21192           }; // Add one or more keycode bindings.
21193
21194
21195           keybinding.on = function (codes, callback, capture) {
21196             if (typeof callback !== 'function') {
21197               return keybinding.off(codes, capture);
21198             }
21199
21200             var arr = utilArrayUniq([].concat(codes));
21201
21202             for (var i = 0; i < arr.length; i++) {
21203               var id = arr[i] + (capture ? '-capture' : '-bubble');
21204               var binding = {
21205                 id: id,
21206                 capture: capture,
21207                 callback: callback,
21208                 event: {
21209                   key: undefined,
21210                   // preferred
21211                   keyCode: 0,
21212                   // fallback
21213                   modifiers: {
21214                     shiftKey: false,
21215                     ctrlKey: false,
21216                     altKey: false,
21217                     metaKey: false
21218                   }
21219                 }
21220               };
21221
21222               if (_keybindings[id]) {
21223                 console.warn('warning: duplicate keybinding for "' + id + '"'); // eslint-disable-line no-console
21224               }
21225
21226               _keybindings[id] = binding;
21227               var matches = arr[i].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
21228
21229               for (var j = 0; j < matches.length; j++) {
21230                 // Normalise matching errors
21231                 if (matches[j] === '++') matches[j] = '+';
21232
21233                 if (matches[j] in utilKeybinding.modifierCodes) {
21234                   var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j]]];
21235                   binding.event.modifiers[prop] = true;
21236                 } else {
21237                   binding.event.key = utilKeybinding.keys[matches[j]] || matches[j];
21238
21239                   if (matches[j] in utilKeybinding.keyCodes) {
21240                     binding.event.keyCode = utilKeybinding.keyCodes[matches[j]];
21241                   }
21242                 }
21243               }
21244             }
21245
21246             return keybinding;
21247           };
21248
21249           return keybinding;
21250         }
21251         /*
21252          * See https://github.com/keithamus/jwerty
21253          */
21254
21255         utilKeybinding.modifierCodes = {
21256           // Shift key, ⇧
21257           '⇧': 16,
21258           shift: 16,
21259           // CTRL key, on Mac: ⌃
21260           '⌃': 17,
21261           ctrl: 17,
21262           // ALT key, on Mac: ⌥ (Alt)
21263           '⌥': 18,
21264           alt: 18,
21265           option: 18,
21266           // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
21267           '⌘': 91,
21268           meta: 91,
21269           cmd: 91,
21270           'super': 91,
21271           win: 91
21272         };
21273         utilKeybinding.modifierProperties = {
21274           16: 'shiftKey',
21275           17: 'ctrlKey',
21276           18: 'altKey',
21277           91: 'metaKey'
21278         };
21279         utilKeybinding.plusKeys = ['plus', 'ffplus', '=', 'ffequals', '≠', '±'];
21280         utilKeybinding.minusKeys = ['_', '-', 'ffminus', 'dash', '–', '—'];
21281         utilKeybinding.keys = {
21282           // Backspace key, on Mac: ⌫ (Backspace)
21283           '⌫': 'Backspace',
21284           backspace: 'Backspace',
21285           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
21286           '⇥': 'Tab',
21287           '⇆': 'Tab',
21288           tab: 'Tab',
21289           // Return key, ↩
21290           '↩': 'Enter',
21291           '↵': 'Enter',
21292           '⏎': 'Enter',
21293           'return': 'Enter',
21294           enter: 'Enter',
21295           '⌅': 'Enter',
21296           // Pause/Break key
21297           'pause': 'Pause',
21298           'pause-break': 'Pause',
21299           // Caps Lock key, ⇪
21300           '⇪': 'CapsLock',
21301           caps: 'CapsLock',
21302           'caps-lock': 'CapsLock',
21303           // Escape key, on Mac: ⎋, on Windows: Esc
21304           '⎋': ['Escape', 'Esc'],
21305           escape: ['Escape', 'Esc'],
21306           esc: ['Escape', 'Esc'],
21307           // Space key
21308           space: [' ', 'Spacebar'],
21309           // Page-Up key, or pgup, on Mac: ↖
21310           '↖': 'PageUp',
21311           pgup: 'PageUp',
21312           'page-up': 'PageUp',
21313           // Page-Down key, or pgdown, on Mac: ↘
21314           '↘': 'PageDown',
21315           pgdown: 'PageDown',
21316           'page-down': 'PageDown',
21317           // END key, on Mac: ⇟
21318           '⇟': 'End',
21319           end: 'End',
21320           // HOME key, on Mac: ⇞
21321           '⇞': 'Home',
21322           home: 'Home',
21323           // Insert key, or ins
21324           ins: 'Insert',
21325           insert: 'Insert',
21326           // Delete key, on Mac: ⌦ (Delete)
21327           '⌦': ['Delete', 'Del'],
21328           del: ['Delete', 'Del'],
21329           'delete': ['Delete', 'Del'],
21330           // Left Arrow Key, or ←
21331           '←': ['ArrowLeft', 'Left'],
21332           left: ['ArrowLeft', 'Left'],
21333           'arrow-left': ['ArrowLeft', 'Left'],
21334           // Up Arrow Key, or ↑
21335           '↑': ['ArrowUp', 'Up'],
21336           up: ['ArrowUp', 'Up'],
21337           'arrow-up': ['ArrowUp', 'Up'],
21338           // Right Arrow Key, or →
21339           '→': ['ArrowRight', 'Right'],
21340           right: ['ArrowRight', 'Right'],
21341           'arrow-right': ['ArrowRight', 'Right'],
21342           // Up Arrow Key, or ↓
21343           '↓': ['ArrowDown', 'Down'],
21344           down: ['ArrowDown', 'Down'],
21345           'arrow-down': ['ArrowDown', 'Down'],
21346           // odities, stuff for backward compatibility (browsers and code):
21347           // Num-Multiply, or *
21348           '*': ['*', 'Multiply'],
21349           star: ['*', 'Multiply'],
21350           asterisk: ['*', 'Multiply'],
21351           multiply: ['*', 'Multiply'],
21352           // Num-Plus or +
21353           '+': ['+', 'Add'],
21354           'plus': ['+', 'Add'],
21355           // Num-Subtract, or -
21356           '-': ['-', 'Subtract'],
21357           subtract: ['-', 'Subtract'],
21358           'dash': ['-', 'Subtract'],
21359           // Semicolon
21360           semicolon: ';',
21361           // = or equals
21362           equals: '=',
21363           // Comma, or ,
21364           comma: ',',
21365           // Period, or ., or full-stop
21366           period: '.',
21367           'full-stop': '.',
21368           // Slash, or /, or forward-slash
21369           slash: '/',
21370           'forward-slash': '/',
21371           // Tick, or `, or back-quote
21372           tick: '`',
21373           'back-quote': '`',
21374           // Open bracket, or [
21375           'open-bracket': '[',
21376           // Back slash, or \
21377           'back-slash': '\\',
21378           // Close backet, or ]
21379           'close-bracket': ']',
21380           // Apostrophe, or Quote, or '
21381           quote: '\'',
21382           apostrophe: '\'',
21383           // NUMPAD 0-9
21384           'num-0': '0',
21385           'num-1': '1',
21386           'num-2': '2',
21387           'num-3': '3',
21388           'num-4': '4',
21389           'num-5': '5',
21390           'num-6': '6',
21391           'num-7': '7',
21392           'num-8': '8',
21393           'num-9': '9',
21394           // F1-F25
21395           f1: 'F1',
21396           f2: 'F2',
21397           f3: 'F3',
21398           f4: 'F4',
21399           f5: 'F5',
21400           f6: 'F6',
21401           f7: 'F7',
21402           f8: 'F8',
21403           f9: 'F9',
21404           f10: 'F10',
21405           f11: 'F11',
21406           f12: 'F12',
21407           f13: 'F13',
21408           f14: 'F14',
21409           f15: 'F15',
21410           f16: 'F16',
21411           f17: 'F17',
21412           f18: 'F18',
21413           f19: 'F19',
21414           f20: 'F20',
21415           f21: 'F21',
21416           f22: 'F22',
21417           f23: 'F23',
21418           f24: 'F24',
21419           f25: 'F25'
21420         };
21421         utilKeybinding.keyCodes = {
21422           // Backspace key, on Mac: ⌫ (Backspace)
21423           '⌫': 8,
21424           backspace: 8,
21425           // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
21426           '⇥': 9,
21427           '⇆': 9,
21428           tab: 9,
21429           // Return key, ↩
21430           '↩': 13,
21431           '↵': 13,
21432           '⏎': 13,
21433           'return': 13,
21434           enter: 13,
21435           '⌅': 13,
21436           // Pause/Break key
21437           'pause': 19,
21438           'pause-break': 19,
21439           // Caps Lock key, ⇪
21440           '⇪': 20,
21441           caps: 20,
21442           'caps-lock': 20,
21443           // Escape key, on Mac: ⎋, on Windows: Esc
21444           '⎋': 27,
21445           escape: 27,
21446           esc: 27,
21447           // Space key
21448           space: 32,
21449           // Page-Up key, or pgup, on Mac: ↖
21450           '↖': 33,
21451           pgup: 33,
21452           'page-up': 33,
21453           // Page-Down key, or pgdown, on Mac: ↘
21454           '↘': 34,
21455           pgdown: 34,
21456           'page-down': 34,
21457           // END key, on Mac: ⇟
21458           '⇟': 35,
21459           end: 35,
21460           // HOME key, on Mac: ⇞
21461           '⇞': 36,
21462           home: 36,
21463           // Insert key, or ins
21464           ins: 45,
21465           insert: 45,
21466           // Delete key, on Mac: ⌦ (Delete)
21467           '⌦': 46,
21468           del: 46,
21469           'delete': 46,
21470           // Left Arrow Key, or ←
21471           '←': 37,
21472           left: 37,
21473           'arrow-left': 37,
21474           // Up Arrow Key, or ↑
21475           '↑': 38,
21476           up: 38,
21477           'arrow-up': 38,
21478           // Right Arrow Key, or →
21479           '→': 39,
21480           right: 39,
21481           'arrow-right': 39,
21482           // Up Arrow Key, or ↓
21483           '↓': 40,
21484           down: 40,
21485           'arrow-down': 40,
21486           // odities, printing characters that come out wrong:
21487           // Firefox Equals
21488           'ffequals': 61,
21489           // Num-Multiply, or *
21490           '*': 106,
21491           star: 106,
21492           asterisk: 106,
21493           multiply: 106,
21494           // Num-Plus or +
21495           '+': 107,
21496           'plus': 107,
21497           // Num-Subtract, or -
21498           '-': 109,
21499           subtract: 109,
21500           // Firefox Plus
21501           'ffplus': 171,
21502           // Firefox Minus
21503           'ffminus': 173,
21504           // Semicolon
21505           ';': 186,
21506           semicolon: 186,
21507           // = or equals
21508           '=': 187,
21509           'equals': 187,
21510           // Comma, or ,
21511           ',': 188,
21512           comma: 188,
21513           // Dash / Underscore key
21514           'dash': 189,
21515           // Period, or ., or full-stop
21516           '.': 190,
21517           period: 190,
21518           'full-stop': 190,
21519           // Slash, or /, or forward-slash
21520           '/': 191,
21521           slash: 191,
21522           'forward-slash': 191,
21523           // Tick, or `, or back-quote
21524           '`': 192,
21525           tick: 192,
21526           'back-quote': 192,
21527           // Open bracket, or [
21528           '[': 219,
21529           'open-bracket': 219,
21530           // Back slash, or \
21531           '\\': 220,
21532           'back-slash': 220,
21533           // Close backet, or ]
21534           ']': 221,
21535           'close-bracket': 221,
21536           // Apostrophe, or Quote, or '
21537           '\'': 222,
21538           quote: 222,
21539           apostrophe: 222
21540         }; // NUMPAD 0-9
21541
21542         var i$1 = 95,
21543             n = 0;
21544
21545         while (++i$1 < 106) {
21546           utilKeybinding.keyCodes['num-' + n] = i$1;
21547           ++n;
21548         } // 0-9
21549
21550
21551         i$1 = 47;
21552         n = 0;
21553
21554         while (++i$1 < 58) {
21555           utilKeybinding.keyCodes[n] = i$1;
21556           ++n;
21557         } // F1-F25
21558
21559
21560         i$1 = 111;
21561         n = 1;
21562
21563         while (++i$1 < 136) {
21564           utilKeybinding.keyCodes['f' + n] = i$1;
21565           ++n;
21566         } // a-z
21567
21568
21569         i$1 = 64;
21570
21571         while (++i$1 < 91) {
21572           utilKeybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
21573         }
21574
21575         function utilObjectOmit(obj, omitKeys) {
21576           return Object.keys(obj).reduce(function (result, key) {
21577             if (omitKeys.indexOf(key) === -1) {
21578               result[key] = obj[key]; // keep
21579             }
21580
21581             return result;
21582           }, {});
21583         }
21584
21585         // Copies a variable number of methods from source to target.
21586         function utilRebind(target, source) {
21587           var i = 1,
21588               n = arguments.length,
21589               method;
21590
21591           while (++i < n) {
21592             target[method = arguments[i]] = d3_rebind(target, source, source[method]);
21593           }
21594
21595           return target;
21596         } // Method is assumed to be a standard D3 getter-setter:
21597         // If passed with no arguments, gets the value.
21598         // If passed with arguments, sets the value and returns the target.
21599
21600         function d3_rebind(target, source, method) {
21601           return function () {
21602             var value = method.apply(source, arguments);
21603             return value === source ? target : value;
21604           };
21605         }
21606
21607         // A per-domain session mutex backed by a cookie and dead man's
21608         // switch. If the session crashes, the mutex will auto-release
21609         // after 5 seconds.
21610         // This accepts a string and returns an object that complies with utilSessionMutexType
21611         function utilSessionMutex(name) {
21612           var mutex = {};
21613           var intervalID;
21614
21615           function renew() {
21616             var expires = new Date();
21617             expires.setSeconds(expires.getSeconds() + 5);
21618             document.cookie = name + '=1; expires=' + expires.toUTCString() + '; sameSite=strict';
21619           }
21620
21621           mutex.lock = function () {
21622             if (intervalID) return true;
21623             var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
21624             if (cookie) return false;
21625             renew();
21626             intervalID = window.setInterval(renew, 4000);
21627             return true;
21628           };
21629
21630           mutex.unlock = function () {
21631             if (!intervalID) return;
21632             document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict';
21633             clearInterval(intervalID);
21634             intervalID = null;
21635           };
21636
21637           mutex.locked = function () {
21638             return !!intervalID;
21639           };
21640
21641           return mutex;
21642         }
21643
21644         function utilTiler() {
21645           var _size = [256, 256];
21646           var _scale = 256;
21647           var _tileSize = 256;
21648           var _zoomExtent = [0, 20];
21649           var _translate = [_size[0] / 2, _size[1] / 2];
21650           var _margin = 0;
21651           var _skipNullIsland = false;
21652
21653           function clamp(num, min, max) {
21654             return Math.max(min, Math.min(num, max));
21655           }
21656
21657           function nearNullIsland(tile) {
21658             var x = tile[0];
21659             var y = tile[1];
21660             var z = tile[2];
21661
21662             if (z >= 7) {
21663               var center = Math.pow(2, z - 1);
21664               var width = Math.pow(2, z - 6);
21665               var min = center - width / 2;
21666               var max = center + width / 2 - 1;
21667               return x >= min && x <= max && y >= min && y <= max;
21668             }
21669
21670             return false;
21671           }
21672
21673           function tiler() {
21674             var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
21675             var z0 = clamp(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
21676             var tileMin = 0;
21677             var tileMax = Math.pow(2, z0) - 1;
21678             var log2ts = Math.log(_tileSize) * Math.LOG2E;
21679             var k = Math.pow(2, z - z0 + log2ts);
21680             var origin = [(_translate[0] - _scale / 2) / k, (_translate[1] - _scale / 2) / k];
21681             var cols = range(clamp(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1));
21682             var rows = range(clamp(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1));
21683             var tiles = [];
21684
21685             for (var i = 0; i < rows.length; i++) {
21686               var y = rows[i];
21687
21688               for (var j = 0; j < cols.length; j++) {
21689                 var x = cols[j];
21690
21691                 if (i >= _margin && i <= rows.length - _margin && j >= _margin && j <= cols.length - _margin) {
21692                   tiles.unshift([x, y, z0]); // tiles in view at beginning
21693                 } else {
21694                   tiles.push([x, y, z0]); // tiles in margin at the end
21695                 }
21696               }
21697             }
21698
21699             tiles.translate = origin;
21700             tiles.scale = k;
21701             return tiles;
21702           }
21703           /**
21704            * getTiles() returns an array of tiles that cover the map view
21705            */
21706
21707
21708           tiler.getTiles = function (projection) {
21709             var origin = [projection.scale() * Math.PI - projection.translate()[0], projection.scale() * Math.PI - projection.translate()[1]];
21710             this.size(projection.clipExtent()[1]).scale(projection.scale() * 2 * Math.PI).translate(projection.translate());
21711             var tiles = tiler();
21712             var ts = tiles.scale;
21713             return tiles.map(function (tile) {
21714               if (_skipNullIsland && nearNullIsland(tile)) {
21715                 return false;
21716               }
21717
21718               var x = tile[0] * ts - origin[0];
21719               var y = tile[1] * ts - origin[1];
21720               return {
21721                 id: tile.toString(),
21722                 xyz: tile,
21723                 extent: geoExtent(projection.invert([x, y + ts]), projection.invert([x + ts, y]))
21724               };
21725             }).filter(Boolean);
21726           };
21727           /**
21728            * getGeoJSON() returns a FeatureCollection for debugging tiles
21729            */
21730
21731
21732           tiler.getGeoJSON = function (projection) {
21733             var features = tiler.getTiles(projection).map(function (tile) {
21734               return {
21735                 type: 'Feature',
21736                 properties: {
21737                   id: tile.id,
21738                   name: tile.id
21739                 },
21740                 geometry: {
21741                   type: 'Polygon',
21742                   coordinates: [tile.extent.polygon()]
21743                 }
21744               };
21745             });
21746             return {
21747               type: 'FeatureCollection',
21748               features: features
21749             };
21750           };
21751
21752           tiler.tileSize = function (val) {
21753             if (!arguments.length) return _tileSize;
21754             _tileSize = val;
21755             return tiler;
21756           };
21757
21758           tiler.zoomExtent = function (val) {
21759             if (!arguments.length) return _zoomExtent;
21760             _zoomExtent = val;
21761             return tiler;
21762           };
21763
21764           tiler.size = function (val) {
21765             if (!arguments.length) return _size;
21766             _size = val;
21767             return tiler;
21768           };
21769
21770           tiler.scale = function (val) {
21771             if (!arguments.length) return _scale;
21772             _scale = val;
21773             return tiler;
21774           };
21775
21776           tiler.translate = function (val) {
21777             if (!arguments.length) return _translate;
21778             _translate = val;
21779             return tiler;
21780           }; // number to extend the rows/columns beyond those covering the viewport
21781
21782
21783           tiler.margin = function (val) {
21784             if (!arguments.length) return _margin;
21785             _margin = +val;
21786             return tiler;
21787           };
21788
21789           tiler.skipNullIsland = function (val) {
21790             if (!arguments.length) return _skipNullIsland;
21791             _skipNullIsland = val;
21792             return tiler;
21793           };
21794
21795           return tiler;
21796         }
21797
21798         function utilTriggerEvent(target, type) {
21799           target.each(function () {
21800             var evt = document.createEvent('HTMLEvents');
21801             evt.initEvent(type, true, true);
21802             this.dispatchEvent(evt);
21803           });
21804         }
21805
21806         var _mainLocalizer = coreLocalizer(); // singleton
21807
21808
21809         var _t = _mainLocalizer.t;
21810         // coreLocalizer manages language and locale parameters including translated strings
21811         //
21812
21813         function coreLocalizer() {
21814           var localizer = {};
21815           var _dataLanguages = {}; // `_dataLocales` is an object containing all _supported_ locale codes -> language info.
21816           // * `rtl` - right-to-left or left-to-right text direction
21817           // * `pct` - the percent of strings translated; 1 = 100%, full coverage
21818           //
21819           // {
21820           // en: { rtl: false, pct: {…} },
21821           // de: { rtl: false, pct: {…} },
21822           // …
21823           // }
21824
21825           var _dataLocales = {}; // `localeStrings` is an object containing all _loaded_ locale codes -> string data.
21826           // {
21827           // en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
21828           // de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
21829           // …
21830           // }
21831
21832           var _localeStrings = {}; // the current locale
21833
21834           var _localeCode = 'en-US'; // `_localeCodes` must contain `_localeCode` first, optionally followed by fallbacks
21835
21836           var _localeCodes = ['en-US', 'en'];
21837           var _languageCode = 'en';
21838           var _textDirection = 'ltr';
21839           var _usesMetric = false;
21840           var _languageNames = {};
21841           var _scriptNames = {}; // getters for the current locale parameters
21842
21843           localizer.localeCode = function () {
21844             return _localeCode;
21845           };
21846
21847           localizer.localeCodes = function () {
21848             return _localeCodes;
21849           };
21850
21851           localizer.languageCode = function () {
21852             return _languageCode;
21853           };
21854
21855           localizer.textDirection = function () {
21856             return _textDirection;
21857           };
21858
21859           localizer.usesMetric = function () {
21860             return _usesMetric;
21861           };
21862
21863           localizer.languageNames = function () {
21864             return _languageNames;
21865           };
21866
21867           localizer.scriptNames = function () {
21868             return _scriptNames;
21869           }; // The client app may want to manually set the locale, regardless of the
21870           // settings provided by the browser
21871
21872
21873           var _preferredLocaleCodes = [];
21874
21875           localizer.preferredLocaleCodes = function (codes) {
21876             if (!arguments.length) return _preferredLocaleCodes;
21877
21878             if (typeof codes === 'string') {
21879               // be generous and accept delimited strings as input
21880               _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
21881             } else {
21882               _preferredLocaleCodes = codes;
21883             }
21884
21885             return localizer;
21886           };
21887
21888           var _loadPromise;
21889
21890           localizer.ensureLoaded = function () {
21891             if (_loadPromise) return _loadPromise;
21892             return _loadPromise = Promise.all([// load the list of languages
21893             _mainFileFetcher.get('languages'), // load the list of supported locales
21894             _mainFileFetcher.get('locales')]).then(function (results) {
21895               _dataLanguages = results[0];
21896               _dataLocales = results[1];
21897             }).then(function () {
21898               var requestedLocales = (_preferredLocaleCodes || []). // List of locales preferred by the browser in priority order.
21899               concat(utilDetect().browserLocales) // fallback to English since it's the only guaranteed complete language
21900               .concat(['en']);
21901
21902               _localeCodes = localesToUseFrom(requestedLocales); // Run iD in the highest-priority locale; the rest are fallbacks
21903
21904               _localeCode = _localeCodes[0]; // Will always return the index for `en` if nothing else
21905
21906               var fullCoverageIndex = _localeCodes.findIndex(function (locale) {
21907                 return _dataLocales[locale].pct === 1;
21908               }); // We only need to load locales up until we find one with full coverage
21909
21910
21911               var loadStringsPromises = _localeCodes.slice(0, fullCoverageIndex + 1).map(function (code) {
21912                 return localizer.loadLocale(code);
21913               });
21914
21915               return Promise.all(loadStringsPromises);
21916             }).then(function () {
21917               updateForCurrentLocale();
21918             })["catch"](function (err) {
21919               return console.error(err);
21920             }); // eslint-disable-line
21921           }; // Returns the locales from `requestedLocales` supported by iD that we should use
21922
21923
21924           function localesToUseFrom(requestedLocales) {
21925             var supportedLocales = _dataLocales;
21926             var toUse = [];
21927
21928             for (var i in requestedLocales) {
21929               var locale = requestedLocales[i];
21930               if (supportedLocales[locale]) toUse.push(locale);
21931
21932               if (locale.includes('-')) {
21933                 // Full locale ('es-ES'), add fallback to the base ('es')
21934                 var langPart = locale.split('-')[0];
21935                 if (supportedLocales[langPart]) toUse.push(langPart);
21936               }
21937             } // remove duplicates
21938
21939
21940             return utilArrayUniq(toUse);
21941           }
21942
21943           function updateForCurrentLocale() {
21944             if (!_localeCode) return;
21945             _languageCode = _localeCode.split('-')[0];
21946             var currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
21947             var hash = utilStringQs(window.location.hash);
21948
21949             if (hash.rtl === 'true') {
21950               _textDirection = 'rtl';
21951             } else if (hash.rtl === 'false') {
21952               _textDirection = 'ltr';
21953             } else {
21954               _textDirection = currentData && currentData.rtl ? 'rtl' : 'ltr';
21955             }
21956
21957             var locale = _localeCode;
21958             if (locale.toLowerCase() === 'en-us') locale = 'en';
21959             _languageNames = _localeStrings[locale].languageNames;
21960             _scriptNames = _localeStrings[locale].scriptNames;
21961             _usesMetric = _localeCode.slice(-3).toLowerCase() !== '-us';
21962           }
21963           /* Locales */
21964           // Returns a Promise to load the strings for the requested locale
21965
21966
21967           localizer.loadLocale = function (requested) {
21968             if (!_dataLocales) {
21969               return Promise.reject('loadLocale called before init');
21970             }
21971
21972             var locale = requested; // US English is the default
21973
21974             if (locale.toLowerCase() === 'en-us') locale = 'en';
21975
21976             if (!_dataLocales[locale]) {
21977               return Promise.reject("Unsupported locale: ".concat(requested));
21978             }
21979
21980             if (_localeStrings[locale]) {
21981               // already loaded
21982               return Promise.resolve(locale);
21983             }
21984
21985             var fileMap = _mainFileFetcher.fileMap();
21986             var key = "locale_".concat(locale);
21987             fileMap[key] = "locales/".concat(locale, ".json");
21988             return _mainFileFetcher.get(key).then(function (d) {
21989               _localeStrings[locale] = d[locale];
21990               return locale;
21991             });
21992           };
21993
21994           localizer.pluralRule = function (number) {
21995             return pluralRule(number, _localeCode);
21996           }; // Returns the plural rule for the given `number` with the given `localeCode`.
21997           // One of: `zero`, `one`, `two`, `few`, `many`, `other`
21998
21999
22000           function pluralRule(number, localeCode) {
22001             // modern browsers have this functionality built-in
22002             var rules = 'Intl' in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
22003
22004             if (rules) {
22005               return rules.select(number);
22006             } // fallback to basic one/other, as in English
22007
22008
22009             if (number === 1) return 'one';
22010             return 'other';
22011           }
22012           /**
22013           * Try to find that string in `locale` or the current `_localeCode` matching
22014           * the given `stringId`. If no string can be found in the requested locale,
22015           * we'll recurse down all the `_localeCodes` until one is found.
22016           *
22017           * @param  {string}   stringId      string identifier
22018           * @param  {object?}  replacements  token replacements and default string
22019           * @param  {string?}  locale        locale to use (defaults to currentLocale)
22020           * @return {string?}  localized string
22021           */
22022
22023
22024           localizer.tInfo = function (stringId, replacements, locale) {
22025             locale = locale || _localeCode;
22026             var path = stringId.split('.').map(function (s) {
22027               return s.replace(/<TX_DOT>/g, '.');
22028             }).reverse();
22029             var stringsKey = locale; // US English is the default
22030
22031             if (stringsKey.toLowerCase() === 'en-us') stringsKey = 'en';
22032             var result = _localeStrings[stringsKey];
22033
22034             while (result !== undefined && path.length) {
22035               result = result[path.pop()];
22036             }
22037
22038             if (result !== undefined) {
22039               if (replacements) {
22040                 if (_typeof(result) === 'object' && Object.keys(result).length) {
22041                   // If plural forms are provided, dig one level deeper based on the
22042                   // first numeric token replacement provided.
22043                   var number = Object.values(replacements).find(function (value) {
22044                     return typeof value === 'number';
22045                   });
22046
22047                   if (number !== undefined) {
22048                     var rule = pluralRule(number, locale);
22049
22050                     if (result[rule]) {
22051                       result = result[rule];
22052                     } else {
22053                       // We're pretty sure this should be a plural but no string
22054                       // could be found for the given rule. Just pick the first
22055                       // string and hope it makes sense.
22056                       result = Object.values(result)[0];
22057                     }
22058                   }
22059                 }
22060
22061                 if (typeof result === 'string') {
22062                   for (var key in replacements) {
22063                     var value = replacements[key];
22064
22065                     if (typeof value === 'number' && value.toLocaleString) {
22066                       // format numbers for the locale
22067                       value = value.toLocaleString(locale, {
22068                         style: 'decimal',
22069                         useGrouping: true,
22070                         minimumFractionDigits: 0
22071                       });
22072                     }
22073
22074                     var token = "{".concat(key, "}");
22075                     var regex = new RegExp(token, 'g');
22076                     result = result.replace(regex, value);
22077                   }
22078                 }
22079               }
22080
22081               if (typeof result === 'string') {
22082                 // found a localized string!
22083                 return {
22084                   text: result,
22085                   locale: locale
22086                 };
22087               }
22088             } // no localized string found...
22089             // attempt to fallback to a lower-priority language
22090
22091
22092             var index = _localeCodes.indexOf(locale);
22093
22094             if (index >= 0 && index < _localeCodes.length - 1) {
22095               // eventually this will be 'en' or another locale with 100% coverage
22096               var fallback = _localeCodes[index + 1];
22097               return localizer.tInfo(stringId, replacements, fallback);
22098             }
22099
22100             if (replacements && 'default' in replacements) {
22101               // Fallback to a default value if one is specified in `replacements`
22102               return {
22103                 text: replacements["default"],
22104                 locale: null
22105               };
22106             }
22107
22108             var missing = "Missing ".concat(locale, " translation: ").concat(stringId);
22109             if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
22110
22111             return {
22112               text: missing,
22113               locale: 'en'
22114             };
22115           }; // Returns only the localized text, discarding the locale info
22116
22117
22118           localizer.t = function (stringId, replacements, locale) {
22119             return localizer.tInfo(stringId, replacements, locale).text;
22120           }; // Returns the localized text wrapped in an HTML element encoding the locale info
22121
22122
22123           localizer.t.html = function (stringId, replacements, locale) {
22124             var info = localizer.tInfo(stringId, replacements, locale); // text may be empty or undefined if `replacements.default` is
22125
22126             return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
22127           };
22128
22129           localizer.htmlForLocalizedText = function (text, localeCode) {
22130             return "<span class=\"localized-text\" lang=\"".concat(localeCode || 'unknown', "\">").concat(text, "</span>");
22131           };
22132
22133           localizer.languageName = function (code, options) {
22134             if (_languageNames[code]) {
22135               // name in locale language
22136               // e.g. "German"
22137               return _languageNames[code];
22138             } // sometimes we only want the local name
22139
22140
22141             if (options && options.localOnly) return null;
22142             var langInfo = _dataLanguages[code];
22143
22144             if (langInfo) {
22145               if (langInfo.nativeName) {
22146                 // name in native language
22147                 // e.g. "Deutsch (de)"
22148                 return localizer.t('translate.language_and_code', {
22149                   language: langInfo.nativeName,
22150                   code: code
22151                 });
22152               } else if (langInfo.base && langInfo.script) {
22153                 var base = langInfo.base; // the code of the language this is based on
22154
22155                 if (_languageNames[base]) {
22156                   // base language name in locale language
22157                   var scriptCode = langInfo.script;
22158                   var script = _scriptNames[scriptCode] || scriptCode; // e.g. "Serbian (Cyrillic)"
22159
22160                   return localizer.t('translate.language_and_code', {
22161                     language: _languageNames[base],
22162                     code: script
22163                   });
22164                 } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
22165                   // e.g. "српски (sr-Cyrl)"
22166                   return localizer.t('translate.language_and_code', {
22167                     language: _dataLanguages[base].nativeName,
22168                     code: code
22169                   });
22170                 }
22171               }
22172             }
22173
22174             return code; // if not found, use the code
22175           };
22176
22177           return localizer;
22178         }
22179
22180         // `presetCollection` is a wrapper around an `Array` of presets `collection`,
22181         // and decorated with some extra methods for searching and matching geometry
22182         //
22183
22184         function presetCollection(collection) {
22185           var MAXRESULTS = 50;
22186           var _this = {};
22187           var _memo = {};
22188           _this.collection = collection;
22189
22190           _this.item = function (id) {
22191             if (_memo[id]) return _memo[id];
22192
22193             var found = _this.collection.find(function (d) {
22194               return d.id === id;
22195             });
22196
22197             if (found) _memo[id] = found;
22198             return found;
22199           };
22200
22201           _this.index = function (id) {
22202             return _this.collection.findIndex(function (d) {
22203               return d.id === id;
22204             });
22205           };
22206
22207           _this.matchGeometry = function (geometry) {
22208             return presetCollection(_this.collection.filter(function (d) {
22209               return d.matchGeometry(geometry);
22210             }));
22211           };
22212
22213           _this.matchAllGeometry = function (geometries) {
22214             return presetCollection(_this.collection.filter(function (d) {
22215               return d && d.matchAllGeometry(geometries);
22216             }));
22217           };
22218
22219           _this.matchAnyGeometry = function (geometries) {
22220             return presetCollection(_this.collection.filter(function (d) {
22221               return geometries.some(function (geom) {
22222                 return d.matchGeometry(geom);
22223               });
22224             }));
22225           };
22226
22227           _this.fallback = function (geometry) {
22228             var id = geometry;
22229             if (id === 'vertex') id = 'point';
22230             return _this.item(id);
22231           };
22232
22233           _this.search = function (value, geometry, countryCode) {
22234             if (!value) return _this;
22235             value = value.toLowerCase().trim(); // match at name beginning or just after a space (e.g. "office" -> match "Law Office")
22236
22237             function leading(a) {
22238               var index = a.indexOf(value);
22239               return index === 0 || a[index - 1] === ' ';
22240             } // match at name beginning only
22241
22242
22243             function leadingStrict(a) {
22244               var index = a.indexOf(value);
22245               return index === 0;
22246             }
22247
22248             function sortNames(a, b) {
22249               var aCompare = (a.suggestion ? a.originalName : a.name()).toLowerCase();
22250               var bCompare = (b.suggestion ? b.originalName : b.name()).toLowerCase(); // priority if search string matches preset name exactly - #4325
22251
22252               if (value === aCompare) return -1;
22253               if (value === bCompare) return 1; // priority for higher matchScore
22254
22255               var i = b.originalScore - a.originalScore;
22256               if (i !== 0) return i; // priority if search string appears earlier in preset name
22257
22258               i = aCompare.indexOf(value) - bCompare.indexOf(value);
22259               if (i !== 0) return i; // priority for shorter preset names
22260
22261               return aCompare.length - bCompare.length;
22262             }
22263
22264             var pool = _this.collection;
22265
22266             if (countryCode) {
22267               pool = pool.filter(function (a) {
22268                 if (a.countryCodes && a.countryCodes.indexOf(countryCode) === -1) return false;
22269                 if (a.notCountryCodes && a.notCountryCodes.indexOf(countryCode) !== -1) return false;
22270                 return true;
22271               });
22272             }
22273
22274             var searchable = pool.filter(function (a) {
22275               return a.searchable !== false && a.suggestion !== true;
22276             });
22277             var suggestions = pool.filter(function (a) {
22278               return a.suggestion === true;
22279             }); // matches value to preset.name
22280
22281             var leading_name = searchable.filter(function (a) {
22282               return leading(a.name().toLowerCase());
22283             }).sort(sortNames); // matches value to preset suggestion name (original name is unhyphenated)
22284
22285             var leading_suggestions = suggestions.filter(function (a) {
22286               return leadingStrict(a.originalName.toLowerCase());
22287             }).sort(sortNames); // matches value to preset.terms values
22288
22289             var leading_terms = searchable.filter(function (a) {
22290               return (a.terms() || []).some(leading);
22291             }); // matches value to preset.tags values
22292
22293             var leading_tag_values = searchable.filter(function (a) {
22294               return Object.values(a.tags || {}).filter(function (val) {
22295                 return val !== '*';
22296               }).some(leading);
22297             }); // finds close matches to value in preset.name
22298
22299             var similar_name = searchable.map(function (a) {
22300               return {
22301                 preset: a,
22302                 dist: utilEditDistance(value, a.name())
22303               };
22304             }).filter(function (a) {
22305               return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
22306             }).sort(function (a, b) {
22307               return a.dist - b.dist;
22308             }).map(function (a) {
22309               return a.preset;
22310             }); // finds close matches to value to preset suggestion name (original name is unhyphenated)
22311
22312             var similar_suggestions = suggestions.map(function (a) {
22313               return {
22314                 preset: a,
22315                 dist: utilEditDistance(value, a.originalName.toLowerCase())
22316               };
22317             }).filter(function (a) {
22318               return a.dist + Math.min(value.length - a.preset.originalName.length, 0) < 1;
22319             }).sort(function (a, b) {
22320               return a.dist - b.dist;
22321             }).map(function (a) {
22322               return a.preset;
22323             }); // finds close matches to value in preset.terms
22324
22325             var similar_terms = searchable.filter(function (a) {
22326               return (a.terms() || []).some(function (b) {
22327                 return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
22328               });
22329             });
22330             var results = leading_name.concat(leading_suggestions, leading_terms, leading_tag_values, similar_name, similar_suggestions, similar_terms).slice(0, MAXRESULTS - 1);
22331
22332             if (geometry) {
22333               if (typeof geometry === 'string') {
22334                 results.push(_this.fallback(geometry));
22335               } else {
22336                 geometry.forEach(function (geom) {
22337                   return results.push(_this.fallback(geom));
22338                 });
22339               }
22340             }
22341
22342             return presetCollection(utilArrayUniq(results));
22343           };
22344
22345           return _this;
22346         }
22347
22348         // `presetCategory` builds a `presetCollection` of member presets,
22349         // decorated with some extra methods for searching and matching geometry
22350         //
22351
22352         function presetCategory(categoryID, category, all) {
22353           var _this = Object.assign({}, category); // shallow copy
22354
22355
22356           _this.id = categoryID;
22357           _this.members = presetCollection(category.members.map(function (presetID) {
22358             return all.item(presetID);
22359           }).filter(Boolean));
22360           _this.geometry = _this.members.collection.reduce(function (acc, preset) {
22361             for (var i in preset.geometry) {
22362               var geometry = preset.geometry[i];
22363
22364               if (acc.indexOf(geometry) === -1) {
22365                 acc.push(geometry);
22366               }
22367             }
22368
22369             return acc;
22370           }, []);
22371
22372           _this.matchGeometry = function (geom) {
22373             return _this.geometry.indexOf(geom) >= 0;
22374           };
22375
22376           _this.matchAllGeometry = function (geometries) {
22377             return _this.members.collection.some(function (preset) {
22378               return preset.matchAllGeometry(geometries);
22379             });
22380           };
22381
22382           _this.matchScore = function () {
22383             return -1;
22384           };
22385
22386           _this.name = function () {
22387             return _t("presets.categories.".concat(categoryID, ".name"), {
22388               'default': categoryID
22389             });
22390           };
22391
22392           _this.nameLabel = function () {
22393             return _t.html("presets.categories.".concat(categoryID, ".name"), {
22394               'default': categoryID
22395             });
22396           };
22397
22398           _this.terms = function () {
22399             return [];
22400           };
22401
22402           return _this;
22403         }
22404
22405         // `presetField` decorates a given `field` Object
22406         // with some extra methods for searching and matching geometry
22407         //
22408
22409         function presetField(fieldID, field) {
22410           var _this = Object.assign({}, field); // shallow copy
22411
22412
22413           _this.id = fieldID; // for use in classes, element ids, css selectors
22414
22415           _this.safeid = utilSafeClassName(fieldID);
22416
22417           _this.matchGeometry = function (geom) {
22418             return !_this.geometry || _this.geometry.indexOf(geom) !== -1;
22419           };
22420
22421           _this.matchAllGeometry = function (geometries) {
22422             return !_this.geometry || geometries.every(function (geom) {
22423               return _this.geometry.indexOf(geom) !== -1;
22424             });
22425           };
22426
22427           _this.t = function (scope, options) {
22428             return _t("presets.fields.".concat(fieldID, ".").concat(scope), options);
22429           };
22430
22431           _this.t.html = function (scope, options) {
22432             return _t.html("presets.fields.".concat(fieldID, ".").concat(scope), options);
22433           };
22434
22435           _this.title = function () {
22436             return _this.overrideLabel || _this.t('label', {
22437               'default': fieldID
22438             });
22439           };
22440
22441           _this.label = function () {
22442             return _this.overrideLabel || _this.t.html('label', {
22443               'default': fieldID
22444             });
22445           };
22446
22447           var _placeholder = _this.placeholder;
22448
22449           _this.placeholder = function () {
22450             return _this.t('placeholder', {
22451               'default': _placeholder
22452             });
22453           };
22454
22455           _this.originalTerms = (_this.terms || []).join();
22456
22457           _this.terms = function () {
22458             return _this.t('terms', {
22459               'default': _this.originalTerms
22460             }).toLowerCase().trim().split(/\s*,+\s*/);
22461           };
22462
22463           _this.increment = _this.type === 'number' ? _this.increment || 1 : undefined;
22464           return _this;
22465         }
22466
22467         // `Array.prototype.lastIndexOf` method
22468         // https://tc39.github.io/ecma262/#sec-array.prototype.lastindexof
22469         _export({ target: 'Array', proto: true, forced: arrayLastIndexOf !== [].lastIndexOf }, {
22470           lastIndexOf: arrayLastIndexOf
22471         });
22472
22473         // `presetPreset` decorates a given `preset` Object
22474         // with some extra methods for searching and matching geometry
22475         //
22476
22477         function presetPreset(presetID, preset, addable, allFields, allPresets) {
22478           allFields = allFields || {};
22479           allPresets = allPresets || {};
22480
22481           var _this = Object.assign({}, preset); // shallow copy
22482
22483
22484           var _addable = addable || false;
22485
22486           var _resolvedFields; // cache
22487
22488
22489           var _resolvedMoreFields; // cache
22490
22491
22492           _this.id = presetID;
22493           _this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
22494
22495           _this.originalTerms = (_this.terms || []).join();
22496           _this.originalName = _this.name || '';
22497           _this.originalScore = _this.matchScore || 1;
22498           _this.originalReference = _this.reference || {};
22499           _this.originalFields = _this.fields || [];
22500           _this.originalMoreFields = _this.moreFields || [];
22501
22502           _this.fields = function () {
22503             return _resolvedFields || (_resolvedFields = resolve('fields'));
22504           };
22505
22506           _this.moreFields = function () {
22507             return _resolvedMoreFields || (_resolvedMoreFields = resolve('moreFields'));
22508           };
22509
22510           _this.resetFields = function () {
22511             return _resolvedFields = _resolvedMoreFields = null;
22512           };
22513
22514           _this.tags = _this.tags || {};
22515           _this.addTags = _this.addTags || _this.tags;
22516           _this.removeTags = _this.removeTags || _this.addTags;
22517           _this.geometry = _this.geometry || [];
22518
22519           _this.matchGeometry = function (geom) {
22520             return _this.geometry.indexOf(geom) >= 0;
22521           };
22522
22523           _this.matchAllGeometry = function (geoms) {
22524             return geoms.every(_this.matchGeometry);
22525           };
22526
22527           _this.matchScore = function (entityTags) {
22528             var tags = _this.tags;
22529             var seen = {};
22530             var score = 0; // match on tags
22531
22532             for (var k in tags) {
22533               seen[k] = true;
22534
22535               if (entityTags[k] === tags[k]) {
22536                 score += _this.originalScore;
22537               } else if (tags[k] === '*' && k in entityTags) {
22538                 score += _this.originalScore / 2;
22539               } else {
22540                 return -1;
22541               }
22542             } // boost score for additional matches in addTags - #6802
22543
22544
22545             var addTags = _this.addTags;
22546
22547             for (var _k in addTags) {
22548               if (!seen[_k] && entityTags[_k] === addTags[_k]) {
22549                 score += _this.originalScore;
22550               }
22551             }
22552
22553             return score;
22554           };
22555
22556           _this.t = function (scope, options) {
22557             var textID = "presets.presets.".concat(presetID, ".").concat(scope);
22558             return _t(textID, options);
22559           };
22560
22561           _this.t.html = function (scope, options) {
22562             var textID = "presets.presets.".concat(presetID, ".").concat(scope);
22563             return _t.html(textID, options);
22564           };
22565
22566           _this.name = function () {
22567             return _this.t('name', {
22568               'default': _this.originalName
22569             });
22570           };
22571
22572           _this.nameLabel = function () {
22573             return _this.t.html('name', {
22574               'default': _this.originalName
22575             });
22576           };
22577
22578           _this.subtitle = function () {
22579             if (_this.suggestion) {
22580               var path = presetID.split('/');
22581               path.pop(); // remove brand name
22582
22583               return _t('presets.presets.' + path.join('/') + '.name');
22584             }
22585
22586             return null;
22587           };
22588
22589           _this.subtitleLabel = function () {
22590             if (_this.suggestion) {
22591               var path = presetID.split('/');
22592               path.pop(); // remove brand name
22593
22594               return _t.html('presets.presets.' + path.join('/') + '.name');
22595             }
22596
22597             return null;
22598           };
22599
22600           _this.terms = function () {
22601             return _this.t('terms', {
22602               'default': _this.originalTerms
22603             }).toLowerCase().trim().split(/\s*,+\s*/);
22604           };
22605
22606           _this.isFallback = function () {
22607             var tagCount = Object.keys(_this.tags).length;
22608             return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty('area');
22609           };
22610
22611           _this.addable = function (val) {
22612             if (!arguments.length) return _addable;
22613             _addable = val;
22614             return _this;
22615           };
22616
22617           _this.reference = function () {
22618             // Lookup documentation on Wikidata...
22619             var qid = _this.tags.wikidata || _this.tags['brand:wikidata'] || _this.tags['operator:wikidata'];
22620
22621             if (qid) {
22622               return {
22623                 qid: qid
22624               };
22625             } // Lookup documentation on OSM Wikibase...
22626
22627
22628             var key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
22629             var value = _this.originalReference.value || _this.tags[key];
22630
22631             if (value === '*') {
22632               return {
22633                 key: key
22634               };
22635             } else {
22636               return {
22637                 key: key,
22638                 value: value
22639               };
22640             }
22641           };
22642
22643           _this.unsetTags = function (tags, geometry, skipFieldDefaults) {
22644             tags = utilObjectOmit(tags, Object.keys(_this.removeTags));
22645
22646             if (geometry && !skipFieldDefaults) {
22647               _this.fields().forEach(function (field) {
22648                 if (field.matchGeometry(geometry) && field.key && field["default"] === tags[field.key]) {
22649                   delete tags[field.key];
22650                 }
22651               });
22652             }
22653
22654             delete tags.area;
22655             return tags;
22656           };
22657
22658           _this.setTags = function (tags, geometry, skipFieldDefaults) {
22659             var addTags = _this.addTags;
22660             tags = Object.assign({}, tags); // shallow copy
22661
22662             for (var k in addTags) {
22663               if (addTags[k] === '*') {
22664                 tags[k] = 'yes';
22665               } else {
22666                 tags[k] = addTags[k];
22667               }
22668             } // Add area=yes if necessary.
22669             // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
22670             // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
22671             // 2. chosen preset doesn't have a key in osmAreaKeys (`railway=station`)
22672
22673
22674             if (!addTags.hasOwnProperty('area')) {
22675               delete tags.area;
22676
22677               if (geometry === 'area') {
22678                 var needsAreaTag = true;
22679
22680                 if (_this.geometry.indexOf('line') === -1) {
22681                   for (var _k2 in addTags) {
22682                     if (_k2 in osmAreaKeys) {
22683                       needsAreaTag = false;
22684                       break;
22685                     }
22686                   }
22687                 }
22688
22689                 if (needsAreaTag) {
22690                   tags.area = 'yes';
22691                 }
22692               }
22693             }
22694
22695             if (geometry && !skipFieldDefaults) {
22696               _this.fields().forEach(function (field) {
22697                 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field["default"]) {
22698                   tags[field.key] = field["default"];
22699                 }
22700               });
22701             }
22702
22703             return tags;
22704           }; // For a preset without fields, use the fields of the parent preset.
22705           // Replace {preset} placeholders with the fields of the specified presets.
22706
22707
22708           function resolve(which) {
22709             var fieldIDs = which === 'fields' ? _this.originalFields : _this.originalMoreFields;
22710             var resolved = [];
22711             fieldIDs.forEach(function (fieldID) {
22712               var match = fieldID.match(/\{(.*)\}/);
22713
22714               if (match !== null) {
22715                 // a presetID wrapped in braces {}
22716                 resolved = resolved.concat(inheritFields(match[1], which));
22717               } else if (allFields[fieldID]) {
22718                 // a normal fieldID
22719                 resolved.push(allFields[fieldID]);
22720               } else {
22721                 console.log("Cannot resolve \"".concat(fieldID, "\" found in ").concat(_this.id, ".").concat(which)); // eslint-disable-line no-console
22722               }
22723             }); // no fields resolved, so use the parent's if possible
22724
22725             if (!resolved.length) {
22726               var endIndex = _this.id.lastIndexOf('/');
22727
22728               var parentID = endIndex && _this.id.substring(0, endIndex);
22729
22730               if (parentID) {
22731                 resolved = inheritFields(parentID, which);
22732               }
22733             }
22734
22735             return utilArrayUniq(resolved); // returns an array of fields to inherit from the given presetID, if found
22736
22737             function inheritFields(presetID, which) {
22738               var parent = allPresets[presetID];
22739               if (!parent) return [];
22740
22741               if (which === 'fields') {
22742                 return parent.fields().filter(shouldInherit);
22743               } else if (which === 'moreFields') {
22744                 return parent.moreFields();
22745               } else {
22746                 return [];
22747               }
22748             } // Skip `fields` for the keys which define the preset.
22749             // These are usually `typeCombo` fields like `shop=*`
22750
22751
22752             function shouldInherit(f) {
22753               if (f.key && _this.tags[f.key] !== undefined && // inherit anyway if multiple values are allowed or just a checkbox
22754               f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'manyCombo' && f.type !== 'check') return false;
22755               return true;
22756             }
22757           }
22758
22759           return _this;
22760         }
22761
22762         var _mainPresetIndex = presetIndex(); // singleton
22763         // `presetIndex` wraps a `presetCollection`
22764         // with methods for loading new data and returning defaults
22765         //
22766
22767         function presetIndex() {
22768           var dispatch$1 = dispatch('favoritePreset', 'recentsChange');
22769           var MAXRECENTS = 30; // seed the preset lists with geometry fallbacks
22770
22771           var POINT = presetPreset('point', {
22772             name: 'Point',
22773             tags: {},
22774             geometry: ['point', 'vertex'],
22775             matchScore: 0.1
22776           });
22777           var LINE = presetPreset('line', {
22778             name: 'Line',
22779             tags: {},
22780             geometry: ['line'],
22781             matchScore: 0.1
22782           });
22783           var AREA = presetPreset('area', {
22784             name: 'Area',
22785             tags: {
22786               area: 'yes'
22787             },
22788             geometry: ['area'],
22789             matchScore: 0.1
22790           });
22791           var RELATION = presetPreset('relation', {
22792             name: 'Relation',
22793             tags: {},
22794             geometry: ['relation'],
22795             matchScore: 0.1
22796           });
22797
22798           var _this = presetCollection([POINT, LINE, AREA, RELATION]);
22799
22800           var _presets = {
22801             point: POINT,
22802             line: LINE,
22803             area: AREA,
22804             relation: RELATION
22805           };
22806           var _defaults = {
22807             point: presetCollection([POINT]),
22808             vertex: presetCollection([POINT]),
22809             line: presetCollection([LINE]),
22810             area: presetCollection([AREA]),
22811             relation: presetCollection([RELATION])
22812           };
22813           var _fields = {};
22814           var _categories = {};
22815           var _universal = [];
22816           var _addablePresetIDs = null; // Set of preset IDs that the user can add
22817
22818           var _recents;
22819
22820           var _favorites; // Index of presets by (geometry, tag key).
22821
22822
22823           var _geometryIndex = {
22824             point: {},
22825             vertex: {},
22826             line: {},
22827             area: {},
22828             relation: {}
22829           };
22830
22831           var _loadPromise;
22832
22833           _this.ensureLoaded = function () {
22834             if (_loadPromise) return _loadPromise;
22835             return _loadPromise = Promise.all([_mainFileFetcher.get('preset_categories'), _mainFileFetcher.get('preset_defaults'), _mainFileFetcher.get('preset_presets'), _mainFileFetcher.get('preset_fields')]).then(function (vals) {
22836               _this.merge({
22837                 categories: vals[0],
22838                 defaults: vals[1],
22839                 presets: vals[2],
22840                 fields: vals[3]
22841               });
22842
22843               osmSetAreaKeys(_this.areaKeys());
22844               osmSetPointTags(_this.pointTags());
22845               osmSetVertexTags(_this.vertexTags());
22846             });
22847           };
22848
22849           _this.merge = function (d) {
22850             // Merge Fields
22851             if (d.fields) {
22852               Object.keys(d.fields).forEach(function (fieldID) {
22853                 var f = d.fields[fieldID];
22854
22855                 if (f) {
22856                   // add or replace
22857                   _fields[fieldID] = presetField(fieldID, f);
22858                 } else {
22859                   // remove
22860                   delete _fields[fieldID];
22861                 }
22862               });
22863             } // Merge Presets
22864
22865
22866             if (d.presets) {
22867               Object.keys(d.presets).forEach(function (presetID) {
22868                 var p = d.presets[presetID];
22869
22870                 if (p) {
22871                   // add or replace
22872                   var isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
22873
22874                   _presets[presetID] = presetPreset(presetID, p, isAddable, _fields, _presets);
22875                 } else {
22876                   // remove (but not if it's a fallback)
22877                   var existing = _presets[presetID];
22878
22879                   if (existing && !existing.isFallback()) {
22880                     delete _presets[presetID];
22881                   }
22882                 }
22883               });
22884             } // Need to rebuild _this.collection before loading categories
22885
22886
22887             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Categories
22888
22889             if (d.categories) {
22890               Object.keys(d.categories).forEach(function (categoryID) {
22891                 var c = d.categories[categoryID];
22892
22893                 if (c) {
22894                   // add or replace
22895                   _categories[categoryID] = presetCategory(categoryID, c, _this);
22896                 } else {
22897                   // remove
22898                   delete _categories[categoryID];
22899                 }
22900               });
22901             } // Rebuild _this.collection after loading categories
22902
22903
22904             _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Defaults
22905
22906             if (d.defaults) {
22907               Object.keys(d.defaults).forEach(function (geometry) {
22908                 var def = d.defaults[geometry];
22909
22910                 if (Array.isArray(def)) {
22911                   // add or replace
22912                   _defaults[geometry] = presetCollection(def.map(function (id) {
22913                     return _presets[id] || _categories[id];
22914                   }).filter(Boolean));
22915                 } else {
22916                   // remove
22917                   delete _defaults[geometry];
22918                 }
22919               });
22920             } // Rebuild universal fields array
22921
22922
22923             _universal = Object.values(_fields).filter(function (field) {
22924               return field.universal;
22925             }); // Reset all the preset fields - they'll need to be resolved again
22926
22927             Object.values(_presets).forEach(function (preset) {
22928               return preset.resetFields();
22929             }); // Rebuild geometry index
22930
22931             _geometryIndex = {
22932               point: {},
22933               vertex: {},
22934               line: {},
22935               area: {},
22936               relation: {}
22937             };
22938
22939             _this.collection.forEach(function (preset) {
22940               (preset.geometry || []).forEach(function (geometry) {
22941                 var g = _geometryIndex[geometry];
22942
22943                 for (var key in preset.tags) {
22944                   (g[key] = g[key] || []).push(preset);
22945                 }
22946               });
22947             });
22948
22949             return _this;
22950           };
22951
22952           _this.match = function (entity, resolver) {
22953             return resolver["transient"](entity, 'presetMatch', function () {
22954               var geometry = entity.geometry(resolver); // Treat entities on addr:interpolation lines as points, not vertices - #3241
22955
22956               if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
22957                 geometry = 'point';
22958               }
22959
22960               return _this.matchTags(entity.tags, geometry);
22961             });
22962           };
22963
22964           _this.matchTags = function (tags, geometry) {
22965             var geometryMatches = _geometryIndex[geometry];
22966             var address;
22967             var best = -1;
22968             var match;
22969
22970             for (var k in tags) {
22971               // If any part of an address is present, allow fallback to "Address" preset - #4353
22972               if (/^addr:/.test(k) && geometryMatches['addr:*']) {
22973                 address = geometryMatches['addr:*'][0];
22974               }
22975
22976               var keyMatches = geometryMatches[k];
22977               if (!keyMatches) continue;
22978
22979               for (var i = 0; i < keyMatches.length; i++) {
22980                 var score = keyMatches[i].matchScore(tags);
22981
22982                 if (score > best) {
22983                   best = score;
22984                   match = keyMatches[i];
22985                 }
22986               }
22987             }
22988
22989             if (address && (!match || match.isFallback())) {
22990               match = address;
22991             }
22992
22993             return match || _this.fallback(geometry);
22994           };
22995
22996           _this.allowsVertex = function (entity, resolver) {
22997             if (entity.type !== 'node') return false;
22998             if (Object.keys(entity.tags).length === 0) return true;
22999             return resolver["transient"](entity, 'vertexMatch', function () {
23000               // address lines allow vertices to act as standalone points
23001               if (entity.isOnAddressLine(resolver)) return true;
23002               var geometries = osmNodeGeometriesForTags(entity.tags);
23003               if (geometries.vertex) return true;
23004               if (geometries.point) return false; // allow vertices for unspecified points
23005
23006               return true;
23007             });
23008           }; // Because of the open nature of tagging, iD will never have a complete
23009           // list of tags used in OSM, so we want it to have logic like "assume
23010           // that a closed way with an amenity tag is an area, unless the amenity
23011           // is one of these specific types". This function computes a structure
23012           // that allows testing of such conditions, based on the presets designated
23013           // as as supporting (or not supporting) the area geometry.
23014           //
23015           // The returned object L is a keeplist/discardlist of tags. A closed way
23016           // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
23017           // (see `Way#isArea()`). In other words, the keys of L form the keeplist,
23018           // and the subkeys form the discardlist.
23019
23020
23021           _this.areaKeys = function () {
23022             // The ignore list is for keys that imply lines. (We always add `area=yes` for exceptions)
23023             var ignore = ['barrier', 'highway', 'footway', 'railway', 'junction', 'type'];
23024             var areaKeys = {}; // ignore name-suggestion-index and deprecated presets
23025
23026             var presets = _this.collection.filter(function (p) {
23027               return !p.suggestion && !p.replacement;
23028             }); // keeplist
23029
23030
23031             presets.forEach(function (p) {
23032               var keys = p.tags && Object.keys(p.tags);
23033               var key = keys && keys.length && keys[0]; // pick the first tag
23034
23035               if (!key) return;
23036               if (ignore.indexOf(key) !== -1) return;
23037
23038               if (p.geometry.indexOf('area') !== -1) {
23039                 // probably an area..
23040                 areaKeys[key] = areaKeys[key] || {};
23041               }
23042             }); // discardlist
23043
23044             presets.forEach(function (p) {
23045               var key;
23046
23047               for (key in p.addTags) {
23048                 // examine all addTags to get a better sense of what can be tagged on lines - #6800
23049                 var value = p.addTags[key];
23050
23051                 if (key in areaKeys && // probably an area...
23052                 p.geometry.indexOf('line') !== -1 && // but sometimes a line
23053                 value !== '*') {
23054                   areaKeys[key][value] = true;
23055                 }
23056               }
23057             });
23058             return areaKeys;
23059           };
23060
23061           _this.pointTags = function () {
23062             return _this.collection.reduce(function (pointTags, d) {
23063               // ignore name-suggestion-index, deprecated, and generic presets
23064               if (d.suggestion || d.replacement || d.searchable === false) return pointTags; // only care about the primary tag
23065
23066               var keys = d.tags && Object.keys(d.tags);
23067               var key = keys && keys.length && keys[0]; // pick the first tag
23068
23069               if (!key) return pointTags; // if this can be a point
23070
23071               if (d.geometry.indexOf('point') !== -1) {
23072                 pointTags[key] = pointTags[key] || {};
23073                 pointTags[key][d.tags[key]] = true;
23074               }
23075
23076               return pointTags;
23077             }, {});
23078           };
23079
23080           _this.vertexTags = function () {
23081             return _this.collection.reduce(function (vertexTags, d) {
23082               // ignore name-suggestion-index, deprecated, and generic presets
23083               if (d.suggestion || d.replacement || d.searchable === false) return vertexTags; // only care about the primary tag
23084
23085               var keys = d.tags && Object.keys(d.tags);
23086               var key = keys && keys.length && keys[0]; // pick the first tag
23087
23088               if (!key) return vertexTags; // if this can be a vertex
23089
23090               if (d.geometry.indexOf('vertex') !== -1) {
23091                 vertexTags[key] = vertexTags[key] || {};
23092                 vertexTags[key][d.tags[key]] = true;
23093               }
23094
23095               return vertexTags;
23096             }, {});
23097           };
23098
23099           _this.field = function (id) {
23100             return _fields[id];
23101           };
23102
23103           _this.universal = function () {
23104             return _universal;
23105           };
23106
23107           _this.defaults = function (geometry, n, startWithRecents) {
23108             var recents = [];
23109
23110             if (startWithRecents) {
23111               recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
23112             }
23113
23114             var defaults;
23115
23116             if (_addablePresetIDs) {
23117               defaults = Array.from(_addablePresetIDs).map(function (id) {
23118                 var preset = _this.item(id);
23119
23120                 if (preset && preset.matchGeometry(geometry)) return preset;
23121                 return null;
23122               }).filter(Boolean);
23123             } else {
23124               defaults = _defaults[geometry].collection.concat(_this.fallback(geometry));
23125             }
23126
23127             return presetCollection(utilArrayUniq(recents.concat(defaults)).slice(0, n - 1));
23128           }; // pass a Set of addable preset ids
23129
23130
23131           _this.addablePresetIDs = function (val) {
23132             if (!arguments.length) return _addablePresetIDs; // accept and convert arrays
23133
23134             if (Array.isArray(val)) val = new Set(val);
23135             _addablePresetIDs = val;
23136
23137             if (_addablePresetIDs) {
23138               // reset all presets
23139               _this.collection.forEach(function (p) {
23140                 // categories aren't addable
23141                 if (p.addable) p.addable(_addablePresetIDs.has(p.id));
23142               });
23143             } else {
23144               _this.collection.forEach(function (p) {
23145                 if (p.addable) p.addable(true);
23146               });
23147             }
23148
23149             return _this;
23150           };
23151
23152           _this.recent = function () {
23153             return presetCollection(utilArrayUniq(_this.getRecents().map(function (d) {
23154               return d.preset;
23155             })));
23156           };
23157
23158           function RibbonItem(preset, source) {
23159             var item = {};
23160             item.preset = preset;
23161             item.source = source;
23162
23163             item.isFavorite = function () {
23164               return item.source === 'favorite';
23165             };
23166
23167             item.isRecent = function () {
23168               return item.source === 'recent';
23169             };
23170
23171             item.matches = function (preset) {
23172               return item.preset.id === preset.id;
23173             };
23174
23175             item.minified = function () {
23176               return {
23177                 pID: item.preset.id
23178               };
23179             };
23180
23181             return item;
23182           }
23183
23184           function ribbonItemForMinified(d, source) {
23185             if (d && d.pID) {
23186               var preset = _this.item(d.pID);
23187
23188               if (!preset) return null;
23189               return RibbonItem(preset, source);
23190             }
23191
23192             return null;
23193           }
23194
23195           _this.getGenericRibbonItems = function () {
23196             return ['point', 'line', 'area'].map(function (id) {
23197               return RibbonItem(_this.item(id), 'generic');
23198             });
23199           };
23200
23201           _this.getAddable = function () {
23202             if (!_addablePresetIDs) return [];
23203             return _addablePresetIDs.map(function (id) {
23204               var preset = _this.item(id);
23205
23206               if (preset) return RibbonItem(preset, 'addable');
23207               return null;
23208             }).filter(Boolean);
23209           };
23210
23211           function setRecents(items) {
23212             _recents = items;
23213             var minifiedItems = items.map(function (d) {
23214               return d.minified();
23215             });
23216             corePreferences('preset_recents', JSON.stringify(minifiedItems));
23217             dispatch$1.call('recentsChange');
23218           }
23219
23220           _this.getRecents = function () {
23221             if (!_recents) {
23222               // fetch from local storage
23223               _recents = (JSON.parse(corePreferences('preset_recents')) || []).reduce(function (acc, d) {
23224                 var item = ribbonItemForMinified(d, 'recent');
23225                 if (item && item.preset.addable()) acc.push(item);
23226                 return acc;
23227               }, []);
23228             }
23229
23230             return _recents;
23231           };
23232
23233           _this.addRecent = function (preset, besidePreset, after) {
23234             var recents = _this.getRecents();
23235
23236             var beforeItem = _this.recentMatching(besidePreset);
23237
23238             var toIndex = recents.indexOf(beforeItem);
23239             if (after) toIndex += 1;
23240             var newItem = RibbonItem(preset, 'recent');
23241             recents.splice(toIndex, 0, newItem);
23242             setRecents(recents);
23243           };
23244
23245           _this.removeRecent = function (preset) {
23246             var item = _this.recentMatching(preset);
23247
23248             if (item) {
23249               var items = _this.getRecents();
23250
23251               items.splice(items.indexOf(item), 1);
23252               setRecents(items);
23253             }
23254           };
23255
23256           _this.recentMatching = function (preset) {
23257             var items = _this.getRecents();
23258
23259             for (var i in items) {
23260               if (items[i].matches(preset)) {
23261                 return items[i];
23262               }
23263             }
23264
23265             return null;
23266           };
23267
23268           _this.moveItem = function (items, fromIndex, toIndex) {
23269             if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
23270             items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
23271             return items;
23272           };
23273
23274           _this.moveRecent = function (item, beforeItem) {
23275             var recents = _this.getRecents();
23276
23277             var fromIndex = recents.indexOf(item);
23278             var toIndex = recents.indexOf(beforeItem);
23279
23280             var items = _this.moveItem(recents, fromIndex, toIndex);
23281
23282             if (items) setRecents(items);
23283           };
23284
23285           _this.setMostRecent = function (preset) {
23286             if (preset.searchable === false) return;
23287
23288             var items = _this.getRecents();
23289
23290             var item = _this.recentMatching(preset);
23291
23292             if (item) {
23293               items.splice(items.indexOf(item), 1);
23294             } else {
23295               item = RibbonItem(preset, 'recent');
23296             } // remove the last recent (first in, first out)
23297
23298
23299             while (items.length >= MAXRECENTS) {
23300               items.pop();
23301             } // prepend array
23302
23303
23304             items.unshift(item);
23305             setRecents(items);
23306           };
23307
23308           function setFavorites(items) {
23309             _favorites = items;
23310             var minifiedItems = items.map(function (d) {
23311               return d.minified();
23312             });
23313             corePreferences('preset_favorites', JSON.stringify(minifiedItems)); // call update
23314
23315             dispatch$1.call('favoritePreset');
23316           }
23317
23318           _this.addFavorite = function (preset, besidePreset, after) {
23319             var favorites = _this.getFavorites();
23320
23321             var beforeItem = _this.favoriteMatching(besidePreset);
23322
23323             var toIndex = favorites.indexOf(beforeItem);
23324             if (after) toIndex += 1;
23325             var newItem = RibbonItem(preset, 'favorite');
23326             favorites.splice(toIndex, 0, newItem);
23327             setFavorites(favorites);
23328           };
23329
23330           _this.toggleFavorite = function (preset) {
23331             var favs = _this.getFavorites();
23332
23333             var favorite = _this.favoriteMatching(preset);
23334
23335             if (favorite) {
23336               favs.splice(favs.indexOf(favorite), 1);
23337             } else {
23338               // only allow 10 favorites
23339               if (favs.length === 10) {
23340                 // remove the last favorite (last in, first out)
23341                 favs.pop();
23342               } // append array
23343
23344
23345               favs.push(RibbonItem(preset, 'favorite'));
23346             }
23347
23348             setFavorites(favs);
23349           };
23350
23351           _this.removeFavorite = function (preset) {
23352             var item = _this.favoriteMatching(preset);
23353
23354             if (item) {
23355               var items = _this.getFavorites();
23356
23357               items.splice(items.indexOf(item), 1);
23358               setFavorites(items);
23359             }
23360           };
23361
23362           _this.getFavorites = function () {
23363             if (!_favorites) {
23364               // fetch from local storage
23365               var rawFavorites = JSON.parse(corePreferences('preset_favorites'));
23366
23367               if (!rawFavorites) {
23368                 rawFavorites = [];
23369                 corePreferences('preset_favorites', JSON.stringify(rawFavorites));
23370               }
23371
23372               _favorites = rawFavorites.reduce(function (output, d) {
23373                 var item = ribbonItemForMinified(d, 'favorite');
23374                 if (item && item.preset.addable()) output.push(item);
23375                 return output;
23376               }, []);
23377             }
23378
23379             return _favorites;
23380           };
23381
23382           _this.favoriteMatching = function (preset) {
23383             var favs = _this.getFavorites();
23384
23385             for (var index in favs) {
23386               if (favs[index].matches(preset)) {
23387                 return favs[index];
23388               }
23389             }
23390
23391             return null;
23392           };
23393
23394           return utilRebind(_this, dispatch$1, 'on');
23395         }
23396
23397         function utilTagText(entity) {
23398           var obj = entity && entity.tags || {};
23399           return Object.keys(obj).map(function (k) {
23400             return k + '=' + obj[k];
23401           }).join(', ');
23402         }
23403         function utilTotalExtent(array, graph) {
23404           var extent = geoExtent();
23405           var val, entity;
23406
23407           for (var i = 0; i < array.length; i++) {
23408             val = array[i];
23409             entity = typeof val === 'string' ? graph.hasEntity(val) : val;
23410
23411             if (entity) {
23412               extent._extend(entity.extent(graph));
23413             }
23414           }
23415
23416           return extent;
23417         }
23418         function utilTagDiff(oldTags, newTags) {
23419           var tagDiff = [];
23420           var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
23421           keys.forEach(function (k) {
23422             var oldVal = oldTags[k];
23423             var newVal = newTags[k];
23424
23425             if ((oldVal || oldVal === '') && (newVal === undefined || newVal !== oldVal)) {
23426               tagDiff.push({
23427                 type: '-',
23428                 key: k,
23429                 oldVal: oldVal,
23430                 newVal: newVal,
23431                 display: '- ' + k + '=' + oldVal
23432               });
23433             }
23434
23435             if ((newVal || newVal === '') && (oldVal === undefined || newVal !== oldVal)) {
23436               tagDiff.push({
23437                 type: '+',
23438                 key: k,
23439                 oldVal: oldVal,
23440                 newVal: newVal,
23441                 display: '+ ' + k + '=' + newVal
23442               });
23443             }
23444           });
23445           return tagDiff;
23446         }
23447         function utilEntitySelector(ids) {
23448           return ids.length ? '.' + ids.join(',.') : 'nothing';
23449         } // returns an selector to select entity ids for:
23450         //  - entityIDs passed in
23451         //  - shallow descendant entityIDs for any of those entities that are relations
23452
23453         function utilEntityOrMemberSelector(ids, graph) {
23454           var seen = new Set(ids);
23455           ids.forEach(collectShallowDescendants);
23456           return utilEntitySelector(Array.from(seen));
23457
23458           function collectShallowDescendants(id) {
23459             var entity = graph.hasEntity(id);
23460             if (!entity || entity.type !== 'relation') return;
23461             entity.members.map(function (member) {
23462               return member.id;
23463             }).forEach(function (id) {
23464               seen.add(id);
23465             });
23466           }
23467         } // returns an selector to select entity ids for:
23468         //  - entityIDs passed in
23469         //  - deep descendant entityIDs for any of those entities that are relations
23470
23471         function utilEntityOrDeepMemberSelector(ids, graph) {
23472           return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
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 utilEntityAndDeepMemberIDs(ids, graph) {
23478           var seen = new Set();
23479           ids.forEach(collectDeepDescendants);
23480           return Array.from(seen);
23481
23482           function collectDeepDescendants(id) {
23483             if (seen.has(id)) return;
23484             seen.add(id);
23485             var entity = graph.hasEntity(id);
23486             if (!entity || entity.type !== 'relation') return;
23487             entity.members.map(function (member) {
23488               return member.id;
23489             }).forEach(collectDeepDescendants); // recurse
23490           }
23491         } // returns an selector to select entity ids for:
23492         //  - deep descendant entityIDs for any of those entities that are relations
23493
23494         function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
23495           var idsSet = new Set(ids);
23496           var seen = new Set();
23497           var returners = new Set();
23498           ids.forEach(collectDeepDescendants);
23499           return utilEntitySelector(Array.from(returners));
23500
23501           function collectDeepDescendants(id) {
23502             if (seen.has(id)) return;
23503             seen.add(id);
23504
23505             if (!idsSet.has(id)) {
23506               returners.add(id);
23507             }
23508
23509             var entity = graph.hasEntity(id);
23510             if (!entity || entity.type !== 'relation') return;
23511             if (skipMultipolgonMembers && entity.isMultipolygon()) return;
23512             entity.members.map(function (member) {
23513               return member.id;
23514             }).forEach(collectDeepDescendants); // recurse
23515           }
23516         } // Adds or removes highlight styling for the specified entities
23517
23518         function utilHighlightEntities(ids, highlighted, context) {
23519           context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed('highlighted', highlighted);
23520         } // returns an Array that is the union of:
23521         //  - nodes for any nodeIDs passed in
23522         //  - child nodes of any wayIDs passed in
23523         //  - descendant member and child nodes of relationIDs passed in
23524
23525         function utilGetAllNodes(ids, graph) {
23526           var seen = new Set();
23527           var nodes = new Set();
23528           ids.forEach(collectNodes);
23529           return Array.from(nodes);
23530
23531           function collectNodes(id) {
23532             if (seen.has(id)) return;
23533             seen.add(id);
23534             var entity = graph.hasEntity(id);
23535             if (!entity) return;
23536
23537             if (entity.type === 'node') {
23538               nodes.add(entity);
23539             } else if (entity.type === 'way') {
23540               entity.nodes.forEach(collectNodes);
23541             } else {
23542               entity.members.map(function (member) {
23543                 return member.id;
23544               }).forEach(collectNodes); // recurse
23545             }
23546           }
23547         }
23548         function utilDisplayName(entity) {
23549           var localizedNameKey = 'name:' + _mainLocalizer.languageCode().toLowerCase();
23550           var name = entity.tags[localizedNameKey] || entity.tags.name || '';
23551           var network = entity.tags.cycle_network || entity.tags.network;
23552
23553           if (!name && entity.tags.ref) {
23554             name = entity.tags.ref;
23555
23556             if (network) {
23557               name = network + ' ' + name;
23558             }
23559           }
23560
23561           return name;
23562         }
23563         function utilDisplayNameForPath(entity) {
23564           var name = utilDisplayName(entity);
23565           var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
23566
23567           if (!isFirefox && name && rtlRegex.test(name)) {
23568             name = fixRTLTextForSvg(name);
23569           }
23570
23571           return name;
23572         }
23573         function utilDisplayType(id) {
23574           return {
23575             n: _t('inspector.node'),
23576             w: _t('inspector.way'),
23577             r: _t('inspector.relation')
23578           }[id.charAt(0)];
23579         }
23580         function utilDisplayLabel(entity, graphOrGeometry) {
23581           var displayName = utilDisplayName(entity);
23582
23583           if (displayName) {
23584             // use the display name if there is one
23585             return displayName;
23586           }
23587
23588           var preset = typeof graphOrGeometry === 'string' ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
23589
23590           if (preset && preset.name()) {
23591             // use the preset name if there is a match
23592             return preset.name();
23593           } // fallback to the display type (node/way/relation)
23594
23595
23596           return utilDisplayType(entity.id);
23597         }
23598         function utilEntityRoot(entityType) {
23599           return {
23600             node: 'n',
23601             way: 'w',
23602             relation: 'r'
23603           }[entityType];
23604         } // Returns a single object containing the tags of all the given entities.
23605         // Example:
23606         // {
23607         //   highway: 'service',
23608         //   service: 'parking_aisle'
23609         // }
23610         //           +
23611         // {
23612         //   highway: 'service',
23613         //   service: 'driveway',
23614         //   width: '3'
23615         // }
23616         //           =
23617         // {
23618         //   highway: 'service',
23619         //   service: [ 'driveway', 'parking_aisle' ],
23620         //   width: [ '3', undefined ]
23621         // }
23622
23623         function utilCombinedTags(entityIDs, graph) {
23624           var tags = {};
23625           var tagCounts = {};
23626           var allKeys = new Set();
23627           var entities = entityIDs.map(function (entityID) {
23628             return graph.hasEntity(entityID);
23629           }).filter(Boolean); // gather the aggregate keys
23630
23631           entities.forEach(function (entity) {
23632             var keys = Object.keys(entity.tags).filter(Boolean);
23633             keys.forEach(function (key) {
23634               allKeys.add(key);
23635             });
23636           });
23637           entities.forEach(function (entity) {
23638             allKeys.forEach(function (key) {
23639               var value = entity.tags[key]; // purposely allow `undefined`
23640
23641               if (!tags.hasOwnProperty(key)) {
23642                 // first value, set as raw
23643                 tags[key] = value;
23644               } else {
23645                 if (!Array.isArray(tags[key])) {
23646                   if (tags[key] !== value) {
23647                     // first alternate value, replace single value with array
23648                     tags[key] = [tags[key], value];
23649                   }
23650                 } else {
23651                   // type is array
23652                   if (tags[key].indexOf(value) === -1) {
23653                     // subsequent alternate value, add to array
23654                     tags[key].push(value);
23655                   }
23656                 }
23657               }
23658
23659               var tagHash = key + '=' + value;
23660               if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
23661               tagCounts[tagHash] += 1;
23662             });
23663           });
23664
23665           for (var key in tags) {
23666             if (!Array.isArray(tags[key])) continue; // sort values by frequency then alphabetically
23667
23668             tags[key] = tags[key].sort(function (val1, val2) {
23669               var key = key; // capture
23670
23671               var count2 = tagCounts[key + '=' + val2];
23672               var count1 = tagCounts[key + '=' + val1];
23673
23674               if (count2 !== count1) {
23675                 return count2 - count1;
23676               }
23677
23678               if (val2 && val1) {
23679                 return val1.localeCompare(val2);
23680               }
23681
23682               return val1 ? 1 : -1;
23683             });
23684           }
23685
23686           return tags;
23687         }
23688         function utilStringQs(str) {
23689           var i = 0; // advance past any leading '?' or '#' characters
23690
23691           while (i < str.length && (str[i] === '?' || str[i] === '#')) {
23692             i++;
23693           }
23694
23695           str = str.slice(i);
23696           return str.split('&').reduce(function (obj, pair) {
23697             var parts = pair.split('=');
23698
23699             if (parts.length === 2) {
23700               obj[parts[0]] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
23701             }
23702
23703             return obj;
23704           }, {});
23705         }
23706         function utilQsString(obj, noencode) {
23707           // encode everything except special characters used in certain hash parameters:
23708           // "/" in map states, ":", ",", {" and "}" in background
23709           function softEncode(s) {
23710             return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
23711           }
23712
23713           return Object.keys(obj).sort().map(function (key) {
23714             return encodeURIComponent(key) + '=' + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
23715           }).join('&');
23716         }
23717         function utilPrefixDOMProperty(property) {
23718           var prefixes = ['webkit', 'ms', 'moz', 'o'];
23719           var i = -1;
23720           var n = prefixes.length;
23721           var s = document.body;
23722           if (property in s) return property;
23723           property = property.substr(0, 1).toUpperCase() + property.substr(1);
23724
23725           while (++i < n) {
23726             if (prefixes[i] + property in s) {
23727               return prefixes[i] + property;
23728             }
23729           }
23730
23731           return false;
23732         }
23733         function utilPrefixCSSProperty(property) {
23734           var prefixes = ['webkit', 'ms', 'Moz', 'O'];
23735           var i = -1;
23736           var n = prefixes.length;
23737           var s = document.body.style;
23738
23739           if (property.toLowerCase() in s) {
23740             return property.toLowerCase();
23741           }
23742
23743           while (++i < n) {
23744             if (prefixes[i] + property in s) {
23745               return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
23746             }
23747           }
23748
23749           return false;
23750         }
23751         var transformProperty;
23752         function utilSetTransform(el, x, y, scale) {
23753           var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform');
23754           var translate = utilDetect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)';
23755           return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
23756         } // Calculates Levenshtein distance between two strings
23757         // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
23758         // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
23759
23760         function utilEditDistance(a, b) {
23761           a = remove$1(a.toLowerCase());
23762           b = remove$1(b.toLowerCase());
23763           if (a.length === 0) return b.length;
23764           if (b.length === 0) return a.length;
23765           var matrix = [];
23766           var i, j;
23767
23768           for (i = 0; i <= b.length; i++) {
23769             matrix[i] = [i];
23770           }
23771
23772           for (j = 0; j <= a.length; j++) {
23773             matrix[0][j] = j;
23774           }
23775
23776           for (i = 1; i <= b.length; i++) {
23777             for (j = 1; j <= a.length; j++) {
23778               if (b.charAt(i - 1) === a.charAt(j - 1)) {
23779                 matrix[i][j] = matrix[i - 1][j - 1];
23780               } else {
23781                 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
23782                 Math.min(matrix[i][j - 1] + 1, // insertion
23783                 matrix[i - 1][j] + 1)); // deletion
23784               }
23785             }
23786           }
23787
23788           return matrix[b.length][a.length];
23789         } // a d3.mouse-alike which
23790         // 1. Only works on HTML elements, not SVG
23791         // 2. Does not cause style recalculation
23792
23793         function utilFastMouse(container) {
23794           var rect = container.getBoundingClientRect();
23795           var rectLeft = rect.left;
23796           var rectTop = rect.top;
23797           var clientLeft = +container.clientLeft;
23798           var clientTop = +container.clientTop;
23799           return function (e) {
23800             return [e.clientX - rectLeft - clientLeft, e.clientY - rectTop - clientTop];
23801           };
23802         }
23803         function utilAsyncMap(inputs, func, callback) {
23804           var remaining = inputs.length;
23805           var results = [];
23806           var errors = [];
23807           inputs.forEach(function (d, i) {
23808             func(d, function done(err, data) {
23809               errors[i] = err;
23810               results[i] = data;
23811               remaining--;
23812               if (!remaining) callback(errors, results);
23813             });
23814           });
23815         } // wraps an index to an interval [0..length-1]
23816
23817         function utilWrap(index, length) {
23818           if (index < 0) {
23819             index += Math.ceil(-index / length) * length;
23820           }
23821
23822           return index % length;
23823         }
23824         /**
23825          * a replacement for functor
23826          *
23827          * @param {*} value any value
23828          * @returns {Function} a function that returns that value or the value if it's a function
23829          */
23830
23831         function utilFunctor(value) {
23832           if (typeof value === 'function') return value;
23833           return function () {
23834             return value;
23835           };
23836         }
23837         function utilNoAuto(selection) {
23838           var isText = selection.size() && selection.node().tagName.toLowerCase() === 'textarea';
23839           return selection // assign 'new-password' even for non-password fields to prevent browsers (Chrome) ignoring 'off'
23840           .attr('autocomplete', 'new-password').attr('autocorrect', 'off').attr('autocapitalize', 'off').attr('spellcheck', isText ? 'true' : 'false');
23841         } // https://stackoverflow.com/questions/194846/is-there-any-kind-of-hash-code-function-in-javascript
23842         // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
23843
23844         function utilHashcode(str) {
23845           var hash = 0;
23846
23847           if (str.length === 0) {
23848             return hash;
23849           }
23850
23851           for (var i = 0; i < str.length; i++) {
23852             var _char = str.charCodeAt(i);
23853
23854             hash = (hash << 5) - hash + _char;
23855             hash = hash & hash; // Convert to 32bit integer
23856           }
23857
23858           return hash;
23859         } // Returns version of `str` with all runs of special characters replaced by `_`;
23860         // suitable for HTML ids, classes, selectors, etc.
23861
23862         function utilSafeClassName(str) {
23863           return str.toLowerCase().replace(/[^a-z0-9]+/g, '_');
23864         } // Returns string based on `val` that is highly unlikely to collide with an id
23865         // used previously or that's present elsewhere in the document. Useful for preventing
23866         // browser-provided autofills or when embedding iD on pages with unknown elements.
23867
23868         function utilUniqueDomId(val) {
23869           return 'ideditor-' + utilSafeClassName(val.toString()) + '-' + new Date().getTime().toString();
23870         } // Returns the length of `str` in unicode characters. This can be less than
23871         // `String.length()` since a single unicode character can be composed of multiple
23872         // JavaScript UTF-16 code units.
23873
23874         function utilUnicodeCharsCount(str) {
23875           // Native ES2015 implementations of `Array.from` split strings into unicode characters
23876           return Array.from(str).length;
23877         } // Returns a new string representing `str` cut from its start to `limit` length
23878         // in unicode characters. Note that this runs the risk of splitting graphemes.
23879
23880         function utilUnicodeCharsTruncated(str, limit) {
23881           return Array.from(str).slice(0, limit).join('');
23882         }
23883
23884         function osmEntity(attrs) {
23885           // For prototypal inheritance.
23886           if (this instanceof osmEntity) return; // Create the appropriate subtype.
23887
23888           if (attrs && attrs.type) {
23889             return osmEntity[attrs.type].apply(this, arguments);
23890           } else if (attrs && attrs.id) {
23891             return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
23892           } // Initialize a generic Entity (used only in tests).
23893
23894
23895           return new osmEntity().initialize(arguments);
23896         }
23897
23898         osmEntity.id = function (type) {
23899           return osmEntity.id.fromOSM(type, osmEntity.id.next[type]--);
23900         };
23901
23902         osmEntity.id.next = {
23903           changeset: -1,
23904           node: -1,
23905           way: -1,
23906           relation: -1
23907         };
23908
23909         osmEntity.id.fromOSM = function (type, id) {
23910           return type[0] + id;
23911         };
23912
23913         osmEntity.id.toOSM = function (id) {
23914           return id.slice(1);
23915         };
23916
23917         osmEntity.id.type = function (id) {
23918           return {
23919             'c': 'changeset',
23920             'n': 'node',
23921             'w': 'way',
23922             'r': 'relation'
23923           }[id[0]];
23924         }; // A function suitable for use as the second argument to d3.selection#data().
23925
23926
23927         osmEntity.key = function (entity) {
23928           return entity.id + 'v' + (entity.v || 0);
23929         };
23930
23931         var _deprecatedTagValuesByKey;
23932
23933         osmEntity.deprecatedTagValuesByKey = function (dataDeprecated) {
23934           if (!_deprecatedTagValuesByKey) {
23935             _deprecatedTagValuesByKey = {};
23936             dataDeprecated.forEach(function (d) {
23937               var oldKeys = Object.keys(d.old);
23938
23939               if (oldKeys.length === 1) {
23940                 var oldKey = oldKeys[0];
23941                 var oldValue = d.old[oldKey];
23942
23943                 if (oldValue !== '*') {
23944                   if (!_deprecatedTagValuesByKey[oldKey]) {
23945                     _deprecatedTagValuesByKey[oldKey] = [oldValue];
23946                   } else {
23947                     _deprecatedTagValuesByKey[oldKey].push(oldValue);
23948                   }
23949                 }
23950               }
23951             });
23952           }
23953
23954           return _deprecatedTagValuesByKey;
23955         };
23956
23957         osmEntity.prototype = {
23958           tags: {},
23959           initialize: function initialize(sources) {
23960             for (var i = 0; i < sources.length; ++i) {
23961               var source = sources[i];
23962
23963               for (var prop in source) {
23964                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
23965                   if (source[prop] === undefined) {
23966                     delete this[prop];
23967                   } else {
23968                     this[prop] = source[prop];
23969                   }
23970                 }
23971               }
23972             }
23973
23974             if (!this.id && this.type) {
23975               this.id = osmEntity.id(this.type);
23976             }
23977
23978             if (!this.hasOwnProperty('visible')) {
23979               this.visible = true;
23980             }
23981
23982             return this;
23983           },
23984           copy: function copy(resolver, copies) {
23985             if (copies[this.id]) return copies[this.id];
23986             var copy = osmEntity(this, {
23987               id: undefined,
23988               user: undefined,
23989               version: undefined
23990             });
23991             copies[this.id] = copy;
23992             return copy;
23993           },
23994           osmId: function osmId() {
23995             return osmEntity.id.toOSM(this.id);
23996           },
23997           isNew: function isNew() {
23998             return this.osmId() < 0;
23999           },
24000           update: function update(attrs) {
24001             return osmEntity(this, attrs, {
24002               v: 1 + (this.v || 0)
24003             });
24004           },
24005           mergeTags: function mergeTags(tags) {
24006             var merged = Object.assign({}, this.tags); // shallow copy
24007
24008             var changed = false;
24009
24010             for (var k in tags) {
24011               var t1 = merged[k];
24012               var t2 = tags[k];
24013
24014               if (!t1) {
24015                 changed = true;
24016                 merged[k] = t2;
24017               } else if (t1 !== t2) {
24018                 changed = true;
24019                 merged[k] = utilUnicodeCharsTruncated(utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(';'), 255 // avoid exceeding character limit; see also services/osm.js -> maxCharsForTagValue()
24020                 );
24021               }
24022             }
24023
24024             return changed ? this.update({
24025               tags: merged
24026             }) : this;
24027           },
24028           intersects: function intersects(extent, resolver) {
24029             return this.extent(resolver).intersects(extent);
24030           },
24031           hasNonGeometryTags: function hasNonGeometryTags() {
24032             return Object.keys(this.tags).some(function (k) {
24033               return k !== 'area';
24034             });
24035           },
24036           hasParentRelations: function hasParentRelations(resolver) {
24037             return resolver.parentRelations(this).length > 0;
24038           },
24039           hasInterestingTags: function hasInterestingTags() {
24040             return Object.keys(this.tags).some(osmIsInterestingTag);
24041           },
24042           hasWikidata: function hasWikidata() {
24043             return !!this.tags.wikidata || !!this.tags['brand:wikidata'];
24044           },
24045           isHighwayIntersection: function isHighwayIntersection() {
24046             return false;
24047           },
24048           isDegenerate: function isDegenerate() {
24049             return true;
24050           },
24051           deprecatedTags: function deprecatedTags(dataDeprecated) {
24052             var tags = this.tags; // if there are no tags, none can be deprecated
24053
24054             if (Object.keys(tags).length === 0) return [];
24055             var deprecated = [];
24056             dataDeprecated.forEach(function (d) {
24057               var oldKeys = Object.keys(d.old);
24058
24059               if (d.replace) {
24060                 var hasExistingValues = Object.keys(d.replace).some(function (replaceKey) {
24061                   if (!tags[replaceKey] || d.old[replaceKey]) return false;
24062                   var replaceValue = d.replace[replaceKey];
24063                   if (replaceValue === '*') return false;
24064                   if (replaceValue === tags[replaceKey]) return false;
24065                   return true;
24066                 }); // don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
24067
24068                 if (hasExistingValues) return;
24069               }
24070
24071               var matchesDeprecatedTags = oldKeys.every(function (oldKey) {
24072                 if (!tags[oldKey]) return false;
24073                 if (d.old[oldKey] === '*') return true;
24074                 if (d.old[oldKey] === tags[oldKey]) return true;
24075                 var vals = tags[oldKey].split(';').filter(Boolean);
24076
24077                 if (vals.length === 0) {
24078                   return false;
24079                 } else if (vals.length > 1) {
24080                   return vals.indexOf(d.old[oldKey]) !== -1;
24081                 } else {
24082                   if (tags[oldKey] === d.old[oldKey]) {
24083                     if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
24084                       var replaceKeys = Object.keys(d.replace);
24085                       return !replaceKeys.every(function (replaceKey) {
24086                         return tags[replaceKey] === d.replace[replaceKey];
24087                       });
24088                     } else {
24089                       return true;
24090                     }
24091                   }
24092                 }
24093
24094                 return false;
24095               });
24096
24097               if (matchesDeprecatedTags) {
24098                 deprecated.push(d);
24099               }
24100             });
24101             return deprecated;
24102           }
24103         };
24104
24105         function osmLanes(entity) {
24106           if (entity.type !== 'way') return null;
24107           if (!entity.tags.highway) return null;
24108           var tags = entity.tags;
24109           var isOneWay = entity.isOneWay();
24110           var laneCount = getLaneCount(tags, isOneWay);
24111           var maxspeed = parseMaxspeed(tags);
24112           var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
24113           var forward = laneDirections.forward;
24114           var backward = laneDirections.backward;
24115           var bothways = laneDirections.bothways; // parse the piped string 'x|y|z' format
24116
24117           var turnLanes = {};
24118           turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
24119           turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
24120           turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
24121           var maxspeedLanes = {};
24122           maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
24123           maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
24124           maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
24125           var psvLanes = {};
24126           psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
24127           psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
24128           psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
24129           var busLanes = {};
24130           busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
24131           busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
24132           busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
24133           var taxiLanes = {};
24134           taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
24135           taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
24136           taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
24137           var hovLanes = {};
24138           hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
24139           hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
24140           hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
24141           var hgvLanes = {};
24142           hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
24143           hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
24144           hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
24145           var bicyclewayLanes = {};
24146           bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
24147           bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
24148           bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
24149           var lanesObj = {
24150             forward: [],
24151             backward: [],
24152             unspecified: []
24153           }; // map forward/backward/unspecified of each lane type to lanesObj
24154
24155           mapToLanesObj(lanesObj, turnLanes, 'turnLane');
24156           mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
24157           mapToLanesObj(lanesObj, psvLanes, 'psv');
24158           mapToLanesObj(lanesObj, busLanes, 'bus');
24159           mapToLanesObj(lanesObj, taxiLanes, 'taxi');
24160           mapToLanesObj(lanesObj, hovLanes, 'hov');
24161           mapToLanesObj(lanesObj, hgvLanes, 'hgv');
24162           mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
24163           return {
24164             metadata: {
24165               count: laneCount,
24166               oneway: isOneWay,
24167               forward: forward,
24168               backward: backward,
24169               bothways: bothways,
24170               turnLanes: turnLanes,
24171               maxspeed: maxspeed,
24172               maxspeedLanes: maxspeedLanes,
24173               psvLanes: psvLanes,
24174               busLanes: busLanes,
24175               taxiLanes: taxiLanes,
24176               hovLanes: hovLanes,
24177               hgvLanes: hgvLanes,
24178               bicyclewayLanes: bicyclewayLanes
24179             },
24180             lanes: lanesObj
24181           };
24182         }
24183
24184         function getLaneCount(tags, isOneWay) {
24185           var count;
24186
24187           if (tags.lanes) {
24188             count = parseInt(tags.lanes, 10);
24189
24190             if (count > 0) {
24191               return count;
24192             }
24193           }
24194
24195           switch (tags.highway) {
24196             case 'trunk':
24197             case 'motorway':
24198               count = isOneWay ? 2 : 4;
24199               break;
24200
24201             default:
24202               count = isOneWay ? 1 : 2;
24203               break;
24204           }
24205
24206           return count;
24207         }
24208
24209         function parseMaxspeed(tags) {
24210           var maxspeed = tags.maxspeed;
24211           if (!maxspeed) return;
24212           var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
24213           if (!maxspeedRegex.test(maxspeed)) return;
24214           return parseInt(maxspeed, 10);
24215         }
24216
24217         function parseLaneDirections(tags, isOneWay, laneCount) {
24218           var forward = parseInt(tags['lanes:forward'], 10);
24219           var backward = parseInt(tags['lanes:backward'], 10);
24220           var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
24221
24222           if (parseInt(tags.oneway, 10) === -1) {
24223             forward = 0;
24224             bothways = 0;
24225             backward = laneCount;
24226           } else if (isOneWay) {
24227             forward = laneCount;
24228             bothways = 0;
24229             backward = 0;
24230           } else if (isNaN(forward) && isNaN(backward)) {
24231             backward = Math.floor((laneCount - bothways) / 2);
24232             forward = laneCount - bothways - backward;
24233           } else if (isNaN(forward)) {
24234             if (backward > laneCount - bothways) {
24235               backward = laneCount - bothways;
24236             }
24237
24238             forward = laneCount - bothways - backward;
24239           } else if (isNaN(backward)) {
24240             if (forward > laneCount - bothways) {
24241               forward = laneCount - bothways;
24242             }
24243
24244             backward = laneCount - bothways - forward;
24245           }
24246
24247           return {
24248             forward: forward,
24249             backward: backward,
24250             bothways: bothways
24251           };
24252         }
24253
24254         function parseTurnLanes(tag) {
24255           if (!tag) return;
24256           var validValues = ['left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right', 'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'];
24257           return tag.split('|').map(function (s) {
24258             if (s === '') s = 'none';
24259             return s.split(';').map(function (d) {
24260               return validValues.indexOf(d) === -1 ? 'unknown' : d;
24261             });
24262           });
24263         }
24264
24265         function parseMaxspeedLanes(tag, maxspeed) {
24266           if (!tag) return;
24267           return tag.split('|').map(function (s) {
24268             if (s === 'none') return s;
24269             var m = parseInt(s, 10);
24270             if (s === '' || m === maxspeed) return null;
24271             return isNaN(m) ? 'unknown' : m;
24272           });
24273         }
24274
24275         function parseMiscLanes(tag) {
24276           if (!tag) return;
24277           var validValues = ['yes', 'no', 'designated'];
24278           return tag.split('|').map(function (s) {
24279             if (s === '') s = 'no';
24280             return validValues.indexOf(s) === -1 ? 'unknown' : s;
24281           });
24282         }
24283
24284         function parseBicycleWay(tag) {
24285           if (!tag) return;
24286           var validValues = ['yes', 'no', 'designated', 'lane'];
24287           return tag.split('|').map(function (s) {
24288             if (s === '') s = 'no';
24289             return validValues.indexOf(s) === -1 ? 'unknown' : s;
24290           });
24291         }
24292
24293         function mapToLanesObj(lanesObj, data, key) {
24294           if (data.forward) data.forward.forEach(function (l, i) {
24295             if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
24296             lanesObj.forward[i][key] = l;
24297           });
24298           if (data.backward) data.backward.forEach(function (l, i) {
24299             if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
24300             lanesObj.backward[i][key] = l;
24301           });
24302           if (data.unspecified) data.unspecified.forEach(function (l, i) {
24303             if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
24304             lanesObj.unspecified[i][key] = l;
24305           });
24306         }
24307
24308         function osmWay() {
24309           if (!(this instanceof osmWay)) {
24310             return new osmWay().initialize(arguments);
24311           } else if (arguments.length) {
24312             this.initialize(arguments);
24313           }
24314         }
24315         osmEntity.way = osmWay;
24316         osmWay.prototype = Object.create(osmEntity.prototype);
24317         Object.assign(osmWay.prototype, {
24318           type: 'way',
24319           nodes: [],
24320           copy: function copy(resolver, copies) {
24321             if (copies[this.id]) return copies[this.id];
24322             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
24323             var nodes = this.nodes.map(function (id) {
24324               return resolver.entity(id).copy(resolver, copies).id;
24325             });
24326             copy = copy.update({
24327               nodes: nodes
24328             });
24329             copies[this.id] = copy;
24330             return copy;
24331           },
24332           extent: function extent(resolver) {
24333             return resolver["transient"](this, 'extent', function () {
24334               var extent = geoExtent();
24335
24336               for (var i = 0; i < this.nodes.length; i++) {
24337                 var node = resolver.hasEntity(this.nodes[i]);
24338
24339                 if (node) {
24340                   extent._extend(node.extent());
24341                 }
24342               }
24343
24344               return extent;
24345             });
24346           },
24347           first: function first() {
24348             return this.nodes[0];
24349           },
24350           last: function last() {
24351             return this.nodes[this.nodes.length - 1];
24352           },
24353           contains: function contains(node) {
24354             return this.nodes.indexOf(node) >= 0;
24355           },
24356           affix: function affix(node) {
24357             if (this.nodes[0] === node) return 'prefix';
24358             if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
24359           },
24360           layer: function layer() {
24361             // explicit layer tag, clamp between -10, 10..
24362             if (isFinite(this.tags.layer)) {
24363               return Math.max(-10, Math.min(+this.tags.layer, 10));
24364             } // implied layer tag..
24365
24366
24367             if (this.tags.covered === 'yes') return -1;
24368             if (this.tags.location === 'overground') return 1;
24369             if (this.tags.location === 'underground') return -1;
24370             if (this.tags.location === 'underwater') return -10;
24371             if (this.tags.power === 'line') return 10;
24372             if (this.tags.power === 'minor_line') return 10;
24373             if (this.tags.aerialway) return 10;
24374             if (this.tags.bridge) return 1;
24375             if (this.tags.cutting) return -1;
24376             if (this.tags.tunnel) return -1;
24377             if (this.tags.waterway) return -1;
24378             if (this.tags.man_made === 'pipeline') return -10;
24379             if (this.tags.boundary) return -10;
24380             return 0;
24381           },
24382           // the approximate width of the line based on its tags except its `width` tag
24383           impliedLineWidthMeters: function impliedLineWidthMeters() {
24384             var averageWidths = {
24385               highway: {
24386                 // width is for single lane
24387                 motorway: 5,
24388                 motorway_link: 5,
24389                 trunk: 4.5,
24390                 trunk_link: 4.5,
24391                 primary: 4,
24392                 secondary: 4,
24393                 tertiary: 4,
24394                 primary_link: 4,
24395                 secondary_link: 4,
24396                 tertiary_link: 4,
24397                 unclassified: 4,
24398                 road: 4,
24399                 living_street: 4,
24400                 bus_guideway: 4,
24401                 pedestrian: 4,
24402                 residential: 3.5,
24403                 service: 3.5,
24404                 track: 3,
24405                 cycleway: 2.5,
24406                 bridleway: 2,
24407                 corridor: 2,
24408                 steps: 2,
24409                 path: 1.5,
24410                 footway: 1.5
24411               },
24412               railway: {
24413                 // width includes ties and rail bed, not just track gauge
24414                 rail: 2.5,
24415                 light_rail: 2.5,
24416                 tram: 2.5,
24417                 subway: 2.5,
24418                 monorail: 2.5,
24419                 funicular: 2.5,
24420                 disused: 2.5,
24421                 preserved: 2.5,
24422                 miniature: 1.5,
24423                 narrow_gauge: 1.5
24424               },
24425               waterway: {
24426                 river: 50,
24427                 canal: 25,
24428                 stream: 5,
24429                 tidal_channel: 5,
24430                 fish_pass: 2.5,
24431                 drain: 2.5,
24432                 ditch: 1.5
24433               }
24434             };
24435
24436             for (var key in averageWidths) {
24437               if (this.tags[key] && averageWidths[key][this.tags[key]]) {
24438                 var width = averageWidths[key][this.tags[key]];
24439
24440                 if (key === 'highway') {
24441                   var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
24442                   if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
24443                   return width * laneCount;
24444                 }
24445
24446                 return width;
24447               }
24448             }
24449
24450             return null;
24451           },
24452           isOneWay: function isOneWay() {
24453             // explicit oneway tag..
24454             var values = {
24455               'yes': true,
24456               '1': true,
24457               '-1': true,
24458               'reversible': true,
24459               'alternating': true,
24460               'no': false,
24461               '0': false
24462             };
24463
24464             if (values[this.tags.oneway] !== undefined) {
24465               return values[this.tags.oneway];
24466             } // implied oneway tag..
24467
24468
24469             for (var key in this.tags) {
24470               if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) return true;
24471             }
24472
24473             return false;
24474           },
24475           // Some identifier for tag that implies that this way is "sided",
24476           // i.e. the right side is the 'inside' (e.g. the right side of a
24477           // natural=cliff is lower).
24478           sidednessIdentifier: function sidednessIdentifier() {
24479             for (var key in this.tags) {
24480               var value = this.tags[key];
24481
24482               if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
24483                 if (osmRightSideIsInsideTags[key][value] === true) {
24484                   return key;
24485                 } else {
24486                   // if the map's value is something other than a
24487                   // literal true, we should use it so we can
24488                   // special case some keys (e.g. natural=coastline
24489                   // is handled differently to other naturals).
24490                   return osmRightSideIsInsideTags[key][value];
24491                 }
24492               }
24493             }
24494
24495             return null;
24496           },
24497           isSided: function isSided() {
24498             if (this.tags.two_sided === 'yes') {
24499               return false;
24500             }
24501
24502             return this.sidednessIdentifier() !== null;
24503           },
24504           lanes: function lanes() {
24505             return osmLanes(this);
24506           },
24507           isClosed: function isClosed() {
24508             return this.nodes.length > 1 && this.first() === this.last();
24509           },
24510           isConvex: function isConvex(resolver) {
24511             if (!this.isClosed() || this.isDegenerate()) return null;
24512             var nodes = utilArrayUniq(resolver.childNodes(this));
24513             var coords = nodes.map(function (n) {
24514               return n.loc;
24515             });
24516             var curr = 0;
24517             var prev = 0;
24518
24519             for (var i = 0; i < coords.length; i++) {
24520               var o = coords[(i + 1) % coords.length];
24521               var a = coords[i];
24522               var b = coords[(i + 2) % coords.length];
24523               var res = geoVecCross(a, b, o);
24524               curr = res > 0 ? 1 : res < 0 ? -1 : 0;
24525
24526               if (curr === 0) {
24527                 continue;
24528               } else if (prev && curr !== prev) {
24529                 return false;
24530               }
24531
24532               prev = curr;
24533             }
24534
24535             return true;
24536           },
24537           // returns an object with the tag that implies this is an area, if any
24538           tagSuggestingArea: function tagSuggestingArea() {
24539             return osmTagSuggestingArea(this.tags);
24540           },
24541           isArea: function isArea() {
24542             if (this.tags.area === 'yes') return true;
24543             if (!this.isClosed() || this.tags.area === 'no') return false;
24544             return this.tagSuggestingArea() !== null;
24545           },
24546           isDegenerate: function isDegenerate() {
24547             return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
24548           },
24549           areAdjacent: function areAdjacent(n1, n2) {
24550             for (var i = 0; i < this.nodes.length; i++) {
24551               if (this.nodes[i] === n1) {
24552                 if (this.nodes[i - 1] === n2) return true;
24553                 if (this.nodes[i + 1] === n2) return true;
24554               }
24555             }
24556
24557             return false;
24558           },
24559           geometry: function geometry(graph) {
24560             return graph["transient"](this, 'geometry', function () {
24561               return this.isArea() ? 'area' : 'line';
24562             });
24563           },
24564           // returns an array of objects representing the segments between the nodes in this way
24565           segments: function segments(graph) {
24566             function segmentExtent(graph) {
24567               var n1 = graph.hasEntity(this.nodes[0]);
24568               var n2 = graph.hasEntity(this.nodes[1]);
24569               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])]]);
24570             }
24571
24572             return graph["transient"](this, 'segments', function () {
24573               var segments = [];
24574
24575               for (var i = 0; i < this.nodes.length - 1; i++) {
24576                 segments.push({
24577                   id: this.id + '-' + i,
24578                   wayId: this.id,
24579                   index: i,
24580                   nodes: [this.nodes[i], this.nodes[i + 1]],
24581                   extent: segmentExtent
24582                 });
24583               }
24584
24585               return segments;
24586             });
24587           },
24588           // If this way is not closed, append the beginning node to the end of the nodelist to close it.
24589           close: function close() {
24590             if (this.isClosed() || !this.nodes.length) return this;
24591             var nodes = this.nodes.slice();
24592             nodes = nodes.filter(noRepeatNodes);
24593             nodes.push(nodes[0]);
24594             return this.update({
24595               nodes: nodes
24596             });
24597           },
24598           // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
24599           unclose: function unclose() {
24600             if (!this.isClosed()) return this;
24601             var nodes = this.nodes.slice();
24602             var connector = this.first();
24603             var i = nodes.length - 1; // remove trailing connectors..
24604
24605             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24606               nodes.splice(i, 1);
24607               i = nodes.length - 1;
24608             }
24609
24610             nodes = nodes.filter(noRepeatNodes);
24611             return this.update({
24612               nodes: nodes
24613             });
24614           },
24615           // Adds a node (id) in front of the node which is currently at position index.
24616           // If index is undefined, the node will be added to the end of the way for linear ways,
24617           //   or just before the final connecting node for circular ways.
24618           // Consecutive duplicates are eliminated including existing ones.
24619           // Circularity is always preserved when adding a node.
24620           addNode: function addNode(id, index) {
24621             var nodes = this.nodes.slice();
24622             var isClosed = this.isClosed();
24623             var max = isClosed ? nodes.length - 1 : nodes.length;
24624
24625             if (index === undefined) {
24626               index = max;
24627             }
24628
24629             if (index < 0 || index > max) {
24630               throw new RangeError('index ' + index + ' out of range 0..' + max);
24631             } // If this is a closed way, remove all connector nodes except the first one
24632             // (there may be duplicates) and adjust index if necessary..
24633
24634
24635             if (isClosed) {
24636               var connector = this.first(); // leading connectors..
24637
24638               var i = 1;
24639
24640               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
24641                 nodes.splice(i, 1);
24642                 if (index > i) index--;
24643               } // trailing connectors..
24644
24645
24646               i = nodes.length - 1;
24647
24648               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24649                 nodes.splice(i, 1);
24650                 if (index > i) index--;
24651                 i = nodes.length - 1;
24652               }
24653             }
24654
24655             nodes.splice(index, 0, id);
24656             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24657
24658             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24659               nodes.push(nodes[0]);
24660             }
24661
24662             return this.update({
24663               nodes: nodes
24664             });
24665           },
24666           // Replaces the node which is currently at position index with the given node (id).
24667           // Consecutive duplicates are eliminated including existing ones.
24668           // Circularity is preserved when updating a node.
24669           updateNode: function updateNode(id, index) {
24670             var nodes = this.nodes.slice();
24671             var isClosed = this.isClosed();
24672             var max = nodes.length - 1;
24673
24674             if (index === undefined || index < 0 || index > max) {
24675               throw new RangeError('index ' + index + ' out of range 0..' + max);
24676             } // If this is a closed way, remove all connector nodes except the first one
24677             // (there may be duplicates) and adjust index if necessary..
24678
24679
24680             if (isClosed) {
24681               var connector = this.first(); // leading connectors..
24682
24683               var i = 1;
24684
24685               while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
24686                 nodes.splice(i, 1);
24687                 if (index > i) index--;
24688               } // trailing connectors..
24689
24690
24691               i = nodes.length - 1;
24692
24693               while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
24694                 nodes.splice(i, 1);
24695                 if (index === i) index = 0; // update leading connector instead
24696
24697                 i = nodes.length - 1;
24698               }
24699             }
24700
24701             nodes.splice(index, 1, id);
24702             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24703
24704             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24705               nodes.push(nodes[0]);
24706             }
24707
24708             return this.update({
24709               nodes: nodes
24710             });
24711           },
24712           // Replaces each occurrence of node id needle with replacement.
24713           // Consecutive duplicates are eliminated including existing ones.
24714           // Circularity is preserved.
24715           replaceNode: function replaceNode(needleID, replacementID) {
24716             var nodes = this.nodes.slice();
24717             var isClosed = this.isClosed();
24718
24719             for (var i = 0; i < nodes.length; i++) {
24720               if (nodes[i] === needleID) {
24721                 nodes[i] = replacementID;
24722               }
24723             }
24724
24725             nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24726
24727             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24728               nodes.push(nodes[0]);
24729             }
24730
24731             return this.update({
24732               nodes: nodes
24733             });
24734           },
24735           // Removes each occurrence of node id.
24736           // Consecutive duplicates are eliminated including existing ones.
24737           // Circularity is preserved.
24738           removeNode: function removeNode(id) {
24739             var nodes = this.nodes.slice();
24740             var isClosed = this.isClosed();
24741             nodes = nodes.filter(function (node) {
24742               return node !== id;
24743             }).filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
24744
24745             if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
24746               nodes.push(nodes[0]);
24747             }
24748
24749             return this.update({
24750               nodes: nodes
24751             });
24752           },
24753           asJXON: function asJXON(changeset_id) {
24754             var r = {
24755               way: {
24756                 '@id': this.osmId(),
24757                 '@version': this.version || 0,
24758                 nd: this.nodes.map(function (id) {
24759                   return {
24760                     keyAttributes: {
24761                       ref: osmEntity.id.toOSM(id)
24762                     }
24763                   };
24764                 }, this),
24765                 tag: Object.keys(this.tags).map(function (k) {
24766                   return {
24767                     keyAttributes: {
24768                       k: k,
24769                       v: this.tags[k]
24770                     }
24771                   };
24772                 }, this)
24773               }
24774             };
24775
24776             if (changeset_id) {
24777               r.way['@changeset'] = changeset_id;
24778             }
24779
24780             return r;
24781           },
24782           asGeoJSON: function asGeoJSON(resolver) {
24783             return resolver["transient"](this, 'GeoJSON', function () {
24784               var coordinates = resolver.childNodes(this).map(function (n) {
24785                 return n.loc;
24786               });
24787
24788               if (this.isArea() && this.isClosed()) {
24789                 return {
24790                   type: 'Polygon',
24791                   coordinates: [coordinates]
24792                 };
24793               } else {
24794                 return {
24795                   type: 'LineString',
24796                   coordinates: coordinates
24797                 };
24798               }
24799             });
24800           },
24801           area: function area(resolver) {
24802             return resolver["transient"](this, 'area', function () {
24803               var nodes = resolver.childNodes(this);
24804               var json = {
24805                 type: 'Polygon',
24806                 coordinates: [nodes.map(function (n) {
24807                   return n.loc;
24808                 })]
24809               };
24810
24811               if (!this.isClosed() && nodes.length) {
24812                 json.coordinates[0].push(nodes[0].loc);
24813               }
24814
24815               var area = d3_geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes
24816               // that OpenStreetMap polygons are not hemisphere-spanning.
24817
24818               if (area > 2 * Math.PI) {
24819                 json.coordinates[0] = json.coordinates[0].reverse();
24820                 area = d3_geoArea(json);
24821               }
24822
24823               return isNaN(area) ? 0 : area;
24824             });
24825           }
24826         }); // Filter function to eliminate consecutive duplicates.
24827
24828         function noRepeatNodes(node, i, arr) {
24829           return i === 0 || node !== arr[i - 1];
24830         }
24831
24832         //
24833         // 1. Relation tagged with `type=multipolygon` and no interesting tags.
24834         // 2. One and only one member with the `outer` role. Must be a way with interesting tags.
24835         // 3. No members without a role.
24836         //
24837         // Old multipolygons are no longer recommended but are still rendered as areas by iD.
24838
24839         function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
24840           if (entity.type !== 'relation' || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
24841             return false;
24842           }
24843
24844           var outerMember;
24845
24846           for (var memberIndex in entity.members) {
24847             var member = entity.members[memberIndex];
24848
24849             if (!member.role || member.role === 'outer') {
24850               if (outerMember) return false;
24851               if (member.type !== 'way') return false;
24852               if (!graph.hasEntity(member.id)) return false;
24853               outerMember = graph.entity(member.id);
24854
24855               if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
24856                 return false;
24857               }
24858             }
24859           }
24860
24861           return outerMember;
24862         } // For fixing up rendering of multipolygons with tags on the outer member.
24863         // https://github.com/openstreetmap/iD/issues/613
24864
24865         function osmIsOldMultipolygonOuterMember(entity, graph) {
24866           if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) return false;
24867           var parents = graph.parentRelations(entity);
24868           if (parents.length !== 1) return false;
24869           var parent = parents[0];
24870           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) return false;
24871           var members = parent.members,
24872               member;
24873
24874           for (var i = 0; i < members.length; i++) {
24875             member = members[i];
24876             if (member.id === entity.id && member.role && member.role !== 'outer') return false; // Not outer member
24877
24878             if (member.id !== entity.id && (!member.role || member.role === 'outer')) return false; // Not a simple multipolygon
24879           }
24880
24881           return parent;
24882         }
24883         function osmOldMultipolygonOuterMember(entity, graph) {
24884           if (entity.type !== 'way') return false;
24885           var parents = graph.parentRelations(entity);
24886           if (parents.length !== 1) return false;
24887           var parent = parents[0];
24888           if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) return false;
24889           var members = parent.members,
24890               member,
24891               outerMember;
24892
24893           for (var i = 0; i < members.length; i++) {
24894             member = members[i];
24895
24896             if (!member.role || member.role === 'outer') {
24897               if (outerMember) return false; // Not a simple multipolygon
24898
24899               outerMember = member;
24900             }
24901           }
24902
24903           if (!outerMember) return false;
24904           var outerEntity = graph.hasEntity(outerMember.id);
24905           if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) return false;
24906           return outerEntity;
24907         } // Join `toJoin` array into sequences of connecting ways.
24908         // Segments which share identical start/end nodes will, as much as possible,
24909         // be connected with each other.
24910         //
24911         // The return value is a nested array. Each constituent array contains elements
24912         // of `toJoin` which have been determined to connect.
24913         //
24914         // Each consitituent array also has a `nodes` property whose value is an
24915         // ordered array of member nodes, with appropriate order reversal and
24916         // start/end coordinate de-duplication.
24917         //
24918         // Members of `toJoin` must have, at minimum, `type` and `id` properties.
24919         // Thus either an array of `osmWay`s or a relation member array may be used.
24920         //
24921         // If an member is an `osmWay`, its tags and childnodes may be reversed via
24922         // `actionReverse` in the output.
24923         //
24924         // The returned sequences array also has an `actions` array property, containing
24925         // any reversal actions that should be applied to the graph, should the calling
24926         // code attempt to actually join the given ways.
24927         //
24928         // Incomplete members (those for which `graph.hasEntity(element.id)` returns
24929         // false) and non-way members are ignored.
24930         //
24931
24932         function osmJoinWays(toJoin, graph) {
24933           function resolve(member) {
24934             return graph.childNodes(graph.entity(member.id));
24935           }
24936
24937           function reverse(item) {
24938             var action = actionReverse(item.id, {
24939               reverseOneway: true
24940             });
24941             sequences.actions.push(action);
24942             return item instanceof osmWay ? action(graph).entity(item.id) : item;
24943           } // make a copy containing only the items to join
24944
24945
24946           toJoin = toJoin.filter(function (member) {
24947             return member.type === 'way' && graph.hasEntity(member.id);
24948           }); // Are the things we are joining relation members or `osmWays`?
24949           // If `osmWays`, skip the "prefer a forward path" code below (see #4872)
24950
24951           var i;
24952           var joinAsMembers = true;
24953
24954           for (i = 0; i < toJoin.length; i++) {
24955             if (toJoin[i] instanceof osmWay) {
24956               joinAsMembers = false;
24957               break;
24958             }
24959           }
24960
24961           var sequences = [];
24962           sequences.actions = [];
24963
24964           while (toJoin.length) {
24965             // start a new sequence
24966             var item = toJoin.shift();
24967             var currWays = [item];
24968             var currNodes = resolve(item).slice(); // add to it
24969
24970             while (toJoin.length) {
24971               var start = currNodes[0];
24972               var end = currNodes[currNodes.length - 1];
24973               var fn = null;
24974               var nodes = null; // Find the next way/member to join.
24975
24976               for (i = 0; i < toJoin.length; i++) {
24977                 item = toJoin[i];
24978                 nodes = resolve(item); // (for member ordering only, not way ordering - see #4872)
24979                 // Strongly prefer to generate a forward path that preserves the order
24980                 // of the members array. For multipolygons and most relations, member
24981                 // order does not matter - but for routes, it does. (see #4589)
24982                 // If we started this sequence backwards (i.e. next member way attaches to
24983                 // the start node and not the end node), reverse the initial way before continuing.
24984
24985                 if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start || nodes[0] === start)) {
24986                   currWays[0] = reverse(currWays[0]);
24987                   currNodes.reverse();
24988                   start = currNodes[0];
24989                   end = currNodes[currNodes.length - 1];
24990                 }
24991
24992                 if (nodes[0] === end) {
24993                   fn = currNodes.push; // join to end
24994
24995                   nodes = nodes.slice(1);
24996                   break;
24997                 } else if (nodes[nodes.length - 1] === end) {
24998                   fn = currNodes.push; // join to end
24999
25000                   nodes = nodes.slice(0, -1).reverse();
25001                   item = reverse(item);
25002                   break;
25003                 } else if (nodes[nodes.length - 1] === start) {
25004                   fn = currNodes.unshift; // join to beginning
25005
25006                   nodes = nodes.slice(0, -1);
25007                   break;
25008                 } else if (nodes[0] === start) {
25009                   fn = currNodes.unshift; // join to beginning
25010
25011                   nodes = nodes.slice(1).reverse();
25012                   item = reverse(item);
25013                   break;
25014                 } else {
25015                   fn = nodes = null;
25016                 }
25017               }
25018
25019               if (!nodes) {
25020                 // couldn't find a joinable way/member
25021                 break;
25022               }
25023
25024               fn.apply(currWays, [item]);
25025               fn.apply(currNodes, nodes);
25026               toJoin.splice(i, 1);
25027             }
25028
25029             currWays.nodes = currNodes;
25030             sequences.push(currWays);
25031           }
25032
25033           return sequences;
25034         }
25035
25036         function actionAddMember(relationId, member, memberIndex, insertPair) {
25037           return function action(graph) {
25038             var relation = graph.entity(relationId); // There are some special rules for Public Transport v2 routes.
25039
25040             var isPTv2 = /stop|platform/.test(member.role);
25041
25042             if ((isNaN(memberIndex) || insertPair) && member.type === 'way' && !isPTv2) {
25043               // Try to perform sensible inserts based on how the ways join together
25044               graph = addWayMember(relation, graph);
25045             } else {
25046               // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
25047               // Stops and Platforms for PTv2 should be ordered first.
25048               // hack: We do not currently have the ability to place them in the exactly correct order.
25049               if (isPTv2 && isNaN(memberIndex)) {
25050                 memberIndex = 0;
25051               }
25052
25053               graph = graph.replace(relation.addMember(member, memberIndex));
25054             }
25055
25056             return graph;
25057           }; // Add a way member into the relation "wherever it makes sense".
25058           // In this situation we were not supplied a memberIndex.
25059
25060           function addWayMember(relation, graph) {
25061             var groups, tempWay, item, i, j, k; // remove PTv2 stops and platforms before doing anything.
25062
25063             var PTv2members = [];
25064             var members = [];
25065
25066             for (i = 0; i < relation.members.length; i++) {
25067               var m = relation.members[i];
25068
25069               if (/stop|platform/.test(m.role)) {
25070                 PTv2members.push(m);
25071               } else {
25072                 members.push(m);
25073               }
25074             }
25075
25076             relation = relation.update({
25077               members: members
25078             });
25079
25080             if (insertPair) {
25081               // We're adding a member that must stay paired with an existing member.
25082               // (This feature is used by `actionSplit`)
25083               //
25084               // This is tricky because the members may exist multiple times in the
25085               // member list, and with different A-B/B-A ordering and different roles.
25086               // (e.g. a bus route that loops out and back - #4589).
25087               //
25088               // Replace the existing member with a temporary way,
25089               // so that `osmJoinWays` can treat the pair like a single way.
25090               tempWay = osmWay({
25091                 id: 'wTemp',
25092                 nodes: insertPair.nodes
25093               });
25094               graph = graph.replace(tempWay);
25095               var tempMember = {
25096                 id: tempWay.id,
25097                 type: 'way',
25098                 role: member.role
25099               };
25100               var tempRelation = relation.replaceMember({
25101                 id: insertPair.originalID
25102               }, tempMember, true);
25103               groups = utilArrayGroupBy(tempRelation.members, 'type');
25104               groups.way = groups.way || [];
25105             } else {
25106               // Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
25107               groups = utilArrayGroupBy(relation.members, 'type');
25108               groups.way = groups.way || [];
25109               groups.way.push(member);
25110             }
25111
25112             members = withIndex(groups.way);
25113             var joined = osmJoinWays(members, graph); // `joined` might not contain all of the way members,
25114             // But will contain only the completed (downloaded) members
25115
25116             for (i = 0; i < joined.length; i++) {
25117               var segment = joined[i];
25118               var nodes = segment.nodes.slice();
25119               var startIndex = segment[0].index; // j = array index in `members` where this segment starts
25120
25121               for (j = 0; j < members.length; j++) {
25122                 if (members[j].index === startIndex) {
25123                   break;
25124                 }
25125               } // k = each member in segment
25126
25127
25128               for (k = 0; k < segment.length; k++) {
25129                 item = segment[k];
25130                 var way = graph.entity(item.id); // If this is a paired item, generate members in correct order and role
25131
25132                 if (tempWay && item.id === tempWay.id) {
25133                   if (nodes[0].id === insertPair.nodes[0]) {
25134                     item.pair = [{
25135                       id: insertPair.originalID,
25136                       type: 'way',
25137                       role: item.role
25138                     }, {
25139                       id: insertPair.insertedID,
25140                       type: 'way',
25141                       role: item.role
25142                     }];
25143                   } else {
25144                     item.pair = [{
25145                       id: insertPair.insertedID,
25146                       type: 'way',
25147                       role: item.role
25148                     }, {
25149                       id: insertPair.originalID,
25150                       type: 'way',
25151                       role: item.role
25152                     }];
25153                   }
25154                 } // reorder `members` if necessary
25155
25156
25157                 if (k > 0) {
25158                   if (j + k >= members.length || item.index !== members[j + k].index) {
25159                     moveMember(members, item.index, j + k);
25160                   }
25161                 }
25162
25163                 nodes.splice(0, way.nodes.length - 1);
25164               }
25165             }
25166
25167             if (tempWay) {
25168               graph = graph.remove(tempWay);
25169             } // Final pass: skip dead items, split pairs, remove index properties
25170
25171
25172             var wayMembers = [];
25173
25174             for (i = 0; i < members.length; i++) {
25175               item = members[i];
25176               if (item.index === -1) continue;
25177
25178               if (item.pair) {
25179                 wayMembers.push(item.pair[0]);
25180                 wayMembers.push(item.pair[1]);
25181               } else {
25182                 wayMembers.push(utilObjectOmit(item, ['index']));
25183               }
25184             } // Put stops and platforms first, then nodes, ways, relations
25185             // This is recommended for Public Transport v2 routes:
25186             // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
25187
25188
25189             var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
25190             return graph.replace(relation.update({
25191               members: newMembers
25192             })); // `moveMember()` changes the `members` array in place by splicing
25193             // the item with `.index = findIndex` to where it belongs,
25194             // and marking the old position as "dead" with `.index = -1`
25195             //
25196             // j=5, k=0                jk
25197             // segment                 5 4 7 6
25198             // members       0 1 2 3 4 5 6 7 8 9        keep 5 in j+k
25199             //
25200             // j=5, k=1                j k
25201             // segment                 5 4 7 6
25202             // members       0 1 2 3 4 5 6 7 8 9        move 4 to j+k
25203             // members       0 1 2 3 x 5 4 6 7 8 9      moved
25204             //
25205             // j=5, k=2                j   k
25206             // segment                 5 4 7 6
25207             // members       0 1 2 3 x 5 4 6 7 8 9      move 7 to j+k
25208             // members       0 1 2 3 x 5 4 7 6 x 8 9    moved
25209             //
25210             // j=5, k=3                j     k
25211             // segment                 5 4 7 6
25212             // members       0 1 2 3 x 5 4 7 6 x 8 9    keep 6 in j+k
25213             //
25214
25215             function moveMember(arr, findIndex, toIndex) {
25216               var i;
25217
25218               for (i = 0; i < arr.length; i++) {
25219                 if (arr[i].index === findIndex) {
25220                   break;
25221                 }
25222               }
25223
25224               var item = Object.assign({}, arr[i]); // shallow copy
25225
25226               arr[i].index = -1; // mark as dead
25227
25228               item.index = toIndex;
25229               arr.splice(toIndex, 0, item);
25230             } // This is the same as `Relation.indexedMembers`,
25231             // Except we don't want to index all the members, only the ways
25232
25233
25234             function withIndex(arr) {
25235               var result = new Array(arr.length);
25236
25237               for (var i = 0; i < arr.length; i++) {
25238                 result[i] = Object.assign({}, arr[i]); // shallow copy
25239
25240                 result[i].index = i;
25241               }
25242
25243               return result;
25244             }
25245           }
25246         }
25247
25248         function actionAddMidpoint(midpoint, node) {
25249           return function (graph) {
25250             graph = graph.replace(node.move(midpoint.loc));
25251             var parents = utilArrayIntersection(graph.parentWays(graph.entity(midpoint.edge[0])), graph.parentWays(graph.entity(midpoint.edge[1])));
25252             parents.forEach(function (way) {
25253               for (var i = 0; i < way.nodes.length - 1; i++) {
25254                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
25255                   graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1)); // Add only one midpoint on doubled-back segments,
25256                   // turning them into self-intersections.
25257
25258                   return;
25259                 }
25260               }
25261             });
25262             return graph;
25263           };
25264         }
25265
25266         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
25267         function actionAddVertex(wayId, nodeId, index) {
25268           return function (graph) {
25269             return graph.replace(graph.entity(wayId).addNode(nodeId, index));
25270           };
25271         }
25272
25273         function actionChangeMember(relationId, member, memberIndex) {
25274           return function (graph) {
25275             return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
25276           };
25277         }
25278
25279         function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
25280           return function action(graph) {
25281             var entity = graph.entity(entityID);
25282             var geometry = entity.geometry(graph);
25283             var tags = entity.tags;
25284             if (oldPreset) tags = oldPreset.unsetTags(tags, geometry);
25285             if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
25286             return graph.replace(entity.update({
25287               tags: tags
25288             }));
25289           };
25290         }
25291
25292         function actionChangeTags(entityId, tags) {
25293           return function (graph) {
25294             var entity = graph.entity(entityId);
25295             return graph.replace(entity.update({
25296               tags: tags
25297             }));
25298           };
25299         }
25300
25301         function osmNode() {
25302           if (!(this instanceof osmNode)) {
25303             return new osmNode().initialize(arguments);
25304           } else if (arguments.length) {
25305             this.initialize(arguments);
25306           }
25307         }
25308         osmEntity.node = osmNode;
25309         osmNode.prototype = Object.create(osmEntity.prototype);
25310         Object.assign(osmNode.prototype, {
25311           type: 'node',
25312           loc: [9999, 9999],
25313           extent: function extent() {
25314             return new geoExtent(this.loc);
25315           },
25316           geometry: function geometry(graph) {
25317             return graph["transient"](this, 'geometry', function () {
25318               return graph.isPoi(this) ? 'point' : 'vertex';
25319             });
25320           },
25321           move: function move(loc) {
25322             return this.update({
25323               loc: loc
25324             });
25325           },
25326           isDegenerate: function isDegenerate() {
25327             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);
25328           },
25329           // Inspect tags and geometry to determine which direction(s) this node/vertex points
25330           directions: function directions(resolver, projection) {
25331             var val;
25332             var i; // which tag to use?
25333
25334             if (this.isHighwayIntersection(resolver) && (this.tags.stop || '').toLowerCase() === 'all') {
25335               // all-way stop tag on a highway intersection
25336               val = 'all';
25337             } else {
25338               // generic direction tag
25339               val = (this.tags.direction || '').toLowerCase(); // better suffix-style direction tag
25340
25341               var re = /:direction$/i;
25342               var keys = Object.keys(this.tags);
25343
25344               for (i = 0; i < keys.length; i++) {
25345                 if (re.test(keys[i])) {
25346                   val = this.tags[keys[i]].toLowerCase();
25347                   break;
25348                 }
25349               }
25350             }
25351
25352             if (val === '') return [];
25353             var cardinal = {
25354               north: 0,
25355               n: 0,
25356               northnortheast: 22,
25357               nne: 22,
25358               northeast: 45,
25359               ne: 45,
25360               eastnortheast: 67,
25361               ene: 67,
25362               east: 90,
25363               e: 90,
25364               eastsoutheast: 112,
25365               ese: 112,
25366               southeast: 135,
25367               se: 135,
25368               southsoutheast: 157,
25369               sse: 157,
25370               south: 180,
25371               s: 180,
25372               southsouthwest: 202,
25373               ssw: 202,
25374               southwest: 225,
25375               sw: 225,
25376               westsouthwest: 247,
25377               wsw: 247,
25378               west: 270,
25379               w: 270,
25380               westnorthwest: 292,
25381               wnw: 292,
25382               northwest: 315,
25383               nw: 315,
25384               northnorthwest: 337,
25385               nnw: 337
25386             };
25387             var values = val.split(';');
25388             var results = [];
25389             values.forEach(function (v) {
25390               // swap cardinal for numeric directions
25391               if (cardinal[v] !== undefined) {
25392                 v = cardinal[v];
25393               } // numeric direction - just add to results
25394
25395
25396               if (v !== '' && !isNaN(+v)) {
25397                 results.push(+v);
25398                 return;
25399               } // string direction - inspect parent ways
25400
25401
25402               var lookBackward = this.tags['traffic_sign:backward'] || v === 'backward' || v === 'both' || v === 'all';
25403               var lookForward = this.tags['traffic_sign:forward'] || v === 'forward' || v === 'both' || v === 'all';
25404               if (!lookForward && !lookBackward) return;
25405               var nodeIds = {};
25406               resolver.parentWays(this).forEach(function (parent) {
25407                 var nodes = parent.nodes;
25408
25409                 for (i = 0; i < nodes.length; i++) {
25410                   if (nodes[i] === this.id) {
25411                     // match current entity
25412                     if (lookForward && i > 0) {
25413                       nodeIds[nodes[i - 1]] = true; // look back to prev node
25414                     }
25415
25416                     if (lookBackward && i < nodes.length - 1) {
25417                       nodeIds[nodes[i + 1]] = true; // look ahead to next node
25418                     }
25419                   }
25420                 }
25421               }, this);
25422               Object.keys(nodeIds).forEach(function (nodeId) {
25423                 // +90 because geoAngle returns angle from X axis, not Y (north)
25424                 results.push(geoAngle(this, resolver.entity(nodeId), projection) * (180 / Math.PI) + 90);
25425               }, this);
25426             }, this);
25427             return utilArrayUniq(results);
25428           },
25429           isEndpoint: function isEndpoint(resolver) {
25430             return resolver["transient"](this, 'isEndpoint', function () {
25431               var id = this.id;
25432               return resolver.parentWays(this).filter(function (parent) {
25433                 return !parent.isClosed() && !!parent.affix(id);
25434               }).length > 0;
25435             });
25436           },
25437           isConnected: function isConnected(resolver) {
25438             return resolver["transient"](this, 'isConnected', function () {
25439               var parents = resolver.parentWays(this);
25440
25441               if (parents.length > 1) {
25442                 // vertex is connected to multiple parent ways
25443                 for (var i in parents) {
25444                   if (parents[i].geometry(resolver) === 'line' && parents[i].hasInterestingTags()) return true;
25445                 }
25446               } else if (parents.length === 1) {
25447                 var way = parents[0];
25448                 var nodes = way.nodes.slice();
25449
25450                 if (way.isClosed()) {
25451                   nodes.pop();
25452                 } // ignore connecting node if closed
25453                 // return true if vertex appears multiple times (way is self intersecting)
25454
25455
25456                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
25457               }
25458
25459               return false;
25460             });
25461           },
25462           parentIntersectionWays: function parentIntersectionWays(resolver) {
25463             return resolver["transient"](this, 'parentIntersectionWays', function () {
25464               return resolver.parentWays(this).filter(function (parent) {
25465                 return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === 'line';
25466               });
25467             });
25468           },
25469           isIntersection: function isIntersection(resolver) {
25470             return this.parentIntersectionWays(resolver).length > 1;
25471           },
25472           isHighwayIntersection: function isHighwayIntersection(resolver) {
25473             return resolver["transient"](this, 'isHighwayIntersection', function () {
25474               return resolver.parentWays(this).filter(function (parent) {
25475                 return parent.tags.highway && parent.geometry(resolver) === 'line';
25476               }).length > 1;
25477             });
25478           },
25479           isOnAddressLine: function isOnAddressLine(resolver) {
25480             return resolver["transient"](this, 'isOnAddressLine', function () {
25481               return resolver.parentWays(this).filter(function (parent) {
25482                 return parent.tags.hasOwnProperty('addr:interpolation') && parent.geometry(resolver) === 'line';
25483               }).length > 0;
25484             });
25485           },
25486           asJXON: function asJXON(changeset_id) {
25487             var r = {
25488               node: {
25489                 '@id': this.osmId(),
25490                 '@lon': this.loc[0],
25491                 '@lat': this.loc[1],
25492                 '@version': this.version || 0,
25493                 tag: Object.keys(this.tags).map(function (k) {
25494                   return {
25495                     keyAttributes: {
25496                       k: k,
25497                       v: this.tags[k]
25498                     }
25499                   };
25500                 }, this)
25501               }
25502             };
25503             if (changeset_id) r.node['@changeset'] = changeset_id;
25504             return r;
25505           },
25506           asGeoJSON: function asGeoJSON() {
25507             return {
25508               type: 'Point',
25509               coordinates: this.loc
25510             };
25511           }
25512         });
25513
25514         function actionCircularize(wayId, projection, maxAngle) {
25515           maxAngle = (maxAngle || 20) * Math.PI / 180;
25516
25517           var action = function action(graph, t) {
25518             if (t === null || !isFinite(t)) t = 1;
25519             t = Math.min(Math.max(+t, 0), 1);
25520             var way = graph.entity(wayId);
25521             var origNodes = {};
25522             graph.childNodes(way).forEach(function (node) {
25523               if (!origNodes[node.id]) origNodes[node.id] = node;
25524             });
25525
25526             if (!way.isConvex(graph)) {
25527               graph = action.makeConvex(graph);
25528             }
25529
25530             var nodes = utilArrayUniq(graph.childNodes(way));
25531             var keyNodes = nodes.filter(function (n) {
25532               return graph.parentWays(n).length !== 1;
25533             });
25534             var points = nodes.map(function (n) {
25535               return projection(n.loc);
25536             });
25537             var keyPoints = keyNodes.map(function (n) {
25538               return projection(n.loc);
25539             });
25540             var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points);
25541             var radius = d3_median(points, function (p) {
25542               return geoVecLength(centroid, p);
25543             });
25544             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
25545             var ids, i, j, k; // we need at least two key nodes for the algorithm to work
25546
25547             if (!keyNodes.length) {
25548               keyNodes = [nodes[0]];
25549               keyPoints = [points[0]];
25550             }
25551
25552             if (keyNodes.length === 1) {
25553               var index = nodes.indexOf(keyNodes[0]);
25554               var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
25555               keyNodes.push(nodes[oppositeIndex]);
25556               keyPoints.push(points[oppositeIndex]);
25557             } // key points and nodes are those connected to the ways,
25558             // they are projected onto the circle, in between nodes are moved
25559             // to constant intervals between key nodes, extra in between nodes are
25560             // added if necessary.
25561
25562
25563             for (i = 0; i < keyPoints.length; i++) {
25564               var nextKeyNodeIndex = (i + 1) % keyNodes.length;
25565               var startNode = keyNodes[i];
25566               var endNode = keyNodes[nextKeyNodeIndex];
25567               var startNodeIndex = nodes.indexOf(startNode);
25568               var endNodeIndex = nodes.indexOf(endNode);
25569               var numberNewPoints = -1;
25570               var indexRange = endNodeIndex - startNodeIndex;
25571               var nearNodes = {};
25572               var inBetweenNodes = [];
25573               var startAngle, endAngle, totalAngle, eachAngle;
25574               var angle, loc, node, origNode;
25575
25576               if (indexRange < 0) {
25577                 indexRange += nodes.length;
25578               } // position this key node
25579
25580
25581               var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4;
25582               keyPoints[i] = [centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
25583               loc = projection.invert(keyPoints[i]);
25584               node = keyNodes[i];
25585               origNode = origNodes[node.id];
25586               node = node.move(geoVecInterp(origNode.loc, loc, t));
25587               graph = graph.replace(node); // figure out the between delta angle we want to match to
25588
25589               startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
25590               endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
25591               totalAngle = endAngle - startAngle; // detects looping around -pi/pi
25592
25593               if (totalAngle * sign > 0) {
25594                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
25595               }
25596
25597               do {
25598                 numberNewPoints++;
25599                 eachAngle = totalAngle / (indexRange + numberNewPoints);
25600               } while (Math.abs(eachAngle) > maxAngle); // move existing nodes
25601
25602
25603               for (j = 1; j < indexRange; j++) {
25604                 angle = startAngle + j * eachAngle;
25605                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]);
25606                 node = nodes[(j + startNodeIndex) % nodes.length];
25607                 origNode = origNodes[node.id];
25608                 nearNodes[node.id] = angle;
25609                 node = node.move(geoVecInterp(origNode.loc, loc, t));
25610                 graph = graph.replace(node);
25611               } // add new in between nodes if necessary
25612
25613
25614               for (j = 0; j < numberNewPoints; j++) {
25615                 angle = startAngle + (indexRange + j) * eachAngle;
25616                 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]); // choose a nearnode to use as the original
25617
25618                 var min = Infinity;
25619
25620                 for (var nodeId in nearNodes) {
25621                   var nearAngle = nearNodes[nodeId];
25622                   var dist = Math.abs(nearAngle - angle);
25623
25624                   if (dist < min) {
25625                     min = dist;
25626                     origNode = origNodes[nodeId];
25627                   }
25628                 }
25629
25630                 node = osmNode({
25631                   loc: geoVecInterp(origNode.loc, loc, t)
25632                 });
25633                 graph = graph.replace(node);
25634                 nodes.splice(endNodeIndex + j, 0, node);
25635                 inBetweenNodes.push(node.id);
25636               } // Check for other ways that share these keyNodes..
25637               // If keyNodes are adjacent in both ways,
25638               // we can add inBetweenNodes to that shared way too..
25639
25640
25641               if (indexRange === 1 && inBetweenNodes.length) {
25642                 var startIndex1 = way.nodes.lastIndexOf(startNode.id);
25643                 var endIndex1 = way.nodes.lastIndexOf(endNode.id);
25644                 var wayDirection1 = endIndex1 - startIndex1;
25645
25646                 if (wayDirection1 < -1) {
25647                   wayDirection1 = 1;
25648                 }
25649
25650                 var parentWays = graph.parentWays(keyNodes[i]);
25651
25652                 for (j = 0; j < parentWays.length; j++) {
25653                   var sharedWay = parentWays[j];
25654                   if (sharedWay === way) continue;
25655
25656                   if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
25657                     var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
25658                     var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
25659                     var wayDirection2 = endIndex2 - startIndex2;
25660                     var insertAt = endIndex2;
25661
25662                     if (wayDirection2 < -1) {
25663                       wayDirection2 = 1;
25664                     }
25665
25666                     if (wayDirection1 !== wayDirection2) {
25667                       inBetweenNodes.reverse();
25668                       insertAt = startIndex2;
25669                     }
25670
25671                     for (k = 0; k < inBetweenNodes.length; k++) {
25672                       sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
25673                     }
25674
25675                     graph = graph.replace(sharedWay);
25676                   }
25677                 }
25678               }
25679             } // update the way to have all the new nodes
25680
25681
25682             ids = nodes.map(function (n) {
25683               return n.id;
25684             });
25685             ids.push(ids[0]);
25686             way = way.update({
25687               nodes: ids
25688             });
25689             graph = graph.replace(way);
25690             return graph;
25691           };
25692
25693           action.makeConvex = function (graph) {
25694             var way = graph.entity(wayId);
25695             var nodes = utilArrayUniq(graph.childNodes(way));
25696             var points = nodes.map(function (n) {
25697               return projection(n.loc);
25698             });
25699             var sign = d3_polygonArea(points) > 0 ? 1 : -1;
25700             var hull = d3_polygonHull(points);
25701             var i, j; // D3 convex hulls go counterclockwise..
25702
25703             if (sign === -1) {
25704               nodes.reverse();
25705               points.reverse();
25706             }
25707
25708             for (i = 0; i < hull.length - 1; i++) {
25709               var startIndex = points.indexOf(hull[i]);
25710               var endIndex = points.indexOf(hull[i + 1]);
25711               var indexRange = endIndex - startIndex;
25712
25713               if (indexRange < 0) {
25714                 indexRange += nodes.length;
25715               } // move interior nodes to the surface of the convex hull..
25716
25717
25718               for (j = 1; j < indexRange; j++) {
25719                 var point = geoVecInterp(hull[i], hull[i + 1], j / indexRange);
25720                 var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
25721                 graph = graph.replace(node);
25722               }
25723             }
25724
25725             return graph;
25726           };
25727
25728           action.disabled = function (graph) {
25729             if (!graph.entity(wayId).isClosed()) {
25730               return 'not_closed';
25731             } //disable when already circular
25732
25733
25734             var way = graph.entity(wayId);
25735             var nodes = utilArrayUniq(graph.childNodes(way));
25736             var points = nodes.map(function (n) {
25737               return projection(n.loc);
25738             });
25739             var hull = d3_polygonHull(points);
25740             var epsilonAngle = Math.PI / 180;
25741
25742             if (hull.length !== points.length || hull.length < 3) {
25743               return false;
25744             }
25745
25746             var centroid = d3_polygonCentroid(points);
25747             var radius = geoVecLengthSquare(centroid, points[0]);
25748             var i, actualPoint; // compare distances between centroid and points
25749
25750             for (i = 0; i < hull.length; i++) {
25751               actualPoint = hull[i];
25752               var actualDist = geoVecLengthSquare(actualPoint, centroid);
25753               var diff = Math.abs(actualDist - radius); //compare distances with epsilon-error (5%)
25754
25755               if (diff > 0.05 * radius) {
25756                 return false;
25757               }
25758             } //check if central angles are smaller than maxAngle
25759
25760
25761             for (i = 0; i < hull.length; i++) {
25762               actualPoint = hull[i];
25763               var nextPoint = hull[(i + 1) % hull.length];
25764               var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
25765               var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
25766               var angle = endAngle - startAngle;
25767
25768               if (angle < 0) {
25769                 angle = -angle;
25770               }
25771
25772               if (angle > Math.PI) {
25773                 angle = 2 * Math.PI - angle;
25774               }
25775
25776               if (angle > maxAngle + epsilonAngle) {
25777                 return false;
25778               }
25779             }
25780
25781             return 'already_circular';
25782           };
25783
25784           action.transitionable = true;
25785           return action;
25786         }
25787
25788         function actionDeleteWay(wayID) {
25789           function canDeleteNode(node, graph) {
25790             // don't delete nodes still attached to ways or relations
25791             if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
25792             var geometries = osmNodeGeometriesForTags(node.tags); // don't delete if this node can be a standalone point
25793
25794             if (geometries.point) return false; // delete if this node only be a vertex
25795
25796             if (geometries.vertex) return true; // iD doesn't know if this should be a point or vertex,
25797             // so only delete if there are no interesting tags
25798
25799             return !node.hasInterestingTags();
25800           }
25801
25802           var action = function action(graph) {
25803             var way = graph.entity(wayID);
25804             graph.parentRelations(way).forEach(function (parent) {
25805               parent = parent.removeMembersWithID(wayID);
25806               graph = graph.replace(parent);
25807
25808               if (parent.isDegenerate()) {
25809                 graph = actionDeleteRelation(parent.id)(graph);
25810               }
25811             });
25812             new Set(way.nodes).forEach(function (nodeID) {
25813               graph = graph.replace(way.removeNode(nodeID));
25814               var node = graph.entity(nodeID);
25815
25816               if (canDeleteNode(node, graph)) {
25817                 graph = graph.remove(node);
25818               }
25819             });
25820             return graph.remove(way);
25821           };
25822
25823           return action;
25824         }
25825
25826         function actionDeleteMultiple(ids) {
25827           var actions = {
25828             way: actionDeleteWay,
25829             node: actionDeleteNode,
25830             relation: actionDeleteRelation
25831           };
25832
25833           var action = function action(graph) {
25834             ids.forEach(function (id) {
25835               if (graph.hasEntity(id)) {
25836                 // It may have been deleted already.
25837                 graph = actions[graph.entity(id).type](id)(graph);
25838               }
25839             });
25840             return graph;
25841           };
25842
25843           return action;
25844         }
25845
25846         function actionDeleteRelation(relationID, allowUntaggedMembers) {
25847           function canDeleteEntity(entity, graph) {
25848             return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && !entity.hasInterestingTags() && !allowUntaggedMembers;
25849           }
25850
25851           var action = function action(graph) {
25852             var relation = graph.entity(relationID);
25853             graph.parentRelations(relation).forEach(function (parent) {
25854               parent = parent.removeMembersWithID(relationID);
25855               graph = graph.replace(parent);
25856
25857               if (parent.isDegenerate()) {
25858                 graph = actionDeleteRelation(parent.id)(graph);
25859               }
25860             });
25861             var memberIDs = utilArrayUniq(relation.members.map(function (m) {
25862               return m.id;
25863             }));
25864             memberIDs.forEach(function (memberID) {
25865               graph = graph.replace(relation.removeMembersWithID(memberID));
25866               var entity = graph.entity(memberID);
25867
25868               if (canDeleteEntity(entity, graph)) {
25869                 graph = actionDeleteMultiple([memberID])(graph);
25870               }
25871             });
25872             return graph.remove(relation);
25873           };
25874
25875           return action;
25876         }
25877
25878         function actionDeleteNode(nodeId) {
25879           var action = function action(graph) {
25880             var node = graph.entity(nodeId);
25881             graph.parentWays(node).forEach(function (parent) {
25882               parent = parent.removeNode(nodeId);
25883               graph = graph.replace(parent);
25884
25885               if (parent.isDegenerate()) {
25886                 graph = actionDeleteWay(parent.id)(graph);
25887               }
25888             });
25889             graph.parentRelations(node).forEach(function (parent) {
25890               parent = parent.removeMembersWithID(nodeId);
25891               graph = graph.replace(parent);
25892
25893               if (parent.isDegenerate()) {
25894                 graph = actionDeleteRelation(parent.id)(graph);
25895               }
25896             });
25897             return graph.remove(node);
25898           };
25899
25900           return action;
25901         }
25902
25903         //
25904         // First choose a node to be the survivor, with preference given
25905         // to an existing (not new) node.
25906         //
25907         // Tags and relation memberships of of non-surviving nodes are merged
25908         // to the survivor.
25909         //
25910         // This is the inverse of `iD.actionDisconnect`.
25911         //
25912         // Reference:
25913         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
25914         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
25915         //
25916
25917         function actionConnect(nodeIDs) {
25918           var action = function action(graph) {
25919             var survivor;
25920             var node;
25921             var parents;
25922             var i, j; // Choose a survivor node, prefer an existing (not new) node - #4974
25923
25924             for (i = 0; i < nodeIDs.length; i++) {
25925               survivor = graph.entity(nodeIDs[i]);
25926               if (survivor.version) break; // found one
25927             } // Replace all non-surviving nodes with the survivor and merge tags.
25928
25929
25930             for (i = 0; i < nodeIDs.length; i++) {
25931               node = graph.entity(nodeIDs[i]);
25932               if (node.id === survivor.id) continue;
25933               parents = graph.parentWays(node);
25934
25935               for (j = 0; j < parents.length; j++) {
25936                 graph = graph.replace(parents[j].replaceNode(node.id, survivor.id));
25937               }
25938
25939               parents = graph.parentRelations(node);
25940
25941               for (j = 0; j < parents.length; j++) {
25942                 graph = graph.replace(parents[j].replaceMember(node, survivor));
25943               }
25944
25945               survivor = survivor.mergeTags(node.tags);
25946               graph = actionDeleteNode(node.id)(graph);
25947             }
25948
25949             graph = graph.replace(survivor); // find and delete any degenerate ways created by connecting adjacent vertices
25950
25951             parents = graph.parentWays(survivor);
25952
25953             for (i = 0; i < parents.length; i++) {
25954               if (parents[i].isDegenerate()) {
25955                 graph = actionDeleteWay(parents[i].id)(graph);
25956               }
25957             }
25958
25959             return graph;
25960           };
25961
25962           action.disabled = function (graph) {
25963             var seen = {};
25964             var restrictionIDs = [];
25965             var survivor;
25966             var node, way;
25967             var relations, relation, role;
25968             var i, j, k; // Choose a survivor node, prefer an existing (not new) node - #4974
25969
25970             for (i = 0; i < nodeIDs.length; i++) {
25971               survivor = graph.entity(nodeIDs[i]);
25972               if (survivor.version) break; // found one
25973             } // 1. disable if the nodes being connected have conflicting relation roles
25974
25975
25976             for (i = 0; i < nodeIDs.length; i++) {
25977               node = graph.entity(nodeIDs[i]);
25978               relations = graph.parentRelations(node);
25979
25980               for (j = 0; j < relations.length; j++) {
25981                 relation = relations[j];
25982                 role = relation.memberById(node.id).role || ''; // if this node is a via node in a restriction, remember for later
25983
25984                 if (relation.hasFromViaTo()) {
25985                   restrictionIDs.push(relation.id);
25986                 }
25987
25988                 if (seen[relation.id] !== undefined && seen[relation.id] !== role) {
25989                   return 'relation';
25990                 } else {
25991                   seen[relation.id] = role;
25992                 }
25993               }
25994             } // gather restrictions for parent ways
25995
25996
25997             for (i = 0; i < nodeIDs.length; i++) {
25998               node = graph.entity(nodeIDs[i]);
25999               var parents = graph.parentWays(node);
26000
26001               for (j = 0; j < parents.length; j++) {
26002                 var parent = parents[j];
26003                 relations = graph.parentRelations(parent);
26004
26005                 for (k = 0; k < relations.length; k++) {
26006                   relation = relations[k];
26007
26008                   if (relation.hasFromViaTo()) {
26009                     restrictionIDs.push(relation.id);
26010                   }
26011                 }
26012               }
26013             } // test restrictions
26014
26015
26016             restrictionIDs = utilArrayUniq(restrictionIDs);
26017
26018             for (i = 0; i < restrictionIDs.length; i++) {
26019               relation = graph.entity(restrictionIDs[i]);
26020               if (!relation.isComplete(graph)) continue;
26021               var memberWays = relation.members.filter(function (m) {
26022                 return m.type === 'way';
26023               }).map(function (m) {
26024                 return graph.entity(m.id);
26025               });
26026               memberWays = utilArrayUniq(memberWays);
26027               var f = relation.memberByRole('from');
26028               var t = relation.memberByRole('to');
26029               var isUturn = f.id === t.id; // 2a. disable if connection would damage a restriction
26030               // (a key node is a node at the junction of ways)
26031
26032               var nodes = {
26033                 from: [],
26034                 via: [],
26035                 to: [],
26036                 keyfrom: [],
26037                 keyto: []
26038               };
26039
26040               for (j = 0; j < relation.members.length; j++) {
26041                 collectNodes(relation.members[j], nodes);
26042               }
26043
26044               nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
26045               nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
26046               var filter = keyNodeFilter(nodes.keyfrom, nodes.keyto);
26047               nodes.from = nodes.from.filter(filter);
26048               nodes.via = nodes.via.filter(filter);
26049               nodes.to = nodes.to.filter(filter);
26050               var connectFrom = false;
26051               var connectVia = false;
26052               var connectTo = false;
26053               var connectKeyFrom = false;
26054               var connectKeyTo = false;
26055
26056               for (j = 0; j < nodeIDs.length; j++) {
26057                 var n = nodeIDs[j];
26058
26059                 if (nodes.from.indexOf(n) !== -1) {
26060                   connectFrom = true;
26061                 }
26062
26063                 if (nodes.via.indexOf(n) !== -1) {
26064                   connectVia = true;
26065                 }
26066
26067                 if (nodes.to.indexOf(n) !== -1) {
26068                   connectTo = true;
26069                 }
26070
26071                 if (nodes.keyfrom.indexOf(n) !== -1) {
26072                   connectKeyFrom = true;
26073                 }
26074
26075                 if (nodes.keyto.indexOf(n) !== -1) {
26076                   connectKeyTo = true;
26077                 }
26078               }
26079
26080               if (connectFrom && connectTo && !isUturn) {
26081                 return 'restriction';
26082               }
26083
26084               if (connectFrom && connectVia) {
26085                 return 'restriction';
26086               }
26087
26088               if (connectTo && connectVia) {
26089                 return 'restriction';
26090               } // connecting to a key node -
26091               // if both nodes are on a member way (i.e. part of the turn restriction),
26092               // the connecting node must be adjacent to the key node.
26093
26094
26095               if (connectKeyFrom || connectKeyTo) {
26096                 if (nodeIDs.length !== 2) {
26097                   return 'restriction';
26098                 }
26099
26100                 var n0 = null;
26101                 var n1 = null;
26102
26103                 for (j = 0; j < memberWays.length; j++) {
26104                   way = memberWays[j];
26105
26106                   if (way.contains(nodeIDs[0])) {
26107                     n0 = nodeIDs[0];
26108                   }
26109
26110                   if (way.contains(nodeIDs[1])) {
26111                     n1 = nodeIDs[1];
26112                   }
26113                 }
26114
26115                 if (n0 && n1) {
26116                   // both nodes are part of the restriction
26117                   var ok = false;
26118
26119                   for (j = 0; j < memberWays.length; j++) {
26120                     way = memberWays[j];
26121
26122                     if (way.areAdjacent(n0, n1)) {
26123                       ok = true;
26124                       break;
26125                     }
26126                   }
26127
26128                   if (!ok) {
26129                     return 'restriction';
26130                   }
26131                 }
26132               } // 2b. disable if nodes being connected will destroy a member way in a restriction
26133               // (to test, make a copy and try actually connecting the nodes)
26134
26135
26136               for (j = 0; j < memberWays.length; j++) {
26137                 way = memberWays[j].update({}); // make copy
26138
26139                 for (k = 0; k < nodeIDs.length; k++) {
26140                   if (nodeIDs[k] === survivor.id) continue;
26141
26142                   if (way.areAdjacent(nodeIDs[k], survivor.id)) {
26143                     way = way.removeNode(nodeIDs[k]);
26144                   } else {
26145                     way = way.replaceNode(nodeIDs[k], survivor.id);
26146                   }
26147                 }
26148
26149                 if (way.isDegenerate()) {
26150                   return 'restriction';
26151                 }
26152               }
26153             }
26154
26155             return false; // if a key node appears multiple times (indexOf !== lastIndexOf) it's a FROM-VIA or TO-VIA junction
26156
26157             function hasDuplicates(n, i, arr) {
26158               return arr.indexOf(n) !== arr.lastIndexOf(n);
26159             }
26160
26161             function keyNodeFilter(froms, tos) {
26162               return function (n) {
26163                 return froms.indexOf(n) === -1 && tos.indexOf(n) === -1;
26164               };
26165             }
26166
26167             function collectNodes(member, collection) {
26168               var entity = graph.hasEntity(member.id);
26169               if (!entity) return;
26170               var role = member.role || '';
26171
26172               if (!collection[role]) {
26173                 collection[role] = [];
26174               }
26175
26176               if (member.type === 'node') {
26177                 collection[role].push(member.id);
26178
26179                 if (role === 'via') {
26180                   collection.keyfrom.push(member.id);
26181                   collection.keyto.push(member.id);
26182                 }
26183               } else if (member.type === 'way') {
26184                 collection[role].push.apply(collection[role], entity.nodes);
26185
26186                 if (role === 'from' || role === 'via') {
26187                   collection.keyfrom.push(entity.first());
26188                   collection.keyfrom.push(entity.last());
26189                 }
26190
26191                 if (role === 'to' || role === 'via') {
26192                   collection.keyto.push(entity.first());
26193                   collection.keyto.push(entity.last());
26194                 }
26195               }
26196             }
26197           };
26198
26199           return action;
26200         }
26201
26202         function actionCopyEntities(ids, fromGraph) {
26203           var _copies = {};
26204
26205           var action = function action(graph) {
26206             ids.forEach(function (id) {
26207               fromGraph.entity(id).copy(fromGraph, _copies);
26208             });
26209
26210             for (var id in _copies) {
26211               graph = graph.replace(_copies[id]);
26212             }
26213
26214             return graph;
26215           };
26216
26217           action.copies = function () {
26218             return _copies;
26219           };
26220
26221           return action;
26222         }
26223
26224         function actionDeleteMember(relationId, memberIndex) {
26225           return function (graph) {
26226             var relation = graph.entity(relationId).removeMember(memberIndex);
26227             graph = graph.replace(relation);
26228             if (relation.isDegenerate()) graph = actionDeleteRelation(relation.id)(graph);
26229             return graph;
26230           };
26231         }
26232
26233         function actionDiscardTags(difference, discardTags) {
26234           discardTags = discardTags || {};
26235           return function (graph) {
26236             difference.modified().forEach(checkTags);
26237             difference.created().forEach(checkTags);
26238             return graph;
26239
26240             function checkTags(entity) {
26241               var keys = Object.keys(entity.tags);
26242               var didDiscard = false;
26243               var tags = {};
26244
26245               for (var i = 0; i < keys.length; i++) {
26246                 var k = keys[i];
26247
26248                 if (discardTags[k] || !entity.tags[k]) {
26249                   didDiscard = true;
26250                 } else {
26251                   tags[k] = entity.tags[k];
26252                 }
26253               }
26254
26255               if (didDiscard) {
26256                 graph = graph.replace(entity.update({
26257                   tags: tags
26258                 }));
26259               }
26260             }
26261           };
26262         }
26263
26264         //
26265         // Optionally, disconnect only the given ways.
26266         //
26267         // For testing convenience, accepts an ID to assign to the (first) new node.
26268         // Normally, this will be undefined and the way will automatically
26269         // be assigned a new ID.
26270         //
26271         // This is the inverse of `iD.actionConnect`.
26272         //
26273         // Reference:
26274         //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
26275         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
26276         //
26277
26278         function actionDisconnect(nodeId, newNodeId) {
26279           var wayIds;
26280
26281           var action = function action(graph) {
26282             var node = graph.entity(nodeId);
26283             var connections = action.connections(graph);
26284             connections.forEach(function (connection) {
26285               var way = graph.entity(connection.wayID);
26286               var newNode = osmNode({
26287                 id: newNodeId,
26288                 loc: node.loc,
26289                 tags: node.tags
26290               });
26291               graph = graph.replace(newNode);
26292
26293               if (connection.index === 0 && way.isArea()) {
26294                 // replace shared node with shared node..
26295                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
26296               } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
26297                 // replace closing node with new new node..
26298                 graph = graph.replace(way.unclose().addNode(newNode.id));
26299               } else {
26300                 // replace shared node with multiple new nodes..
26301                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
26302               }
26303             });
26304             return graph;
26305           };
26306
26307           action.connections = function (graph) {
26308             var candidates = [];
26309             var keeping = false;
26310             var parentWays = graph.parentWays(graph.entity(nodeId));
26311             var way, waynode;
26312
26313             for (var i = 0; i < parentWays.length; i++) {
26314               way = parentWays[i];
26315
26316               if (wayIds && wayIds.indexOf(way.id) === -1) {
26317                 keeping = true;
26318                 continue;
26319               }
26320
26321               if (way.isArea() && way.nodes[0] === nodeId) {
26322                 candidates.push({
26323                   wayID: way.id,
26324                   index: 0
26325                 });
26326               } else {
26327                 for (var j = 0; j < way.nodes.length; j++) {
26328                   waynode = way.nodes[j];
26329
26330                   if (waynode === nodeId) {
26331                     if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j === way.nodes.length - 1) {
26332                       continue;
26333                     }
26334
26335                     candidates.push({
26336                       wayID: way.id,
26337                       index: j
26338                     });
26339                   }
26340                 }
26341               }
26342             }
26343
26344             return keeping ? candidates : candidates.slice(1);
26345           };
26346
26347           action.disabled = function (graph) {
26348             var connections = action.connections(graph);
26349             if (connections.length === 0) return 'not_connected';
26350             var parentWays = graph.parentWays(graph.entity(nodeId));
26351             var seenRelationIds = {};
26352             var sharedRelation;
26353             parentWays.forEach(function (way) {
26354               var relations = graph.parentRelations(way);
26355               relations.forEach(function (relation) {
26356                 if (relation.id in seenRelationIds) {
26357                   if (wayIds) {
26358                     if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
26359                       sharedRelation = relation;
26360                     }
26361                   } else {
26362                     sharedRelation = relation;
26363                   }
26364                 } else {
26365                   seenRelationIds[relation.id] = way.id;
26366                 }
26367               });
26368             });
26369             if (sharedRelation) return 'relation';
26370           };
26371
26372           action.limitWays = function (val) {
26373             if (!arguments.length) return wayIds;
26374             wayIds = val;
26375             return action;
26376           };
26377
26378           return action;
26379         }
26380
26381         var geojsonRewind = rewind;
26382
26383         function rewind(gj, outer) {
26384           var type = gj && gj.type,
26385               i;
26386
26387           if (type === 'FeatureCollection') {
26388             for (i = 0; i < gj.features.length; i++) {
26389               rewind(gj.features[i], outer);
26390             }
26391           } else if (type === 'GeometryCollection') {
26392             for (i = 0; i < gj.geometries.length; i++) {
26393               rewind(gj.geometries[i], outer);
26394             }
26395           } else if (type === 'Feature') {
26396             rewind(gj.geometry, outer);
26397           } else if (type === 'Polygon') {
26398             rewindRings(gj.coordinates, outer);
26399           } else if (type === 'MultiPolygon') {
26400             for (i = 0; i < gj.coordinates.length; i++) {
26401               rewindRings(gj.coordinates[i], outer);
26402             }
26403           }
26404
26405           return gj;
26406         }
26407
26408         function rewindRings(rings, outer) {
26409           if (rings.length === 0) return;
26410           rewindRing(rings[0], outer);
26411
26412           for (var i = 1; i < rings.length; i++) {
26413             rewindRing(rings[i], !outer);
26414           }
26415         }
26416
26417         function rewindRing(ring, dir) {
26418           var area = 0;
26419
26420           for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
26421             area += (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
26422           }
26423
26424           if (area >= 0 !== !!dir) ring.reverse();
26425         }
26426
26427         function actionExtract(entityID) {
26428           var extractedNodeID;
26429
26430           var action = function action(graph) {
26431             var entity = graph.entity(entityID);
26432
26433             if (entity.type === 'node') {
26434               return extractFromNode(entity, graph);
26435             }
26436
26437             return extractFromWayOrRelation(entity, graph);
26438           };
26439
26440           function extractFromNode(node, graph) {
26441             extractedNodeID = node.id; // Create a new node to replace the one we will detach
26442
26443             var replacement = osmNode({
26444               loc: node.loc
26445             });
26446             graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
26447
26448             graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
26449               return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
26450             }, graph); // Process any relations too
26451
26452             return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
26453               return accGraph.replace(parentRel.replaceMember(node, replacement));
26454             }, graph);
26455           }
26456
26457           function extractFromWayOrRelation(entity, graph) {
26458             var fromGeometry = entity.geometry(graph);
26459             var keysToCopyAndRetain = ['source', 'wheelchair'];
26460             var keysToRetain = ['area'];
26461             var buildingKeysToRetain = ['architect', 'building', 'height', 'layer']; // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
26462
26463             var extractedLoc = d3_geoCentroid(geojsonRewind(Object.assign({}, entity.asGeoJSON(graph)), true));
26464
26465             if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
26466               extractedLoc = entity.extent(graph).center();
26467             }
26468
26469             var indoorAreaValues = {
26470               area: true,
26471               corridor: true,
26472               elevator: true,
26473               level: true,
26474               room: true
26475             };
26476             var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
26477             var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
26478             var entityTags = Object.assign({}, entity.tags); // shallow copy
26479
26480             var pointTags = {};
26481
26482             for (var key in entityTags) {
26483               if (entity.type === 'relation' && key === 'type') {
26484                 continue;
26485               }
26486
26487               if (keysToRetain.indexOf(key) !== -1) {
26488                 continue;
26489               }
26490
26491               if (isBuilding) {
26492                 // don't transfer building-related tags
26493                 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
26494               } // leave `indoor` tag on the area
26495
26496
26497               if (isIndoorArea && key === 'indoor') {
26498                 continue;
26499               } // copy the tag from the entity to the point
26500
26501
26502               pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
26503
26504               if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
26505                 continue;
26506               } else if (isIndoorArea && key === 'level') {
26507                 // leave `level` on both features
26508                 continue;
26509               } // remove the tag from the entity
26510
26511
26512               delete entityTags[key];
26513             }
26514
26515             if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
26516               // ensure that areas keep area geometry
26517               entityTags.area = 'yes';
26518             }
26519
26520             var replacement = osmNode({
26521               loc: extractedLoc,
26522               tags: pointTags
26523             });
26524             graph = graph.replace(replacement);
26525             extractedNodeID = replacement.id;
26526             return graph.replace(entity.update({
26527               tags: entityTags
26528             }));
26529           }
26530
26531           action.getExtractedNodeID = function () {
26532             return extractedNodeID;
26533           };
26534
26535           return action;
26536         }
26537
26538         //
26539         // This is the inverse of `iD.actionSplit`.
26540         //
26541         // Reference:
26542         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
26543         //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
26544         //
26545
26546         function actionJoin(ids) {
26547           function groupEntitiesByGeometry(graph) {
26548             var entities = ids.map(function (id) {
26549               return graph.entity(id);
26550             });
26551             return Object.assign({
26552               line: []
26553             }, utilArrayGroupBy(entities, function (entity) {
26554               return entity.geometry(graph);
26555             }));
26556           }
26557
26558           var action = function action(graph) {
26559             var ways = ids.map(graph.entity, graph);
26560             var survivorID = ways[0].id; // if any of the ways are sided (e.g. coastline, cliff, kerb)
26561             // sort them first so they establish the overall order - #6033
26562
26563             ways.sort(function (a, b) {
26564               var aSided = a.isSided();
26565               var bSided = b.isSided();
26566               return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
26567             }); // Prefer to keep an existing way.
26568
26569             for (var i = 0; i < ways.length; i++) {
26570               if (!ways[i].isNew()) {
26571                 survivorID = ways[i].id;
26572                 break;
26573               }
26574             }
26575
26576             var sequences = osmJoinWays(ways, graph);
26577             var joined = sequences[0]; // We might need to reverse some of these ways before joining them.  #4688
26578             // `joined.actions` property will contain any actions we need to apply.
26579
26580             graph = sequences.actions.reduce(function (g, action) {
26581               return action(g);
26582             }, graph);
26583             var survivor = graph.entity(survivorID);
26584             survivor = survivor.update({
26585               nodes: joined.nodes.map(function (n) {
26586                 return n.id;
26587               })
26588             });
26589             graph = graph.replace(survivor);
26590             joined.forEach(function (way) {
26591               if (way.id === survivorID) return;
26592               graph.parentRelations(way).forEach(function (parent) {
26593                 graph = graph.replace(parent.replaceMember(way, survivor));
26594               });
26595               survivor = survivor.mergeTags(way.tags);
26596               graph = graph.replace(survivor);
26597               graph = actionDeleteWay(way.id)(graph);
26598             }); // Finds if the join created a single-member multipolygon,
26599             // and if so turns it into a basic area instead
26600
26601             function checkForSimpleMultipolygon() {
26602               if (!survivor.isClosed()) return;
26603               var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
26604                 // find multipolygons where the survivor is the only member
26605                 return multipolygon.members.length === 1;
26606               }); // skip if this is the single member of multiple multipolygons
26607
26608               if (multipolygons.length !== 1) return;
26609               var multipolygon = multipolygons[0];
26610
26611               for (var key in survivor.tags) {
26612                 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
26613                 multipolygon.tags[key] !== survivor.tags[key]) return;
26614               }
26615
26616               survivor = survivor.mergeTags(multipolygon.tags);
26617               graph = graph.replace(survivor);
26618               graph = actionDeleteRelation(multipolygon.id, true
26619               /* allow untagged members */
26620               )(graph);
26621               var tags = Object.assign({}, survivor.tags);
26622
26623               if (survivor.geometry(graph) !== 'area') {
26624                 // ensure the feature persists as an area
26625                 tags.area = 'yes';
26626               }
26627
26628               delete tags.type; // remove type=multipolygon
26629
26630               survivor = survivor.update({
26631                 tags: tags
26632               });
26633               graph = graph.replace(survivor);
26634             }
26635
26636             checkForSimpleMultipolygon();
26637             return graph;
26638           }; // Returns the number of nodes the resultant way is expected to have
26639
26640
26641           action.resultingWayNodesLength = function (graph) {
26642             return ids.reduce(function (count, id) {
26643               return count + graph.entity(id).nodes.length;
26644             }, 0) - ids.length - 1;
26645           };
26646
26647           action.disabled = function (graph) {
26648             var geometries = groupEntitiesByGeometry(graph);
26649
26650             if (ids.length < 2 || ids.length !== geometries.line.length) {
26651               return 'not_eligible';
26652             }
26653
26654             var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
26655
26656             if (joined.length > 1) {
26657               return 'not_adjacent';
26658             } // Loop through all combinations of path-pairs
26659             // to check potential intersections between all pairs
26660
26661
26662             for (var i = 0; i < ids.length - 1; i++) {
26663               for (var j = i + 1; j < ids.length; j++) {
26664                 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
26665                   return e.loc;
26666                 });
26667                 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
26668                   return e.loc;
26669                 });
26670                 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
26671                 // each other/the line, as opposed to crossing it
26672
26673                 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
26674                   return n.loc.toString();
26675                 }), intersections.map(function (n) {
26676                   return n.toString();
26677                 }));
26678
26679                 if (common.length !== intersections.length) {
26680                   return 'paths_intersect';
26681                 }
26682               }
26683             }
26684
26685             var nodeIds = joined[0].nodes.map(function (n) {
26686               return n.id;
26687             }).slice(1, -1);
26688             var relation;
26689             var tags = {};
26690             var conflicting = false;
26691             joined[0].forEach(function (way) {
26692               var parents = graph.parentRelations(way);
26693               parents.forEach(function (parent) {
26694                 if (parent.isRestriction() && parent.members.some(function (m) {
26695                   return nodeIds.indexOf(m.id) >= 0;
26696                 })) {
26697                   relation = parent;
26698                 }
26699               });
26700
26701               for (var k in way.tags) {
26702                 if (!(k in tags)) {
26703                   tags[k] = way.tags[k];
26704                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
26705                   conflicting = true;
26706                 }
26707               }
26708             });
26709
26710             if (relation) {
26711               return 'restriction';
26712             }
26713
26714             if (conflicting) {
26715               return 'conflicting_tags';
26716             }
26717           };
26718
26719           return action;
26720         }
26721
26722         function actionMerge(ids) {
26723           function groupEntitiesByGeometry(graph) {
26724             var entities = ids.map(function (id) {
26725               return graph.entity(id);
26726             });
26727             return Object.assign({
26728               point: [],
26729               area: [],
26730               line: [],
26731               relation: []
26732             }, utilArrayGroupBy(entities, function (entity) {
26733               return entity.geometry(graph);
26734             }));
26735           }
26736
26737           var action = function action(graph) {
26738             var geometries = groupEntitiesByGeometry(graph);
26739             var target = geometries.area[0] || geometries.line[0];
26740             var points = geometries.point;
26741             points.forEach(function (point) {
26742               target = target.mergeTags(point.tags);
26743               graph = graph.replace(target);
26744               graph.parentRelations(point).forEach(function (parent) {
26745                 graph = graph.replace(parent.replaceMember(point, target));
26746               });
26747               var nodes = utilArrayUniq(graph.childNodes(target));
26748               var removeNode = point;
26749
26750               for (var i = 0; i < nodes.length; i++) {
26751                 var node = nodes[i];
26752
26753                 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
26754                   continue;
26755                 } // Found an uninteresting child node on the target way.
26756                 // Move orig point into its place to preserve point's history. #3683
26757
26758
26759                 graph = graph.replace(point.update({
26760                   tags: {},
26761                   loc: node.loc
26762                 }));
26763                 target = target.replaceNode(node.id, point.id);
26764                 graph = graph.replace(target);
26765                 removeNode = node;
26766                 break;
26767               }
26768
26769               graph = graph.remove(removeNode);
26770             });
26771
26772             if (target.tags.area === 'yes') {
26773               var tags = Object.assign({}, target.tags); // shallow copy
26774
26775               delete tags.area;
26776
26777               if (osmTagSuggestingArea(tags)) {
26778                 // remove the `area` tag if area geometry is now implied - #3851
26779                 target = target.update({
26780                   tags: tags
26781                 });
26782                 graph = graph.replace(target);
26783               }
26784             }
26785
26786             return graph;
26787           };
26788
26789           action.disabled = function (graph) {
26790             var geometries = groupEntitiesByGeometry(graph);
26791
26792             if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
26793               return 'not_eligible';
26794             }
26795           };
26796
26797           return action;
26798         }
26799
26800         //
26801         // 1. move all the nodes to a common location
26802         // 2. `actionConnect` them
26803
26804         function actionMergeNodes(nodeIDs, loc) {
26805           // If there is a single "interesting" node, use that as the location.
26806           // Otherwise return the average location of all the nodes.
26807           function chooseLoc(graph) {
26808             if (!nodeIDs.length) return null;
26809             var sum = [0, 0];
26810             var interestingCount = 0;
26811             var interestingLoc;
26812
26813             for (var i = 0; i < nodeIDs.length; i++) {
26814               var node = graph.entity(nodeIDs[i]);
26815
26816               if (node.hasInterestingTags()) {
26817                 interestingLoc = ++interestingCount === 1 ? node.loc : null;
26818               }
26819
26820               sum = geoVecAdd(sum, node.loc);
26821             }
26822
26823             return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
26824           }
26825
26826           var action = function action(graph) {
26827             if (nodeIDs.length < 2) return graph;
26828             var toLoc = loc;
26829
26830             if (!toLoc) {
26831               toLoc = chooseLoc(graph);
26832             }
26833
26834             for (var i = 0; i < nodeIDs.length; i++) {
26835               var node = graph.entity(nodeIDs[i]);
26836
26837               if (node.loc !== toLoc) {
26838                 graph = graph.replace(node.move(toLoc));
26839               }
26840             }
26841
26842             return actionConnect(nodeIDs)(graph);
26843           };
26844
26845           action.disabled = function (graph) {
26846             if (nodeIDs.length < 2) return 'not_eligible';
26847
26848             for (var i = 0; i < nodeIDs.length; i++) {
26849               var entity = graph.entity(nodeIDs[i]);
26850               if (entity.type !== 'node') return 'not_eligible';
26851             }
26852
26853             return actionConnect(nodeIDs).disabled(graph);
26854           };
26855
26856           return action;
26857         }
26858
26859         function osmChangeset() {
26860           if (!(this instanceof osmChangeset)) {
26861             return new osmChangeset().initialize(arguments);
26862           } else if (arguments.length) {
26863             this.initialize(arguments);
26864           }
26865         }
26866         osmEntity.changeset = osmChangeset;
26867         osmChangeset.prototype = Object.create(osmEntity.prototype);
26868         Object.assign(osmChangeset.prototype, {
26869           type: 'changeset',
26870           extent: function extent() {
26871             return new geoExtent();
26872           },
26873           geometry: function geometry() {
26874             return 'changeset';
26875           },
26876           asJXON: function asJXON() {
26877             return {
26878               osm: {
26879                 changeset: {
26880                   tag: Object.keys(this.tags).map(function (k) {
26881                     return {
26882                       '@k': k,
26883                       '@v': this.tags[k]
26884                     };
26885                   }, this),
26886                   '@version': 0.6,
26887                   '@generator': 'iD'
26888                 }
26889               }
26890             };
26891           },
26892           // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26893           // XML. Returns a string.
26894           osmChangeJXON: function osmChangeJXON(changes) {
26895             var changeset_id = this.id;
26896
26897             function nest(x, order) {
26898               var groups = {};
26899
26900               for (var i = 0; i < x.length; i++) {
26901                 var tagName = Object.keys(x[i])[0];
26902                 if (!groups[tagName]) groups[tagName] = [];
26903                 groups[tagName].push(x[i][tagName]);
26904               }
26905
26906               var ordered = {};
26907               order.forEach(function (o) {
26908                 if (groups[o]) ordered[o] = groups[o];
26909               });
26910               return ordered;
26911             } // sort relations in a changeset by dependencies
26912
26913
26914             function sort(changes) {
26915               // find a referenced relation in the current changeset
26916               function resolve(item) {
26917                 return relations.find(function (relation) {
26918                   return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
26919                 });
26920               } // a new item is an item that has not been already processed
26921
26922
26923               function isNew(item) {
26924                 return !sorted[item['@id']] && !processing.find(function (proc) {
26925                   return proc['@id'] === item['@id'];
26926                 });
26927               }
26928
26929               var processing = [];
26930               var sorted = {};
26931               var relations = changes.relation;
26932               if (!relations) return changes;
26933
26934               for (var i = 0; i < relations.length; i++) {
26935                 var relation = relations[i]; // skip relation if already sorted
26936
26937                 if (!sorted[relation['@id']]) {
26938                   processing.push(relation);
26939                 }
26940
26941                 while (processing.length > 0) {
26942                   var next = processing[0],
26943                       deps = next.member.map(resolve).filter(Boolean).filter(isNew);
26944
26945                   if (deps.length === 0) {
26946                     sorted[next['@id']] = next;
26947                     processing.shift();
26948                   } else {
26949                     processing = deps.concat(processing);
26950                   }
26951                 }
26952               }
26953
26954               changes.relation = Object.values(sorted);
26955               return changes;
26956             }
26957
26958             function rep(entity) {
26959               return entity.asJXON(changeset_id);
26960             }
26961
26962             return {
26963               osmChange: {
26964                 '@version': 0.6,
26965                 '@generator': 'iD',
26966                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
26967                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26968                 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
26969                   '@if-unused': true
26970                 })
26971               }
26972             };
26973           },
26974           asGeoJSON: function asGeoJSON() {
26975             return {};
26976           }
26977         });
26978
26979         function osmNote() {
26980           if (!(this instanceof osmNote)) {
26981             return new osmNote().initialize(arguments);
26982           } else if (arguments.length) {
26983             this.initialize(arguments);
26984           }
26985         }
26986
26987         osmNote.id = function () {
26988           return osmNote.id.next--;
26989         };
26990
26991         osmNote.id.next = -1;
26992         Object.assign(osmNote.prototype, {
26993           type: 'note',
26994           initialize: function initialize(sources) {
26995             for (var i = 0; i < sources.length; ++i) {
26996               var source = sources[i];
26997
26998               for (var prop in source) {
26999                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
27000                   if (source[prop] === undefined) {
27001                     delete this[prop];
27002                   } else {
27003                     this[prop] = source[prop];
27004                   }
27005                 }
27006               }
27007             }
27008
27009             if (!this.id) {
27010               this.id = osmNote.id().toString();
27011             }
27012
27013             return this;
27014           },
27015           extent: function extent() {
27016             return new geoExtent(this.loc);
27017           },
27018           update: function update(attrs) {
27019             return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
27020           },
27021           isNew: function isNew() {
27022             return this.id < 0;
27023           },
27024           move: function move(loc) {
27025             return this.update({
27026               loc: loc
27027             });
27028           }
27029         });
27030
27031         function osmRelation() {
27032           if (!(this instanceof osmRelation)) {
27033             return new osmRelation().initialize(arguments);
27034           } else if (arguments.length) {
27035             this.initialize(arguments);
27036           }
27037         }
27038         osmEntity.relation = osmRelation;
27039         osmRelation.prototype = Object.create(osmEntity.prototype);
27040
27041         osmRelation.creationOrder = function (a, b) {
27042           var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
27043           var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
27044           if (aId < 0 || bId < 0) return aId - bId;
27045           return bId - aId;
27046         };
27047
27048         Object.assign(osmRelation.prototype, {
27049           type: 'relation',
27050           members: [],
27051           copy: function copy(resolver, copies) {
27052             if (copies[this.id]) return copies[this.id];
27053             var copy = osmEntity.prototype.copy.call(this, resolver, copies);
27054             var members = this.members.map(function (member) {
27055               return Object.assign({}, member, {
27056                 id: resolver.entity(member.id).copy(resolver, copies).id
27057               });
27058             });
27059             copy = copy.update({
27060               members: members
27061             });
27062             copies[this.id] = copy;
27063             return copy;
27064           },
27065           extent: function extent(resolver, memo) {
27066             return resolver["transient"](this, 'extent', function () {
27067               if (memo && memo[this.id]) return geoExtent();
27068               memo = memo || {};
27069               memo[this.id] = true;
27070               var extent = geoExtent();
27071
27072               for (var i = 0; i < this.members.length; i++) {
27073                 var member = resolver.hasEntity(this.members[i].id);
27074
27075                 if (member) {
27076                   extent._extend(member.extent(resolver, memo));
27077                 }
27078               }
27079
27080               return extent;
27081             });
27082           },
27083           geometry: function geometry(graph) {
27084             return graph["transient"](this, 'geometry', function () {
27085               return this.isMultipolygon() ? 'area' : 'relation';
27086             });
27087           },
27088           isDegenerate: function isDegenerate() {
27089             return this.members.length === 0;
27090           },
27091           // Return an array of members, each extended with an 'index' property whose value
27092           // is the member index.
27093           indexedMembers: function indexedMembers() {
27094             var result = new Array(this.members.length);
27095
27096             for (var i = 0; i < this.members.length; i++) {
27097               result[i] = Object.assign({}, this.members[i], {
27098                 index: i
27099               });
27100             }
27101
27102             return result;
27103           },
27104           // Return the first member with the given role. A copy of the member object
27105           // is returned, extended with an 'index' property whose value is the member index.
27106           memberByRole: function memberByRole(role) {
27107             for (var i = 0; i < this.members.length; i++) {
27108               if (this.members[i].role === role) {
27109                 return Object.assign({}, this.members[i], {
27110                   index: i
27111                 });
27112               }
27113             }
27114           },
27115           // Same as memberByRole, but returns all members with the given role
27116           membersByRole: function membersByRole(role) {
27117             var result = [];
27118
27119             for (var i = 0; i < this.members.length; i++) {
27120               if (this.members[i].role === role) {
27121                 result.push(Object.assign({}, this.members[i], {
27122                   index: i
27123                 }));
27124               }
27125             }
27126
27127             return result;
27128           },
27129           // Return the first member with the given id. A copy of the member object
27130           // is returned, extended with an 'index' property whose value is the member index.
27131           memberById: function memberById(id) {
27132             for (var i = 0; i < this.members.length; i++) {
27133               if (this.members[i].id === id) {
27134                 return Object.assign({}, this.members[i], {
27135                   index: i
27136                 });
27137               }
27138             }
27139           },
27140           // Return the first member with the given id and role. A copy of the member object
27141           // is returned, extended with an 'index' property whose value is the member index.
27142           memberByIdAndRole: function memberByIdAndRole(id, role) {
27143             for (var i = 0; i < this.members.length; i++) {
27144               if (this.members[i].id === id && this.members[i].role === role) {
27145                 return Object.assign({}, this.members[i], {
27146                   index: i
27147                 });
27148               }
27149             }
27150           },
27151           addMember: function addMember(member, index) {
27152             var members = this.members.slice();
27153             members.splice(index === undefined ? members.length : index, 0, member);
27154             return this.update({
27155               members: members
27156             });
27157           },
27158           updateMember: function updateMember(member, index) {
27159             var members = this.members.slice();
27160             members.splice(index, 1, Object.assign({}, members[index], member));
27161             return this.update({
27162               members: members
27163             });
27164           },
27165           removeMember: function removeMember(index) {
27166             var members = this.members.slice();
27167             members.splice(index, 1);
27168             return this.update({
27169               members: members
27170             });
27171           },
27172           removeMembersWithID: function removeMembersWithID(id) {
27173             var members = this.members.filter(function (m) {
27174               return m.id !== id;
27175             });
27176             return this.update({
27177               members: members
27178             });
27179           },
27180           moveMember: function moveMember(fromIndex, toIndex) {
27181             var members = this.members.slice();
27182             members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
27183             return this.update({
27184               members: members
27185             });
27186           },
27187           // Wherever a member appears with id `needle.id`, replace it with a member
27188           // with id `replacement.id`, type `replacement.type`, and the original role,
27189           // By default, adding a duplicate member (by id and role) is prevented.
27190           // Return an updated relation.
27191           replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
27192             if (!this.memberById(needle.id)) return this;
27193             var members = [];
27194
27195             for (var i = 0; i < this.members.length; i++) {
27196               var member = this.members[i];
27197
27198               if (member.id !== needle.id) {
27199                 members.push(member);
27200               } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
27201                 members.push({
27202                   id: replacement.id,
27203                   type: replacement.type,
27204                   role: member.role
27205                 });
27206               }
27207             }
27208
27209             return this.update({
27210               members: members
27211             });
27212           },
27213           asJXON: function asJXON(changeset_id) {
27214             var r = {
27215               relation: {
27216                 '@id': this.osmId(),
27217                 '@version': this.version || 0,
27218                 member: this.members.map(function (member) {
27219                   return {
27220                     keyAttributes: {
27221                       type: member.type,
27222                       role: member.role,
27223                       ref: osmEntity.id.toOSM(member.id)
27224                     }
27225                   };
27226                 }, this),
27227                 tag: Object.keys(this.tags).map(function (k) {
27228                   return {
27229                     keyAttributes: {
27230                       k: k,
27231                       v: this.tags[k]
27232                     }
27233                   };
27234                 }, this)
27235               }
27236             };
27237
27238             if (changeset_id) {
27239               r.relation['@changeset'] = changeset_id;
27240             }
27241
27242             return r;
27243           },
27244           asGeoJSON: function asGeoJSON(resolver) {
27245             return resolver["transient"](this, 'GeoJSON', function () {
27246               if (this.isMultipolygon()) {
27247                 return {
27248                   type: 'MultiPolygon',
27249                   coordinates: this.multipolygon(resolver)
27250                 };
27251               } else {
27252                 return {
27253                   type: 'FeatureCollection',
27254                   properties: this.tags,
27255                   features: this.members.map(function (member) {
27256                     return Object.assign({
27257                       role: member.role
27258                     }, resolver.entity(member.id).asGeoJSON(resolver));
27259                   })
27260                 };
27261               }
27262             });
27263           },
27264           area: function area(resolver) {
27265             return resolver["transient"](this, 'area', function () {
27266               return d3_geoArea(this.asGeoJSON(resolver));
27267             });
27268           },
27269           isMultipolygon: function isMultipolygon() {
27270             return this.tags.type === 'multipolygon';
27271           },
27272           isComplete: function isComplete(resolver) {
27273             for (var i = 0; i < this.members.length; i++) {
27274               if (!resolver.hasEntity(this.members[i].id)) {
27275                 return false;
27276               }
27277             }
27278
27279             return true;
27280           },
27281           hasFromViaTo: function hasFromViaTo() {
27282             return this.members.some(function (m) {
27283               return m.role === 'from';
27284             }) && this.members.some(function (m) {
27285               return m.role === 'via';
27286             }) && this.members.some(function (m) {
27287               return m.role === 'to';
27288             });
27289           },
27290           isRestriction: function isRestriction() {
27291             return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27292           },
27293           isValidRestriction: function isValidRestriction() {
27294             if (!this.isRestriction()) return false;
27295             var froms = this.members.filter(function (m) {
27296               return m.role === 'from';
27297             });
27298             var vias = this.members.filter(function (m) {
27299               return m.role === 'via';
27300             });
27301             var tos = this.members.filter(function (m) {
27302               return m.role === 'to';
27303             });
27304             if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
27305             if (froms.some(function (m) {
27306               return m.type !== 'way';
27307             })) return false;
27308             if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
27309             if (tos.some(function (m) {
27310               return m.type !== 'way';
27311             })) return false;
27312             if (vias.length === 0) return false;
27313             if (vias.length > 1 && vias.some(function (m) {
27314               return m.type !== 'way';
27315             })) return false;
27316             return true;
27317           },
27318           // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27319           // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27320           //
27321           // This corresponds to the structure needed for rendering a multipolygon path using a
27322           // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27323           //
27324           // In the case of invalid geometries, this function will still return a result which
27325           // includes the nodes of all way members, but some Nds may be unclosed and some inner
27326           // rings not matched with the intended outer ring.
27327           //
27328           multipolygon: function multipolygon(resolver) {
27329             var outers = this.members.filter(function (m) {
27330               return 'outer' === (m.role || 'outer');
27331             });
27332             var inners = this.members.filter(function (m) {
27333               return 'inner' === m.role;
27334             });
27335             outers = osmJoinWays(outers, resolver);
27336             inners = osmJoinWays(inners, resolver);
27337
27338             var sequenceToLineString = function sequenceToLineString(sequence) {
27339               if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
27340                 // close unclosed parts to ensure correct area rendering - #2945
27341                 sequence.nodes.push(sequence.nodes[0]);
27342               }
27343
27344               return sequence.nodes.map(function (node) {
27345                 return node.loc;
27346               });
27347             };
27348
27349             outers = outers.map(sequenceToLineString);
27350             inners = inners.map(sequenceToLineString);
27351             var result = outers.map(function (o) {
27352               // Heuristic for detecting counterclockwise winding order. Assumes
27353               // that OpenStreetMap polygons are not hemisphere-spanning.
27354               return [d3_geoArea({
27355                 type: 'Polygon',
27356                 coordinates: [o]
27357               }) > 2 * Math.PI ? o.reverse() : o];
27358             });
27359
27360             function findOuter(inner) {
27361               var o, outer;
27362
27363               for (o = 0; o < outers.length; o++) {
27364                 outer = outers[o];
27365                 if (geoPolygonContainsPolygon(outer, inner)) return o;
27366               }
27367
27368               for (o = 0; o < outers.length; o++) {
27369                 outer = outers[o];
27370                 if (geoPolygonIntersectsPolygon(outer, inner, false)) return o;
27371               }
27372             }
27373
27374             for (var i = 0; i < inners.length; i++) {
27375               var inner = inners[i];
27376
27377               if (d3_geoArea({
27378                 type: 'Polygon',
27379                 coordinates: [inner]
27380               }) < 2 * Math.PI) {
27381                 inner = inner.reverse();
27382               }
27383
27384               var o = findOuter(inners[i]);
27385
27386               if (o !== undefined) {
27387                 result[o].push(inners[i]);
27388               } else {
27389                 result.push([inners[i]]); // Invalid geometry
27390               }
27391             }
27392
27393             return result;
27394           }
27395         });
27396
27397         var QAItem = /*#__PURE__*/function () {
27398           function QAItem(loc, service, itemType, id, props) {
27399             _classCallCheck(this, QAItem);
27400
27401             // Store required properties
27402             this.loc = loc;
27403             this.service = service.title;
27404             this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
27405
27406             this.id = id ? id : "".concat(QAItem.id());
27407             this.update(props); // Some QA services have marker icons to differentiate issues
27408
27409             if (service && typeof service.getIcon === 'function') {
27410               this.icon = service.getIcon(itemType);
27411             }
27412           }
27413
27414           _createClass(QAItem, [{
27415             key: "update",
27416             value: function update(props) {
27417               var _this = this;
27418
27419               // You can't override this initial information
27420               var loc = this.loc,
27421                   service = this.service,
27422                   itemType = this.itemType,
27423                   id = this.id;
27424               Object.keys(props).forEach(function (prop) {
27425                 return _this[prop] = props[prop];
27426               });
27427               this.loc = loc;
27428               this.service = service;
27429               this.itemType = itemType;
27430               this.id = id;
27431               return this;
27432             } // Generic handling for newly created QAItems
27433
27434           }], [{
27435             key: "id",
27436             value: function id() {
27437               return this.nextId--;
27438             }
27439           }]);
27440
27441           return QAItem;
27442         }();
27443         QAItem.nextId = -1;
27444
27445         //
27446         // Optionally, split only the given ways, if multiple ways share
27447         // the given node.
27448         //
27449         // This is the inverse of `iD.actionJoin`.
27450         //
27451         // For testing convenience, accepts an ID to assign to the new way.
27452         // Normally, this will be undefined and the way will automatically
27453         // be assigned a new ID.
27454         //
27455         // Reference:
27456         //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
27457         //
27458
27459         function actionSplit(nodeIds, newWayIds) {
27460           // accept single ID for backwards-compatiblity
27461           if (typeof nodeIds === 'string') nodeIds = [nodeIds];
27462
27463           var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
27464
27465
27466           var _keepHistoryOn = 'longest'; // 'longest', 'first'
27467           // The IDs of the ways actually created by running this action
27468
27469           var _createdWayIDs = [];
27470
27471           function dist(graph, nA, nB) {
27472             var locA = graph.entity(nA).loc;
27473             var locB = graph.entity(nB).loc;
27474             var epsilon = 1e-6;
27475             return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
27476           } // If the way is closed, we need to search for a partner node
27477           // to split the way at.
27478           //
27479           // The following looks for a node that is both far away from
27480           // the initial node in terms of way segment length and nearby
27481           // in terms of beeline-distance. This assures that areas get
27482           // split on the most "natural" points (independent of the number
27483           // of nodes).
27484           // For example: bone-shaped areas get split across their waist
27485           // line, circles across the diameter.
27486
27487
27488           function splitArea(nodes, idxA, graph) {
27489             var lengths = new Array(nodes.length);
27490             var length;
27491             var i;
27492             var best = 0;
27493             var idxB;
27494
27495             function wrap(index) {
27496               return utilWrap(index, nodes.length);
27497             } // calculate lengths
27498
27499
27500             length = 0;
27501
27502             for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
27503               length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
27504               lengths[i] = length;
27505             }
27506
27507             length = 0;
27508
27509             for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
27510               length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
27511
27512               if (length < lengths[i]) {
27513                 lengths[i] = length;
27514               }
27515             } // determine best opposite node to split
27516
27517
27518             for (i = 0; i < nodes.length; i++) {
27519               var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
27520
27521               if (cost > best) {
27522                 idxB = i;
27523                 best = cost;
27524               }
27525             }
27526
27527             return idxB;
27528           }
27529
27530           function totalLengthBetweenNodes(graph, nodes) {
27531             var totalLength = 0;
27532
27533             for (var i = 0; i < nodes.length - 1; i++) {
27534               totalLength += dist(graph, nodes[i], nodes[i + 1]);
27535             }
27536
27537             return totalLength;
27538           }
27539
27540           function split(graph, nodeId, wayA, newWayId) {
27541             var wayB = osmWay({
27542               id: newWayId,
27543               tags: wayA.tags
27544             }); // `wayB` is the NEW way
27545
27546             var origNodes = wayA.nodes.slice();
27547             var nodesA;
27548             var nodesB;
27549             var isArea = wayA.isArea();
27550             var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
27551
27552             if (wayA.isClosed()) {
27553               var nodes = wayA.nodes.slice(0, -1);
27554               var idxA = nodes.indexOf(nodeId);
27555               var idxB = splitArea(nodes, idxA, graph);
27556
27557               if (idxB < idxA) {
27558                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
27559                 nodesB = nodes.slice(idxB, idxA + 1);
27560               } else {
27561                 nodesA = nodes.slice(idxA, idxB + 1);
27562                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
27563               }
27564             } else {
27565               var idx = wayA.nodes.indexOf(nodeId, 1);
27566               nodesA = wayA.nodes.slice(0, idx + 1);
27567               nodesB = wayA.nodes.slice(idx);
27568             }
27569
27570             var lengthA = totalLengthBetweenNodes(graph, nodesA);
27571             var lengthB = totalLengthBetweenNodes(graph, nodesB);
27572
27573             if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
27574               // keep the history on the longer way, regardless of the node count
27575               wayA = wayA.update({
27576                 nodes: nodesB
27577               });
27578               wayB = wayB.update({
27579                 nodes: nodesA
27580               });
27581               var temp = lengthA;
27582               lengthA = lengthB;
27583               lengthB = temp;
27584             } else {
27585               wayA = wayA.update({
27586                 nodes: nodesA
27587               });
27588               wayB = wayB.update({
27589                 nodes: nodesB
27590               });
27591             }
27592
27593             if (wayA.tags.step_count) {
27594               // divide up the the step count proportionally between the two ways
27595               var stepCount = parseFloat(wayA.tags.step_count);
27596
27597               if (stepCount && // ensure a number
27598               isFinite(stepCount) && // ensure positive
27599               stepCount > 0 && // ensure integer
27600               Math.round(stepCount) === stepCount) {
27601                 var tagsA = Object.assign({}, wayA.tags);
27602                 var tagsB = Object.assign({}, wayB.tags);
27603                 var ratioA = lengthA / (lengthA + lengthB);
27604                 var countA = Math.round(stepCount * ratioA);
27605                 tagsA.step_count = countA.toString();
27606                 tagsB.step_count = (stepCount - countA).toString();
27607                 wayA = wayA.update({
27608                   tags: tagsA
27609                 });
27610                 wayB = wayB.update({
27611                   tags: tagsB
27612                 });
27613               }
27614             }
27615
27616             graph = graph.replace(wayA);
27617             graph = graph.replace(wayB);
27618             graph.parentRelations(wayA).forEach(function (relation) {
27619               var member; // Turn restrictions - make sure:
27620               // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
27621               //    (whichever one is connected to the VIA node/ways)
27622               // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
27623
27624               if (relation.hasFromViaTo()) {
27625                 var f = relation.memberByRole('from');
27626                 var v = relation.membersByRole('via');
27627                 var t = relation.memberByRole('to');
27628                 var i; // 1. split a FROM/TO
27629
27630                 if (f.id === wayA.id || t.id === wayA.id) {
27631                   var keepB = false;
27632
27633                   if (v.length === 1 && v[0].type === 'node') {
27634                     // check via node
27635                     keepB = wayB.contains(v[0].id);
27636                   } else {
27637                     // check via way(s)
27638                     for (i = 0; i < v.length; i++) {
27639                       if (v[i].type === 'way') {
27640                         var wayVia = graph.hasEntity(v[i].id);
27641
27642                         if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
27643                           keepB = true;
27644                           break;
27645                         }
27646                       }
27647                     }
27648                   }
27649
27650                   if (keepB) {
27651                     relation = relation.replaceMember(wayA, wayB);
27652                     graph = graph.replace(relation);
27653                   } // 2. split a VIA
27654
27655                 } else {
27656                   for (i = 0; i < v.length; i++) {
27657                     if (v[i].type === 'way' && v[i].id === wayA.id) {
27658                       member = {
27659                         id: wayB.id,
27660                         type: 'way',
27661                         role: 'via'
27662                       };
27663                       graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
27664                       break;
27665                     }
27666                   }
27667                 } // All other relations (Routes, Multipolygons, etc):
27668                 // 1. Both `wayA` and `wayB` remain in the relation
27669                 // 2. But must be inserted as a pair (see `actionAddMember` for details)
27670
27671               } else {
27672                 if (relation === isOuter) {
27673                   graph = graph.replace(relation.mergeTags(wayA.tags));
27674                   graph = graph.replace(wayA.update({
27675                     tags: {}
27676                   }));
27677                   graph = graph.replace(wayB.update({
27678                     tags: {}
27679                   }));
27680                 }
27681
27682                 member = {
27683                   id: wayB.id,
27684                   type: 'way',
27685                   role: relation.memberById(wayA.id).role
27686                 };
27687                 var insertPair = {
27688                   originalID: wayA.id,
27689                   insertedID: wayB.id,
27690                   nodes: origNodes
27691                 };
27692                 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
27693               }
27694             });
27695
27696             if (!isOuter && isArea) {
27697               var multipolygon = osmRelation({
27698                 tags: Object.assign({}, wayA.tags, {
27699                   type: 'multipolygon'
27700                 }),
27701                 members: [{
27702                   id: wayA.id,
27703                   role: 'outer',
27704                   type: 'way'
27705                 }, {
27706                   id: wayB.id,
27707                   role: 'outer',
27708                   type: 'way'
27709                 }]
27710               });
27711               graph = graph.replace(multipolygon);
27712               graph = graph.replace(wayA.update({
27713                 tags: {}
27714               }));
27715               graph = graph.replace(wayB.update({
27716                 tags: {}
27717               }));
27718             }
27719
27720             _createdWayIDs.push(wayB.id);
27721
27722             return graph;
27723           }
27724
27725           var action = function action(graph) {
27726             _createdWayIDs = [];
27727             var newWayIndex = 0;
27728
27729             for (var i = 0; i < nodeIds.length; i++) {
27730               var nodeId = nodeIds[i];
27731               var candidates = action.waysForNode(nodeId, graph);
27732
27733               for (var j = 0; j < candidates.length; j++) {
27734                 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
27735                 newWayIndex += 1;
27736               }
27737             }
27738
27739             return graph;
27740           };
27741
27742           action.getCreatedWayIDs = function () {
27743             return _createdWayIDs;
27744           };
27745
27746           action.waysForNode = function (nodeId, graph) {
27747             var node = graph.entity(nodeId);
27748             var splittableParents = graph.parentWays(node).filter(isSplittable);
27749
27750             if (!_wayIDs) {
27751               // If the ways to split aren't specified, only split the lines.
27752               // If there are no lines to split, split the areas.
27753               var hasLine = splittableParents.some(function (parent) {
27754                 return parent.geometry(graph) === 'line';
27755               });
27756
27757               if (hasLine) {
27758                 return splittableParents.filter(function (parent) {
27759                   return parent.geometry(graph) === 'line';
27760                 });
27761               }
27762             }
27763
27764             return splittableParents;
27765
27766             function isSplittable(parent) {
27767               // If the ways to split are specified, ignore everything else.
27768               if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
27769
27770               if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
27771
27772               for (var i = 1; i < parent.nodes.length - 1; i++) {
27773                 if (parent.nodes[i] === nodeId) return true;
27774               }
27775
27776               return false;
27777             }
27778           };
27779
27780           action.ways = function (graph) {
27781             return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
27782               return action.waysForNode(nodeId, graph);
27783             })));
27784           };
27785
27786           action.disabled = function (graph) {
27787             for (var i = 0; i < nodeIds.length; i++) {
27788               var nodeId = nodeIds[i];
27789               var candidates = action.waysForNode(nodeId, graph);
27790
27791               if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
27792                 return 'not_eligible';
27793               }
27794             }
27795           };
27796
27797           action.limitWays = function (val) {
27798             if (!arguments.length) return _wayIDs;
27799             _wayIDs = val;
27800             return action;
27801           };
27802
27803           action.keepHistoryOn = function (val) {
27804             if (!arguments.length) return _keepHistoryOn;
27805             _keepHistoryOn = val;
27806             return action;
27807           };
27808
27809           return action;
27810         }
27811
27812         function coreGraph(other, mutable) {
27813           if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
27814
27815           if (other instanceof coreGraph) {
27816             var base = other.base();
27817             this.entities = Object.assign(Object.create(base.entities), other.entities);
27818             this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
27819             this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
27820           } else {
27821             this.entities = Object.create({});
27822             this._parentWays = Object.create({});
27823             this._parentRels = Object.create({});
27824             this.rebase(other || [], [this]);
27825           }
27826
27827           this.transients = {};
27828           this._childNodes = {};
27829           this.frozen = !mutable;
27830         }
27831         coreGraph.prototype = {
27832           hasEntity: function hasEntity(id) {
27833             return this.entities[id];
27834           },
27835           entity: function entity(id) {
27836             var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
27837
27838             if (!entity) {
27839               entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
27840             }
27841
27842             if (!entity) {
27843               throw new Error('entity ' + id + ' not found');
27844             }
27845
27846             return entity;
27847           },
27848           geometry: function geometry(id) {
27849             return this.entity(id).geometry(this);
27850           },
27851           "transient": function transient(entity, key, fn) {
27852             var id = entity.id;
27853             var transients = this.transients[id] || (this.transients[id] = {});
27854
27855             if (transients[key] !== undefined) {
27856               return transients[key];
27857             }
27858
27859             transients[key] = fn.call(entity);
27860             return transients[key];
27861           },
27862           parentWays: function parentWays(entity) {
27863             var parents = this._parentWays[entity.id];
27864             var result = [];
27865
27866             if (parents) {
27867               parents.forEach(function (id) {
27868                 result.push(this.entity(id));
27869               }, this);
27870             }
27871
27872             return result;
27873           },
27874           isPoi: function isPoi(entity) {
27875             var parents = this._parentWays[entity.id];
27876             return !parents || parents.size === 0;
27877           },
27878           isShared: function isShared(entity) {
27879             var parents = this._parentWays[entity.id];
27880             return parents && parents.size > 1;
27881           },
27882           parentRelations: function parentRelations(entity) {
27883             var parents = this._parentRels[entity.id];
27884             var result = [];
27885
27886             if (parents) {
27887               parents.forEach(function (id) {
27888                 result.push(this.entity(id));
27889               }, this);
27890             }
27891
27892             return result;
27893           },
27894           parentMultipolygons: function parentMultipolygons(entity) {
27895             return this.parentRelations(entity).filter(function (relation) {
27896               return relation.isMultipolygon();
27897             });
27898           },
27899           childNodes: function childNodes(entity) {
27900             if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27901             if (!entity.nodes) return [];
27902             var nodes = [];
27903
27904             for (var i = 0; i < entity.nodes.length; i++) {
27905               nodes[i] = this.entity(entity.nodes[i]);
27906             }
27907             this._childNodes[entity.id] = nodes;
27908             return this._childNodes[entity.id];
27909           },
27910           base: function base() {
27911             return {
27912               'entities': Object.getPrototypeOf(this.entities),
27913               'parentWays': Object.getPrototypeOf(this._parentWays),
27914               'parentRels': Object.getPrototypeOf(this._parentRels)
27915             };
27916           },
27917           // Unlike other graph methods, rebase mutates in place. This is because it
27918           // is used only during the history operation that merges newly downloaded
27919           // data into each state. To external consumers, it should appear as if the
27920           // graph always contained the newly downloaded data.
27921           rebase: function rebase(entities, stack, force) {
27922             var base = this.base();
27923             var i, j, k, id;
27924
27925             for (i = 0; i < entities.length; i++) {
27926               var entity = entities[i];
27927               if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
27928
27929               base.entities[entity.id] = entity;
27930
27931               this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
27932
27933
27934               if (entity.type === 'way') {
27935                 for (j = 0; j < entity.nodes.length; j++) {
27936                   id = entity.nodes[j];
27937
27938                   for (k = 1; k < stack.length; k++) {
27939                     var ents = stack[k].entities;
27940
27941                     if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27942                       delete ents[id];
27943                     }
27944                   }
27945                 }
27946               }
27947             }
27948
27949             for (i = 0; i < stack.length; i++) {
27950               stack[i]._updateRebased();
27951             }
27952           },
27953           _updateRebased: function _updateRebased() {
27954             var base = this.base();
27955             Object.keys(this._parentWays).forEach(function (child) {
27956               if (base.parentWays[child]) {
27957                 base.parentWays[child].forEach(function (id) {
27958                   if (!this.entities.hasOwnProperty(id)) {
27959                     this._parentWays[child].add(id);
27960                   }
27961                 }, this);
27962               }
27963             }, this);
27964             Object.keys(this._parentRels).forEach(function (child) {
27965               if (base.parentRels[child]) {
27966                 base.parentRels[child].forEach(function (id) {
27967                   if (!this.entities.hasOwnProperty(id)) {
27968                     this._parentRels[child].add(id);
27969                   }
27970                 }, this);
27971               }
27972             }, this);
27973             this.transients = {}; // this._childNodes is not updated, under the assumption that
27974             // ways are always downloaded with their child nodes.
27975           },
27976           // Updates calculated properties (parentWays, parentRels) for the specified change
27977           _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
27978             parentWays = parentWays || this._parentWays;
27979             parentRels = parentRels || this._parentRels;
27980             var type = entity && entity.type || oldentity && oldentity.type;
27981             var removed, added, i;
27982
27983             if (type === 'way') {
27984               // Update parentWays
27985               if (oldentity && entity) {
27986                 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
27987                 added = utilArrayDifference(entity.nodes, oldentity.nodes);
27988               } else if (oldentity) {
27989                 removed = oldentity.nodes;
27990                 added = [];
27991               } else if (entity) {
27992                 removed = [];
27993                 added = entity.nodes;
27994               }
27995
27996               for (i = 0; i < removed.length; i++) {
27997                 // make a copy of prototype property, store as own property, and update..
27998                 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
27999                 parentWays[removed[i]]["delete"](oldentity.id);
28000               }
28001
28002               for (i = 0; i < added.length; i++) {
28003                 // make a copy of prototype property, store as own property, and update..
28004                 parentWays[added[i]] = new Set(parentWays[added[i]]);
28005                 parentWays[added[i]].add(entity.id);
28006               }
28007             } else if (type === 'relation') {
28008               // Update parentRels
28009               // diff only on the IDs since the same entity can be a member multiple times with different roles
28010               var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
28011                 return m.id;
28012               }) : [];
28013               var entityMemberIDs = entity ? entity.members.map(function (m) {
28014                 return m.id;
28015               }) : [];
28016
28017               if (oldentity && entity) {
28018                 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
28019                 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
28020               } else if (oldentity) {
28021                 removed = oldentityMemberIDs;
28022                 added = [];
28023               } else if (entity) {
28024                 removed = [];
28025                 added = entityMemberIDs;
28026               }
28027
28028               for (i = 0; i < removed.length; i++) {
28029                 // make a copy of prototype property, store as own property, and update..
28030                 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
28031                 parentRels[removed[i]]["delete"](oldentity.id);
28032               }
28033
28034               for (i = 0; i < added.length; i++) {
28035                 // make a copy of prototype property, store as own property, and update..
28036                 parentRels[added[i]] = new Set(parentRels[added[i]]);
28037                 parentRels[added[i]].add(entity.id);
28038               }
28039             }
28040           },
28041           replace: function replace(entity) {
28042             if (this.entities[entity.id] === entity) return this;
28043             return this.update(function () {
28044               this._updateCalculated(this.entities[entity.id], entity);
28045
28046               this.entities[entity.id] = entity;
28047             });
28048           },
28049           remove: function remove(entity) {
28050             return this.update(function () {
28051               this._updateCalculated(entity, undefined);
28052
28053               this.entities[entity.id] = undefined;
28054             });
28055           },
28056           revert: function revert(id) {
28057             var baseEntity = this.base().entities[id];
28058             var headEntity = this.entities[id];
28059             if (headEntity === baseEntity) return this;
28060             return this.update(function () {
28061               this._updateCalculated(headEntity, baseEntity);
28062
28063               delete this.entities[id];
28064             });
28065           },
28066           update: function update() {
28067             var graph = this.frozen ? coreGraph(this, true) : this;
28068
28069             for (var i = 0; i < arguments.length; i++) {
28070               arguments[i].call(graph, graph);
28071             }
28072
28073             if (this.frozen) graph.frozen = true;
28074             return graph;
28075           },
28076           // Obliterates any existing entities
28077           load: function load(entities) {
28078             var base = this.base();
28079             this.entities = Object.create(base.entities);
28080
28081             for (var i in entities) {
28082               this.entities[i] = entities[i];
28083
28084               this._updateCalculated(base.entities[i], this.entities[i]);
28085             }
28086
28087             return this;
28088           }
28089         };
28090
28091         function osmTurn(turn) {
28092           if (!(this instanceof osmTurn)) {
28093             return new osmTurn(turn);
28094           }
28095
28096           Object.assign(this, turn);
28097         }
28098         function osmIntersection(graph, startVertexId, maxDistance) {
28099           maxDistance = maxDistance || 30; // in meters
28100
28101           var vgraph = coreGraph(); // virtual graph
28102
28103           var i, j, k;
28104
28105           function memberOfRestriction(entity) {
28106             return graph.parentRelations(entity).some(function (r) {
28107               return r.isRestriction();
28108             });
28109           }
28110
28111           function isRoad(way) {
28112             if (way.isArea() || way.isDegenerate()) return false;
28113             var roads = {
28114               'motorway': true,
28115               'motorway_link': true,
28116               'trunk': true,
28117               'trunk_link': true,
28118               'primary': true,
28119               'primary_link': true,
28120               'secondary': true,
28121               'secondary_link': true,
28122               'tertiary': true,
28123               'tertiary_link': true,
28124               'residential': true,
28125               'unclassified': true,
28126               'living_street': true,
28127               'service': true,
28128               'road': true,
28129               'track': true
28130             };
28131             return roads[way.tags.highway];
28132           }
28133
28134           var startNode = graph.entity(startVertexId);
28135           var checkVertices = [startNode];
28136           var checkWays;
28137           var vertices = [];
28138           var vertexIds = [];
28139           var vertex;
28140           var ways = [];
28141           var wayIds = [];
28142           var way;
28143           var nodes = [];
28144           var node;
28145           var parents = [];
28146           var parent; // `actions` will store whatever actions must be performed to satisfy
28147           // preconditions for adding a turn restriction to this intersection.
28148           //  - Remove any existing degenerate turn restrictions (missing from/to, etc)
28149           //  - Reverse oneways so that they are drawn in the forward direction
28150           //  - Split ways on key vertices
28151
28152           var actions = []; // STEP 1:  walk the graph outwards from starting vertex to search
28153           //  for more key vertices and ways to include in the intersection..
28154
28155           while (checkVertices.length) {
28156             vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
28157
28158             checkWays = graph.parentWays(vertex);
28159             var hasWays = false;
28160
28161             for (i = 0; i < checkWays.length; i++) {
28162               way = checkWays[i];
28163               if (!isRoad(way) && !memberOfRestriction(way)) continue;
28164               ways.push(way); // it's a road, or it's already in a turn restriction
28165
28166               hasWays = true; // check the way's children for more key vertices
28167
28168               nodes = utilArrayUniq(graph.childNodes(way));
28169
28170               for (j = 0; j < nodes.length; j++) {
28171                 node = nodes[j];
28172                 if (node === vertex) continue; // same thing
28173
28174                 if (vertices.indexOf(node) !== -1) continue; // seen it already
28175
28176                 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
28177                 // a key vertex will have parents that are also roads
28178
28179                 var hasParents = false;
28180                 parents = graph.parentWays(node);
28181
28182                 for (k = 0; k < parents.length; k++) {
28183                   parent = parents[k];
28184                   if (parent === way) continue; // same thing
28185
28186                   if (ways.indexOf(parent) !== -1) continue; // seen it already
28187
28188                   if (!isRoad(parent)) continue; // not a road
28189
28190                   hasParents = true;
28191                   break;
28192                 }
28193
28194                 if (hasParents) {
28195                   checkVertices.push(node);
28196                 }
28197               }
28198             }
28199
28200             if (hasWays) {
28201               vertices.push(vertex);
28202             }
28203           }
28204
28205           vertices = utilArrayUniq(vertices);
28206           ways = utilArrayUniq(ways); // STEP 2:  Build a virtual graph containing only the entities in the intersection..
28207           // Everything done after this step should act on the virtual graph
28208           // Any actions that must be performed later to the main graph go in `actions` array
28209
28210           ways.forEach(function (way) {
28211             graph.childNodes(way).forEach(function (node) {
28212               vgraph = vgraph.replace(node);
28213             });
28214             vgraph = vgraph.replace(way);
28215             graph.parentRelations(way).forEach(function (relation) {
28216               if (relation.isRestriction()) {
28217                 if (relation.isValidRestriction(graph)) {
28218                   vgraph = vgraph.replace(relation);
28219                 } else if (relation.isComplete(graph)) {
28220                   actions.push(actionDeleteRelation(relation.id));
28221                 }
28222               }
28223             });
28224           }); // STEP 3:  Force all oneways to be drawn in the forward direction
28225
28226           ways.forEach(function (w) {
28227             var way = vgraph.entity(w.id);
28228
28229             if (way.tags.oneway === '-1') {
28230               var action = actionReverse(way.id, {
28231                 reverseOneway: true
28232               });
28233               actions.push(action);
28234               vgraph = action(vgraph);
28235             }
28236           }); // STEP 4:  Split ways on key vertices
28237
28238           var origCount = osmEntity.id.next.way;
28239           vertices.forEach(function (v) {
28240             // This is an odd way to do it, but we need to find all the ways that
28241             // will be split here, then split them one at a time to ensure that these
28242             // actions can be replayed on the main graph exactly in the same order.
28243             // (It is unintuitive, but the order of ways returned from graph.parentWays()
28244             // is arbitrary, depending on how the main graph and vgraph were built)
28245             var splitAll = actionSplit([v.id]).keepHistoryOn('first');
28246
28247             if (!splitAll.disabled(vgraph)) {
28248               splitAll.ways(vgraph).forEach(function (way) {
28249                 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
28250                 actions.push(splitOne);
28251                 vgraph = splitOne(vgraph);
28252               });
28253             }
28254           }); // In here is where we should also split the intersection at nearby junction.
28255           //   for https://github.com/mapbox/iD-internal/issues/31
28256           // nearbyVertices.forEach(function(v) {
28257           // });
28258           // Reasons why we reset the way id count here:
28259           //  1. Continuity with way ids created by the splits so that we can replay
28260           //     these actions later if the user decides to create a turn restriction
28261           //  2. Avoids churning way ids just by hovering over a vertex
28262           //     and displaying the turn restriction editor
28263
28264           osmEntity.id.next.way = origCount; // STEP 5:  Update arrays to point to vgraph entities
28265
28266           vertexIds = vertices.map(function (v) {
28267             return v.id;
28268           });
28269           vertices = [];
28270           ways = [];
28271           vertexIds.forEach(function (id) {
28272             var vertex = vgraph.entity(id);
28273             var parents = vgraph.parentWays(vertex);
28274             vertices.push(vertex);
28275             ways = ways.concat(parents);
28276           });
28277           vertices = utilArrayUniq(vertices);
28278           ways = utilArrayUniq(ways);
28279           vertexIds = vertices.map(function (v) {
28280             return v.id;
28281           });
28282           wayIds = ways.map(function (w) {
28283             return w.id;
28284           }); // STEP 6:  Update the ways with some metadata that will be useful for
28285           // walking the intersection graph later and rendering turn arrows.
28286
28287           function withMetadata(way, vertexIds) {
28288             var __oneWay = way.isOneWay(); // which affixes are key vertices?
28289
28290
28291             var __first = vertexIds.indexOf(way.first()) !== -1;
28292
28293             var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
28294
28295
28296             var __via = __first && __last;
28297
28298             var __from = __first && !__oneWay || __last;
28299
28300             var __to = __first || __last && !__oneWay;
28301
28302             return way.update({
28303               __first: __first,
28304               __last: __last,
28305               __from: __from,
28306               __via: __via,
28307               __to: __to,
28308               __oneWay: __oneWay
28309             });
28310           }
28311
28312           ways = [];
28313           wayIds.forEach(function (id) {
28314             var way = withMetadata(vgraph.entity(id), vertexIds);
28315             vgraph = vgraph.replace(way);
28316             ways.push(way);
28317           }); // STEP 7:  Simplify - This is an iterative process where we:
28318           //  1. Find trivial vertices with only 2 parents
28319           //  2. trim off the leaf way from those vertices and remove from vgraph
28320
28321           var keepGoing;
28322           var removeWayIds = [];
28323           var removeVertexIds = [];
28324
28325           do {
28326             keepGoing = false;
28327             checkVertices = vertexIds.slice();
28328
28329             for (i = 0; i < checkVertices.length; i++) {
28330               var vertexId = checkVertices[i];
28331               vertex = vgraph.hasEntity(vertexId);
28332
28333               if (!vertex) {
28334                 if (vertexIds.indexOf(vertexId) !== -1) {
28335                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28336                 }
28337
28338                 removeVertexIds.push(vertexId);
28339                 continue;
28340               }
28341
28342               parents = vgraph.parentWays(vertex);
28343
28344               if (parents.length < 3) {
28345                 if (vertexIds.indexOf(vertexId) !== -1) {
28346                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28347                 }
28348               }
28349
28350               if (parents.length === 2) {
28351                 // vertex with 2 parents is trivial
28352                 var a = parents[0];
28353                 var b = parents[1];
28354                 var aIsLeaf = a && !a.__via;
28355                 var bIsLeaf = b && !b.__via;
28356                 var leaf, survivor;
28357
28358                 if (aIsLeaf && !bIsLeaf) {
28359                   leaf = a;
28360                   survivor = b;
28361                 } else if (!aIsLeaf && bIsLeaf) {
28362                   leaf = b;
28363                   survivor = a;
28364                 }
28365
28366                 if (leaf && survivor) {
28367                   survivor = withMetadata(survivor, vertexIds); // update survivor way
28368
28369                   vgraph = vgraph.replace(survivor).remove(leaf); // update graph
28370
28371                   removeWayIds.push(leaf.id);
28372                   keepGoing = true;
28373                 }
28374               }
28375
28376               parents = vgraph.parentWays(vertex);
28377
28378               if (parents.length < 2) {
28379                 // vertex is no longer a key vertex
28380                 if (vertexIds.indexOf(vertexId) !== -1) {
28381                   vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
28382                 }
28383
28384                 removeVertexIds.push(vertexId);
28385                 keepGoing = true;
28386               }
28387
28388               if (parents.length < 1) {
28389                 // vertex is no longer attached to anything
28390                 vgraph = vgraph.remove(vertex);
28391               }
28392             }
28393           } while (keepGoing);
28394
28395           vertices = vertices.filter(function (vertex) {
28396             return removeVertexIds.indexOf(vertex.id) === -1;
28397           }).map(function (vertex) {
28398             return vgraph.entity(vertex.id);
28399           });
28400           ways = ways.filter(function (way) {
28401             return removeWayIds.indexOf(way.id) === -1;
28402           }).map(function (way) {
28403             return vgraph.entity(way.id);
28404           }); // OK!  Here is our intersection..
28405
28406           var intersection = {
28407             graph: vgraph,
28408             actions: actions,
28409             vertices: vertices,
28410             ways: ways
28411           }; // Get all the valid turns through this intersection given a starting way id.
28412           // This operates on the virtual graph for everything.
28413           //
28414           // Basically, walk through all possible paths from starting way,
28415           //   honoring the existing turn restrictions as we go (watch out for loops!)
28416           //
28417           // For each path found, generate and return a `osmTurn` datastructure.
28418           //
28419
28420           intersection.turns = function (fromWayId, maxViaWay) {
28421             if (!fromWayId) return [];
28422             if (!maxViaWay) maxViaWay = 0;
28423             var vgraph = intersection.graph;
28424             var keyVertexIds = intersection.vertices.map(function (v) {
28425               return v.id;
28426             });
28427             var start = vgraph.entity(fromWayId);
28428             if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0   from-*-to              (0 vias)
28429             // maxViaWay=1   from-*-via-*-to        (1 via max)
28430             // maxViaWay=2   from-*-via-*-via-*-to  (2 vias max)
28431
28432             var maxPathLength = maxViaWay * 2 + 3;
28433             var turns = [];
28434             step(start);
28435             return turns; // traverse the intersection graph and find all the valid paths
28436
28437             function step(entity, currPath, currRestrictions, matchedRestriction) {
28438               currPath = (currPath || []).slice(); // shallow copy
28439
28440               if (currPath.length >= maxPathLength) return;
28441               currPath.push(entity.id);
28442               currRestrictions = (currRestrictions || []).slice(); // shallow copy
28443
28444               var i, j;
28445
28446               if (entity.type === 'node') {
28447                 var parents = vgraph.parentWays(entity);
28448                 var nextWays = []; // which ways can we step into?
28449
28450                 for (i = 0; i < parents.length; i++) {
28451                   var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
28452
28453                   if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
28454
28455                   if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
28456
28457                   var restrict = null;
28458
28459                   for (j = 0; j < currRestrictions.length; j++) {
28460                     var restriction = currRestrictions[j];
28461                     var f = restriction.memberByRole('from');
28462                     var v = restriction.membersByRole('via');
28463                     var t = restriction.memberByRole('to');
28464                     var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
28465
28466                     var matchesFrom = f.id === fromWayId;
28467                     var matchesViaTo = false;
28468                     var isAlongOnlyPath = false;
28469
28470                     if (t.id === way.id) {
28471                       // match TO
28472                       if (v.length === 1 && v[0].type === 'node') {
28473                         // match VIA node
28474                         matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
28475                       } else {
28476                         // match all VIA ways
28477                         var pathVias = [];
28478
28479                         for (k = 2; k < currPath.length; k += 2) {
28480                           // k = 2 skips FROM
28481                           pathVias.push(currPath[k]); // (path goes way-node-way...)
28482                         }
28483
28484                         var restrictionVias = [];
28485
28486                         for (k = 0; k < v.length; k++) {
28487                           if (v[k].type === 'way') {
28488                             restrictionVias.push(v[k].id);
28489                           }
28490                         }
28491
28492                         var diff = utilArrayDifference(pathVias, restrictionVias);
28493                         matchesViaTo = !diff.length;
28494                       }
28495                     } else if (isOnly) {
28496                       for (k = 0; k < v.length; k++) {
28497                         // way doesn't match TO, but is one of the via ways along the path of an "only"
28498                         if (v[k].type === 'way' && v[k].id === way.id) {
28499                           isAlongOnlyPath = true;
28500                           break;
28501                         }
28502                       }
28503                     }
28504
28505                     if (matchesViaTo) {
28506                       if (isOnly) {
28507                         restrict = {
28508                           id: restriction.id,
28509                           direct: matchesFrom,
28510                           from: f.id,
28511                           only: true,
28512                           end: true
28513                         };
28514                       } else {
28515                         restrict = {
28516                           id: restriction.id,
28517                           direct: matchesFrom,
28518                           from: f.id,
28519                           no: true,
28520                           end: true
28521                         };
28522                       }
28523                     } else {
28524                       // indirect - caused by a different nearby restriction
28525                       if (isAlongOnlyPath) {
28526                         restrict = {
28527                           id: restriction.id,
28528                           direct: false,
28529                           from: f.id,
28530                           only: true,
28531                           end: false
28532                         };
28533                       } else if (isOnly) {
28534                         restrict = {
28535                           id: restriction.id,
28536                           direct: false,
28537                           from: f.id,
28538                           no: true,
28539                           end: true
28540                         };
28541                       }
28542                     } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
28543
28544
28545                     if (restrict && restrict.direct) break;
28546                   }
28547
28548                   nextWays.push({
28549                     way: way,
28550                     restrict: restrict
28551                   });
28552                 }
28553
28554                 nextWays.forEach(function (nextWay) {
28555                   step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
28556                 });
28557               } else {
28558                 // entity.type === 'way'
28559                 if (currPath.length >= 3) {
28560                   // this is a "complete" path..
28561                   var turnPath = currPath.slice(); // shallow copy
28562                   // an indirect restriction - only include the partial path (starting at FROM)
28563
28564                   if (matchedRestriction && matchedRestriction.direct === false) {
28565                     for (i = 0; i < turnPath.length; i++) {
28566                       if (turnPath[i] === matchedRestriction.from) {
28567                         turnPath = turnPath.slice(i);
28568                         break;
28569                       }
28570                     }
28571                   }
28572
28573                   var turn = pathToTurn(turnPath);
28574
28575                   if (turn) {
28576                     if (matchedRestriction) {
28577                       turn.restrictionID = matchedRestriction.id;
28578                       turn.no = matchedRestriction.no;
28579                       turn.only = matchedRestriction.only;
28580                       turn.direct = matchedRestriction.direct;
28581                     }
28582
28583                     turns.push(osmTurn(turn));
28584                   }
28585
28586                   if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
28587                 }
28588
28589                 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
28590                 // which nodes can we step into?
28591
28592                 var n1 = vgraph.entity(entity.first());
28593                 var n2 = vgraph.entity(entity.last());
28594                 var dist = geoSphericalDistance(n1.loc, n2.loc);
28595                 var nextNodes = [];
28596
28597                 if (currPath.length > 1) {
28598                   if (dist > maxDistance) return; // the next node is too far
28599
28600                   if (!entity.__via) return; // this way is a leaf / can't be a via
28601                 }
28602
28603                 if (!entity.__oneWay && // bidirectional..
28604                 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
28605                 currPath.indexOf(n1.id) === -1) {
28606                   // haven't seen it yet..
28607                   nextNodes.push(n1); // can advance to first node
28608                 }
28609
28610                 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
28611                 currPath.indexOf(n2.id) === -1) {
28612                   // haven't seen it yet..
28613                   nextNodes.push(n2); // can advance to last node
28614                 }
28615
28616                 nextNodes.forEach(function (nextNode) {
28617                   // gather restrictions FROM this way
28618                   var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
28619                     if (!r.isRestriction()) return false;
28620                     var f = r.memberByRole('from');
28621                     if (!f || f.id !== entity.id) return false;
28622                     var isOnly = /^only_/.test(r.tags.restriction);
28623                     if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
28624
28625                     var isOnlyVia = false;
28626                     var v = r.membersByRole('via');
28627
28628                     if (v.length === 1 && v[0].type === 'node') {
28629                       // via node
28630                       isOnlyVia = v[0].id === nextNode.id;
28631                     } else {
28632                       // via way(s)
28633                       for (var i = 0; i < v.length; i++) {
28634                         if (v[i].type !== 'way') continue;
28635                         var viaWay = vgraph.entity(v[i].id);
28636
28637                         if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
28638                           isOnlyVia = true;
28639                           break;
28640                         }
28641                       }
28642                     }
28643
28644                     return isOnlyVia;
28645                   });
28646                   step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
28647                 });
28648               }
28649             } // assumes path is alternating way-node-way of odd length
28650
28651
28652             function pathToTurn(path) {
28653               if (path.length < 3) return;
28654               var fromWayId, fromNodeId, fromVertexId;
28655               var toWayId, toNodeId, toVertexId;
28656               var viaWayIds, viaNodeId, isUturn;
28657               fromWayId = path[0];
28658               toWayId = path[path.length - 1];
28659
28660               if (path.length === 3 && fromWayId === toWayId) {
28661                 // u turn
28662                 var way = vgraph.entity(fromWayId);
28663                 if (way.__oneWay) return null;
28664                 isUturn = true;
28665                 viaNodeId = fromVertexId = toVertexId = path[1];
28666                 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
28667               } else {
28668                 isUturn = false;
28669                 fromVertexId = path[1];
28670                 fromNodeId = adjacentNode(fromWayId, fromVertexId);
28671                 toVertexId = path[path.length - 2];
28672                 toNodeId = adjacentNode(toWayId, toVertexId);
28673
28674                 if (path.length === 3) {
28675                   viaNodeId = path[1];
28676                 } else {
28677                   viaWayIds = path.filter(function (entityId) {
28678                     return entityId[0] === 'w';
28679                   });
28680                   viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
28681                 }
28682               }
28683
28684               return {
28685                 key: path.join('_'),
28686                 path: path,
28687                 from: {
28688                   node: fromNodeId,
28689                   way: fromWayId,
28690                   vertex: fromVertexId
28691                 },
28692                 via: {
28693                   node: viaNodeId,
28694                   ways: viaWayIds
28695                 },
28696                 to: {
28697                   node: toNodeId,
28698                   way: toWayId,
28699                   vertex: toVertexId
28700                 },
28701                 u: isUturn
28702               };
28703
28704               function adjacentNode(wayId, affixId) {
28705                 var nodes = vgraph.entity(wayId).nodes;
28706                 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
28707               }
28708             }
28709           };
28710
28711           return intersection;
28712         }
28713         function osmInferRestriction(graph, turn, projection) {
28714           var fromWay = graph.entity(turn.from.way);
28715           var fromNode = graph.entity(turn.from.node);
28716           var fromVertex = graph.entity(turn.from.vertex);
28717           var toWay = graph.entity(turn.to.way);
28718           var toNode = graph.entity(turn.to.node);
28719           var toVertex = graph.entity(turn.to.vertex);
28720           var fromOneWay = fromWay.tags.oneway === 'yes';
28721           var toOneWay = toWay.tags.oneway === 'yes';
28722           var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
28723
28724           while (angle < 0) {
28725             angle += 360;
28726           }
28727
28728           if (fromNode === toNode) return 'no_u_turn';
28729           if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
28730
28731           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)
28732
28733           if (angle < 158) return 'no_right_turn';
28734           if (angle > 202) return 'no_left_turn';
28735           return 'no_straight_on';
28736         }
28737
28738         function actionMergePolygon(ids, newRelationId) {
28739           function groupEntities(graph) {
28740             var entities = ids.map(function (id) {
28741               return graph.entity(id);
28742             });
28743             var geometryGroups = utilArrayGroupBy(entities, function (entity) {
28744               if (entity.type === 'way' && entity.isClosed()) {
28745                 return 'closedWay';
28746               } else if (entity.type === 'relation' && entity.isMultipolygon()) {
28747                 return 'multipolygon';
28748               } else {
28749                 return 'other';
28750               }
28751             });
28752             return Object.assign({
28753               closedWay: [],
28754               multipolygon: [],
28755               other: []
28756             }, geometryGroups);
28757           }
28758
28759           var action = function action(graph) {
28760             var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
28761             //
28762             // Each element is itself an array of objects with an id property, and has a
28763             // locs property which is an array of the locations forming the polygon.
28764
28765             var polygons = entities.multipolygon.reduce(function (polygons, m) {
28766               return polygons.concat(osmJoinWays(m.members, graph));
28767             }, []).concat(entities.closedWay.map(function (d) {
28768               var member = [{
28769                 id: d.id
28770               }];
28771               member.nodes = graph.childNodes(d);
28772               return member;
28773             })); // contained is an array of arrays of boolean values,
28774             // where contained[j][k] is true iff the jth way is
28775             // contained by the kth way.
28776
28777             var contained = polygons.map(function (w, i) {
28778               return polygons.map(function (d, n) {
28779                 if (i === n) return null;
28780                 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
28781                   return n.loc;
28782                 }), w.nodes.map(function (n) {
28783                   return n.loc;
28784                 }));
28785               });
28786             }); // Sort all polygons as either outer or inner ways
28787
28788             var members = [];
28789             var outer = true;
28790
28791             while (polygons.length) {
28792               extractUncontained(polygons);
28793               polygons = polygons.filter(isContained);
28794               contained = contained.filter(isContained).map(filterContained);
28795             }
28796
28797             function isContained(d, i) {
28798               return contained[i].some(function (val) {
28799                 return val;
28800               });
28801             }
28802
28803             function filterContained(d) {
28804               return d.filter(isContained);
28805             }
28806
28807             function extractUncontained(polygons) {
28808               polygons.forEach(function (d, i) {
28809                 if (!isContained(d, i)) {
28810                   d.forEach(function (member) {
28811                     members.push({
28812                       type: 'way',
28813                       id: member.id,
28814                       role: outer ? 'outer' : 'inner'
28815                     });
28816                   });
28817                 }
28818               });
28819               outer = !outer;
28820             } // Move all tags to one relation
28821
28822
28823             var relation = entities.multipolygon[0] || osmRelation({
28824               id: newRelationId,
28825               tags: {
28826                 type: 'multipolygon'
28827               }
28828             });
28829             entities.multipolygon.slice(1).forEach(function (m) {
28830               relation = relation.mergeTags(m.tags);
28831               graph = graph.remove(m);
28832             });
28833             entities.closedWay.forEach(function (way) {
28834               function isThisOuter(m) {
28835                 return m.id === way.id && m.role !== 'inner';
28836               }
28837
28838               if (members.some(isThisOuter)) {
28839                 relation = relation.mergeTags(way.tags);
28840                 graph = graph.replace(way.update({
28841                   tags: {}
28842                 }));
28843               }
28844             });
28845             return graph.replace(relation.update({
28846               members: members,
28847               tags: utilObjectOmit(relation.tags, ['area'])
28848             }));
28849           };
28850
28851           action.disabled = function (graph) {
28852             var entities = groupEntities(graph);
28853
28854             if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
28855               return 'not_eligible';
28856             }
28857
28858             if (!entities.multipolygon.every(function (r) {
28859               return r.isComplete(graph);
28860             })) {
28861               return 'incomplete_relation';
28862             }
28863
28864             if (!entities.multipolygon.length) {
28865               var sharedMultipolygons = [];
28866               entities.closedWay.forEach(function (way, i) {
28867                 if (i === 0) {
28868                   sharedMultipolygons = graph.parentMultipolygons(way);
28869                 } else {
28870                   sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
28871                 }
28872               });
28873               sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
28874                 return relation.members.length === entities.closedWay.length;
28875               });
28876
28877               if (sharedMultipolygons.length) {
28878                 // don't create a new multipolygon if it'd be redundant
28879                 return 'not_eligible';
28880               }
28881             } else if (entities.closedWay.some(function (way) {
28882               return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
28883             })) {
28884               // don't add a way to a multipolygon again if it's already a member
28885               return 'not_eligible';
28886             }
28887           };
28888
28889           return action;
28890         }
28891
28892         var UNSUPPORTED_Y$3 = regexpStickyHelpers.UNSUPPORTED_Y;
28893
28894         // `RegExp.prototype.flags` getter
28895         // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
28896         if (descriptors && (/./g.flags != 'g' || UNSUPPORTED_Y$3)) {
28897           objectDefineProperty.f(RegExp.prototype, 'flags', {
28898             configurable: true,
28899             get: regexpFlags
28900           });
28901         }
28902
28903         var fastDeepEqual = function equal(a, b) {
28904           if (a === b) return true;
28905
28906           if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
28907             if (a.constructor !== b.constructor) return false;
28908             var length, i, keys;
28909
28910             if (Array.isArray(a)) {
28911               length = a.length;
28912               if (length != b.length) return false;
28913
28914               for (i = length; i-- !== 0;) {
28915                 if (!equal(a[i], b[i])) return false;
28916               }
28917
28918               return true;
28919             }
28920
28921             if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
28922             if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
28923             if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
28924             keys = Object.keys(a);
28925             length = keys.length;
28926             if (length !== Object.keys(b).length) return false;
28927
28928             for (i = length; i-- !== 0;) {
28929               if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
28930             }
28931
28932             for (i = length; i-- !== 0;) {
28933               var key = keys[i];
28934               if (!equal(a[key], b[key])) return false;
28935             }
28936
28937             return true;
28938           } // true if both NaN, false otherwise
28939
28940
28941           return a !== a && b !== b;
28942         };
28943
28944         // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
28945         // comparison, Bell Telephone Laboratories CSTR #41 (1976)
28946         // http://www.cs.dartmouth.edu/~doug/
28947         // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
28948         //
28949         // Expects two arrays, finds longest common sequence
28950
28951         function LCS(buffer1, buffer2) {
28952           var equivalenceClasses = {};
28953
28954           for (var j = 0; j < buffer2.length; j++) {
28955             var item = buffer2[j];
28956
28957             if (equivalenceClasses[item]) {
28958               equivalenceClasses[item].push(j);
28959             } else {
28960               equivalenceClasses[item] = [j];
28961             }
28962           }
28963
28964           var NULLRESULT = {
28965             buffer1index: -1,
28966             buffer2index: -1,
28967             chain: null
28968           };
28969           var candidates = [NULLRESULT];
28970
28971           for (var i = 0; i < buffer1.length; i++) {
28972             var _item = buffer1[i];
28973             var buffer2indices = equivalenceClasses[_item] || [];
28974             var r = 0;
28975             var c = candidates[0];
28976
28977             for (var jx = 0; jx < buffer2indices.length; jx++) {
28978               var _j = buffer2indices[jx];
28979               var s = void 0;
28980
28981               for (s = r; s < candidates.length; s++) {
28982                 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
28983                   break;
28984                 }
28985               }
28986
28987               if (s < candidates.length) {
28988                 var newCandidate = {
28989                   buffer1index: i,
28990                   buffer2index: _j,
28991                   chain: candidates[s]
28992                 };
28993
28994                 if (r === candidates.length) {
28995                   candidates.push(c);
28996                 } else {
28997                   candidates[r] = c;
28998                 }
28999
29000                 r = s + 1;
29001                 c = newCandidate;
29002
29003                 if (r === candidates.length) {
29004                   break; // no point in examining further (j)s
29005                 }
29006               }
29007             }
29008
29009             candidates[r] = c;
29010           } // At this point, we know the LCS: it's in the reverse of the
29011           // linked-list through .chain of candidates[candidates.length - 1].
29012
29013
29014           return candidates[candidates.length - 1];
29015         } // We apply the LCS to build a 'comm'-style picture of the
29016         // offsets and lengths of mismatched chunks in the input
29017         // buffers. This is used by diff3MergeRegions.
29018
29019
29020         function diffIndices(buffer1, buffer2) {
29021           var lcs = LCS(buffer1, buffer2);
29022           var result = [];
29023           var tail1 = buffer1.length;
29024           var tail2 = buffer2.length;
29025
29026           for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
29027             var mismatchLength1 = tail1 - candidate.buffer1index - 1;
29028             var mismatchLength2 = tail2 - candidate.buffer2index - 1;
29029             tail1 = candidate.buffer1index;
29030             tail2 = candidate.buffer2index;
29031
29032             if (mismatchLength1 || mismatchLength2) {
29033               result.push({
29034                 buffer1: [tail1 + 1, mismatchLength1],
29035                 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
29036                 buffer2: [tail2 + 1, mismatchLength2],
29037                 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
29038               });
29039             }
29040           }
29041
29042           result.reverse();
29043           return result;
29044         } // We apply the LCS to build a JSON representation of a
29045         // independently derived from O, returns a fairly complicated
29046         // internal representation of merge decisions it's taken. The
29047         // interested reader may wish to consult
29048         //
29049         // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
29050         // 'A Formal Investigation of ' In Arvind and Prasad,
29051         // editors, Foundations of Software Technology and Theoretical
29052         // Computer Science (FSTTCS), December 2007.
29053         //
29054         // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
29055         //
29056
29057
29058         function diff3MergeRegions(a, o, b) {
29059           // "hunks" are array subsets where `a` or `b` are different from `o`
29060           // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
29061           var hunks = [];
29062
29063           function addHunk(h, ab) {
29064             hunks.push({
29065               ab: ab,
29066               oStart: h.buffer1[0],
29067               oLength: h.buffer1[1],
29068               // length of o to remove
29069               abStart: h.buffer2[0],
29070               abLength: h.buffer2[1] // length of a/b to insert
29071               // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
29072
29073             });
29074           }
29075
29076           diffIndices(o, a).forEach(function (item) {
29077             return addHunk(item, 'a');
29078           });
29079           diffIndices(o, b).forEach(function (item) {
29080             return addHunk(item, 'b');
29081           });
29082           hunks.sort(function (x, y) {
29083             return x.oStart - y.oStart;
29084           });
29085           var results = [];
29086           var currOffset = 0;
29087
29088           function advanceTo(endOffset) {
29089             if (endOffset > currOffset) {
29090               results.push({
29091                 stable: true,
29092                 buffer: 'o',
29093                 bufferStart: currOffset,
29094                 bufferLength: endOffset - currOffset,
29095                 bufferContent: o.slice(currOffset, endOffset)
29096               });
29097               currOffset = endOffset;
29098             }
29099           }
29100
29101           while (hunks.length) {
29102             var hunk = hunks.shift();
29103             var regionStart = hunk.oStart;
29104             var regionEnd = hunk.oStart + hunk.oLength;
29105             var regionHunks = [hunk];
29106             advanceTo(regionStart); // Try to pull next overlapping hunk into this region
29107
29108             while (hunks.length) {
29109               var nextHunk = hunks[0];
29110               var nextHunkStart = nextHunk.oStart;
29111               if (nextHunkStart > regionEnd) break; // no overlap
29112
29113               regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
29114               regionHunks.push(hunks.shift());
29115             }
29116
29117             if (regionHunks.length === 1) {
29118               // Only one hunk touches this region, meaning that there is no conflict here.
29119               // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
29120               if (hunk.abLength > 0) {
29121                 var buffer = hunk.ab === 'a' ? a : b;
29122                 results.push({
29123                   stable: true,
29124                   buffer: hunk.ab,
29125                   bufferStart: hunk.abStart,
29126                   bufferLength: hunk.abLength,
29127                   bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
29128                 });
29129               }
29130             } else {
29131               // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
29132               // Effectively merge all the `a` hunks into one giant hunk, then do the
29133               // same for the `b` hunks; then, correct for skew in the regions of `o`
29134               // that each side changed, and report appropriate spans for the three sides.
29135               var bounds = {
29136                 a: [a.length, -1, o.length, -1],
29137                 b: [b.length, -1, o.length, -1]
29138               };
29139
29140               while (regionHunks.length) {
29141                 hunk = regionHunks.shift();
29142                 var oStart = hunk.oStart;
29143                 var oEnd = oStart + hunk.oLength;
29144                 var abStart = hunk.abStart;
29145                 var abEnd = abStart + hunk.abLength;
29146                 var _b = bounds[hunk.ab];
29147                 _b[0] = Math.min(abStart, _b[0]);
29148                 _b[1] = Math.max(abEnd, _b[1]);
29149                 _b[2] = Math.min(oStart, _b[2]);
29150                 _b[3] = Math.max(oEnd, _b[3]);
29151               }
29152
29153               var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
29154               var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
29155               var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
29156               var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
29157               var result = {
29158                 stable: false,
29159                 aStart: aStart,
29160                 aLength: aEnd - aStart,
29161                 aContent: a.slice(aStart, aEnd),
29162                 oStart: regionStart,
29163                 oLength: regionEnd - regionStart,
29164                 oContent: o.slice(regionStart, regionEnd),
29165                 bStart: bStart,
29166                 bLength: bEnd - bStart,
29167                 bContent: b.slice(bStart, bEnd)
29168               };
29169               results.push(result);
29170             }
29171
29172             currOffset = regionEnd;
29173           }
29174
29175           advanceTo(o.length);
29176           return results;
29177         } // Applies the output of diff3MergeRegions to actually
29178         // construct the merged buffer; the returned result alternates
29179         // between 'ok' and 'conflict' blocks.
29180         // A "false conflict" is where `a` and `b` both change the same from `o`
29181
29182
29183         function diff3Merge(a, o, b, options) {
29184           var defaults = {
29185             excludeFalseConflicts: true,
29186             stringSeparator: /\s+/
29187           };
29188           options = Object.assign(defaults, options);
29189           var aString = typeof a === 'string';
29190           var oString = typeof o === 'string';
29191           var bString = typeof b === 'string';
29192           if (aString) a = a.split(options.stringSeparator);
29193           if (oString) o = o.split(options.stringSeparator);
29194           if (bString) b = b.split(options.stringSeparator);
29195           var results = [];
29196           var regions = diff3MergeRegions(a, o, b);
29197           var okBuffer = [];
29198
29199           function flushOk() {
29200             if (okBuffer.length) {
29201               results.push({
29202                 ok: okBuffer
29203               });
29204             }
29205
29206             okBuffer = [];
29207           }
29208
29209           function isFalseConflict(a, b) {
29210             if (a.length !== b.length) return false;
29211
29212             for (var i = 0; i < a.length; i++) {
29213               if (a[i] !== b[i]) return false;
29214             }
29215
29216             return true;
29217           }
29218
29219           regions.forEach(function (region) {
29220             if (region.stable) {
29221               var _okBuffer;
29222
29223               (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
29224             } else {
29225               if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
29226                 var _okBuffer2;
29227
29228                 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
29229               } else {
29230                 flushOk();
29231                 results.push({
29232                   conflict: {
29233                     a: region.aContent,
29234                     aIndex: region.aStart,
29235                     o: region.oContent,
29236                     oIndex: region.oStart,
29237                     b: region.bContent,
29238                     bIndex: region.bStart
29239                   }
29240                 });
29241               }
29242             }
29243           });
29244           flushOk();
29245           return results;
29246         }
29247
29248         function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
29249           discardTags = discardTags || {};
29250           var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
29251
29252           var _conflicts = [];
29253
29254           function user(d) {
29255             return typeof formatUser === 'function' ? formatUser(d) : d;
29256           }
29257
29258           function mergeLocation(remote, target) {
29259             function pointEqual(a, b) {
29260               var epsilon = 1e-6;
29261               return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
29262             }
29263
29264             if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
29265               return target;
29266             }
29267
29268             if (_option === 'force_remote') {
29269               return target.update({
29270                 loc: remote.loc
29271               });
29272             }
29273
29274             _conflicts.push(_t('merge_remote_changes.conflict.location', {
29275               user: user(remote.user)
29276             }));
29277
29278             return target;
29279           }
29280
29281           function mergeNodes(base, remote, target) {
29282             if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
29283               return target;
29284             }
29285
29286             if (_option === 'force_remote') {
29287               return target.update({
29288                 nodes: remote.nodes
29289               });
29290             }
29291
29292             var ccount = _conflicts.length;
29293             var o = base.nodes || [];
29294             var a = target.nodes || [];
29295             var b = remote.nodes || [];
29296             var nodes = [];
29297             var hunks = diff3Merge(a, o, b, {
29298               excludeFalseConflicts: true
29299             });
29300
29301             for (var i = 0; i < hunks.length; i++) {
29302               var hunk = hunks[i];
29303
29304               if (hunk.ok) {
29305                 nodes.push.apply(nodes, hunk.ok);
29306               } else {
29307                 // for all conflicts, we can assume c.a !== c.b
29308                 // because `diff3Merge` called with `true` option to exclude false conflicts..
29309                 var c = hunk.conflict;
29310
29311                 if (fastDeepEqual(c.o, c.a)) {
29312                   // only changed remotely
29313                   nodes.push.apply(nodes, c.b);
29314                 } else if (fastDeepEqual(c.o, c.b)) {
29315                   // only changed locally
29316                   nodes.push.apply(nodes, c.a);
29317                 } else {
29318                   // changed both locally and remotely
29319                   _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
29320                     user: user(remote.user)
29321                   }));
29322
29323                   break;
29324                 }
29325               }
29326             }
29327
29328             return _conflicts.length === ccount ? target.update({
29329               nodes: nodes
29330             }) : target;
29331           }
29332
29333           function mergeChildren(targetWay, children, updates, graph) {
29334             function isUsed(node, targetWay) {
29335               var hasInterestingParent = graph.parentWays(node).some(function (way) {
29336                 return way.id !== targetWay.id;
29337               });
29338               return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
29339             }
29340
29341             var ccount = _conflicts.length;
29342
29343             for (var i = 0; i < children.length; i++) {
29344               var id = children[i];
29345               var node = graph.hasEntity(id); // remove unused childNodes..
29346
29347               if (targetWay.nodes.indexOf(id) === -1) {
29348                 if (node && !isUsed(node, targetWay)) {
29349                   updates.removeIds.push(id);
29350                 }
29351
29352                 continue;
29353               } // restore used childNodes..
29354
29355
29356               var local = localGraph.hasEntity(id);
29357               var remote = remoteGraph.hasEntity(id);
29358               var target;
29359
29360               if (_option === 'force_remote' && remote && remote.visible) {
29361                 updates.replacements.push(remote);
29362               } else if (_option === 'force_local' && local) {
29363                 target = osmEntity(local);
29364
29365                 if (remote) {
29366                   target = target.update({
29367                     version: remote.version
29368                   });
29369                 }
29370
29371                 updates.replacements.push(target);
29372               } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
29373                 target = osmEntity(local, {
29374                   version: remote.version
29375                 });
29376
29377                 if (remote.visible) {
29378                   target = mergeLocation(remote, target);
29379                 } else {
29380                   _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29381                     user: user(remote.user)
29382                   }));
29383                 }
29384
29385                 if (_conflicts.length !== ccount) break;
29386                 updates.replacements.push(target);
29387               }
29388             }
29389
29390             return targetWay;
29391           }
29392
29393           function updateChildren(updates, graph) {
29394             for (var i = 0; i < updates.replacements.length; i++) {
29395               graph = graph.replace(updates.replacements[i]);
29396             }
29397
29398             if (updates.removeIds.length) {
29399               graph = actionDeleteMultiple(updates.removeIds)(graph);
29400             }
29401
29402             return graph;
29403           }
29404
29405           function mergeMembers(remote, target) {
29406             if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
29407               return target;
29408             }
29409
29410             if (_option === 'force_remote') {
29411               return target.update({
29412                 members: remote.members
29413               });
29414             }
29415
29416             _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
29417               user: user(remote.user)
29418             }));
29419
29420             return target;
29421           }
29422
29423           function mergeTags(base, remote, target) {
29424             if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
29425               return target;
29426             }
29427
29428             if (_option === 'force_remote') {
29429               return target.update({
29430                 tags: remote.tags
29431               });
29432             }
29433
29434             var ccount = _conflicts.length;
29435             var o = base.tags || {};
29436             var a = target.tags || {};
29437             var b = remote.tags || {};
29438             var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
29439               return !discardTags[k];
29440             });
29441             var tags = Object.assign({}, a); // shallow copy
29442
29443             var changed = false;
29444
29445             for (var i = 0; i < keys.length; i++) {
29446               var k = keys[i];
29447
29448               if (o[k] !== b[k] && a[k] !== b[k]) {
29449                 // changed remotely..
29450                 if (o[k] !== a[k]) {
29451                   // changed locally..
29452                   _conflicts.push(_t('merge_remote_changes.conflict.tags', {
29453                     tag: k,
29454                     local: a[k],
29455                     remote: b[k],
29456                     user: user(remote.user)
29457                   }));
29458                 } else {
29459                   // unchanged locally, accept remote change..
29460                   if (b.hasOwnProperty(k)) {
29461                     tags[k] = b[k];
29462                   } else {
29463                     delete tags[k];
29464                   }
29465
29466                   changed = true;
29467                 }
29468               }
29469             }
29470
29471             return changed && _conflicts.length === ccount ? target.update({
29472               tags: tags
29473             }) : target;
29474           } //  `graph.base()` is the common ancestor of the two graphs.
29475           //  `localGraph` contains user's edits up to saving
29476           //  `remoteGraph` contains remote edits to modified nodes
29477           //  `graph` must be a descendent of `localGraph` and may include
29478           //      some conflict resolution actions performed on it.
29479           //
29480           //                  --- ... --- `localGraph` -- ... -- `graph`
29481           //                 /
29482           //  `graph.base()` --- ... --- `remoteGraph`
29483           //
29484
29485
29486           var action = function action(graph) {
29487             var updates = {
29488               replacements: [],
29489               removeIds: []
29490             };
29491             var base = graph.base().entities[id];
29492             var local = localGraph.entity(id);
29493             var remote = remoteGraph.entity(id);
29494             var target = osmEntity(local, {
29495               version: remote.version
29496             }); // delete/undelete
29497
29498             if (!remote.visible) {
29499               if (_option === 'force_remote') {
29500                 return actionDeleteMultiple([id])(graph);
29501               } else if (_option === 'force_local') {
29502                 if (target.type === 'way') {
29503                   target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
29504                   graph = updateChildren(updates, graph);
29505                 }
29506
29507                 return graph.replace(target);
29508               } else {
29509                 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
29510                   user: user(remote.user)
29511                 }));
29512
29513                 return graph; // do nothing
29514               }
29515             } // merge
29516
29517
29518             if (target.type === 'node') {
29519               target = mergeLocation(remote, target);
29520             } else if (target.type === 'way') {
29521               // pull in any child nodes that may not be present locally..
29522               graph.rebase(remoteGraph.childNodes(remote), [graph], false);
29523               target = mergeNodes(base, remote, target);
29524               target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
29525             } else if (target.type === 'relation') {
29526               target = mergeMembers(remote, target);
29527             }
29528
29529             target = mergeTags(base, remote, target);
29530
29531             if (!_conflicts.length) {
29532               graph = updateChildren(updates, graph).replace(target);
29533             }
29534
29535             return graph;
29536           };
29537
29538           action.withOption = function (opt) {
29539             _option = opt;
29540             return action;
29541           };
29542
29543           action.conflicts = function () {
29544             return _conflicts;
29545           };
29546
29547           return action;
29548         }
29549
29550         // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
29551
29552         function actionMove(moveIDs, tryDelta, projection, cache) {
29553           var _delta = tryDelta;
29554
29555           function setupCache(graph) {
29556             function canMove(nodeID) {
29557               // Allow movement of any node that is in the selectedIDs list..
29558               if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
29559
29560               var parents = graph.parentWays(graph.entity(nodeID));
29561               if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
29562
29563               var parentsMoving = parents.every(function (way) {
29564                 return cache.moving[way.id];
29565               });
29566               if (!parentsMoving) delete cache.moving[nodeID];
29567               return parentsMoving;
29568             }
29569
29570             function cacheEntities(ids) {
29571               for (var i = 0; i < ids.length; i++) {
29572                 var id = ids[i];
29573                 if (cache.moving[id]) continue;
29574                 cache.moving[id] = true;
29575                 var entity = graph.hasEntity(id);
29576                 if (!entity) continue;
29577
29578                 if (entity.type === 'node') {
29579                   cache.nodes.push(id);
29580                   cache.startLoc[id] = entity.loc;
29581                 } else if (entity.type === 'way') {
29582                   cache.ways.push(id);
29583                   cacheEntities(entity.nodes);
29584                 } else {
29585                   cacheEntities(entity.members.map(function (member) {
29586                     return member.id;
29587                   }));
29588                 }
29589               }
29590             }
29591
29592             function cacheIntersections(ids) {
29593               function isEndpoint(way, id) {
29594                 return !way.isClosed() && !!way.affix(id);
29595               }
29596
29597               for (var i = 0; i < ids.length; i++) {
29598                 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
29599
29600                 var childNodes = graph.childNodes(graph.entity(id));
29601
29602                 for (var j = 0; j < childNodes.length; j++) {
29603                   var node = childNodes[j];
29604                   var parents = graph.parentWays(node);
29605                   if (parents.length !== 2) continue;
29606                   var moved = graph.entity(id);
29607                   var unmoved = null;
29608
29609                   for (var k = 0; k < parents.length; k++) {
29610                     var way = parents[k];
29611
29612                     if (!cache.moving[way.id]) {
29613                       unmoved = way;
29614                       break;
29615                     }
29616                   }
29617
29618                   if (!unmoved) continue; // exclude ways that are overly connected..
29619
29620                   if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
29621                   if (moved.isArea() || unmoved.isArea()) continue;
29622                   cache.intersections.push({
29623                     nodeId: node.id,
29624                     movedId: moved.id,
29625                     unmovedId: unmoved.id,
29626                     movedIsEP: isEndpoint(moved, node.id),
29627                     unmovedIsEP: isEndpoint(unmoved, node.id)
29628                   });
29629                 }
29630               }
29631             }
29632
29633             if (!cache) {
29634               cache = {};
29635             }
29636
29637             if (!cache.ok) {
29638               cache.moving = {};
29639               cache.intersections = [];
29640               cache.replacedVertex = {};
29641               cache.startLoc = {};
29642               cache.nodes = [];
29643               cache.ways = [];
29644               cacheEntities(moveIDs);
29645               cacheIntersections(cache.ways);
29646               cache.nodes = cache.nodes.filter(canMove);
29647               cache.ok = true;
29648             }
29649           } // Place a vertex where the moved vertex used to be, to preserve way shape..
29650           //
29651           //  Start:
29652           //      b ---- e
29653           //     / \
29654           //    /   \
29655           //   /     \
29656           //  a       c
29657           //
29658           //      *               node '*' added to preserve shape
29659           //     / \
29660           //    /   b ---- e      way `b,e` moved here:
29661           //   /     \
29662           //  a       c
29663           //
29664           //
29665
29666
29667           function replaceMovedVertex(nodeId, wayId, graph, delta) {
29668             var way = graph.entity(wayId);
29669             var moved = graph.entity(nodeId);
29670             var movedIndex = way.nodes.indexOf(nodeId);
29671             var len, prevIndex, nextIndex;
29672
29673             if (way.isClosed()) {
29674               len = way.nodes.length - 1;
29675               prevIndex = (movedIndex + len - 1) % len;
29676               nextIndex = (movedIndex + len + 1) % len;
29677             } else {
29678               len = way.nodes.length;
29679               prevIndex = movedIndex - 1;
29680               nextIndex = movedIndex + 1;
29681             }
29682
29683             var prev = graph.hasEntity(way.nodes[prevIndex]);
29684             var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
29685
29686             if (!prev || !next) return graph;
29687             var key = wayId + '_' + nodeId;
29688             var orig = cache.replacedVertex[key];
29689
29690             if (!orig) {
29691               orig = osmNode();
29692               cache.replacedVertex[key] = orig;
29693               cache.startLoc[orig.id] = cache.startLoc[nodeId];
29694             }
29695
29696             var start, end;
29697
29698             if (delta) {
29699               start = projection(cache.startLoc[nodeId]);
29700               end = projection.invert(geoVecAdd(start, delta));
29701             } else {
29702               end = cache.startLoc[nodeId];
29703             }
29704
29705             orig = orig.move(end);
29706             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..
29707
29708             if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
29709
29710             var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
29711             var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
29712             var d1 = geoPathLength(p1);
29713             var d2 = geoPathLength(p2);
29714             var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
29715
29716             if (way.isClosed() && insertAt === 0) insertAt = len;
29717             way = way.addNode(orig.id, insertAt);
29718             return graph.replace(orig).replace(way);
29719           } // Remove duplicate vertex that might have been added by
29720           // replaceMovedVertex.  This is done after the unzorro checks.
29721
29722
29723           function removeDuplicateVertices(wayId, graph) {
29724             var way = graph.entity(wayId);
29725             var epsilon = 1e-6;
29726             var prev, curr;
29727
29728             function isInteresting(node, graph) {
29729               return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
29730             }
29731
29732             for (var i = 0; i < way.nodes.length; i++) {
29733               curr = graph.entity(way.nodes[i]);
29734
29735               if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
29736                 if (!isInteresting(prev, graph)) {
29737                   way = way.removeNode(prev.id);
29738                   graph = graph.replace(way).remove(prev);
29739                 } else if (!isInteresting(curr, graph)) {
29740                   way = way.removeNode(curr.id);
29741                   graph = graph.replace(way).remove(curr);
29742                 }
29743               }
29744
29745               prev = curr;
29746             }
29747
29748             return graph;
29749           } // Reorder nodes around intersections that have moved..
29750           //
29751           //  Start:                way1.nodes: b,e         (moving)
29752           //  a - b - c ----- d     way2.nodes: a,b,c,d     (static)
29753           //      |                 vertex: b
29754           //      e                 isEP1: true,  isEP2, false
29755           //
29756           //  way1 `b,e` moved here:
29757           //  a ----- c = b - d
29758           //              |
29759           //              e
29760           //
29761           //  reorder nodes         way1.nodes: b,e
29762           //  a ----- c - b - d     way2.nodes: a,c,b,d
29763           //              |
29764           //              e
29765           //
29766
29767
29768           function unZorroIntersection(intersection, graph) {
29769             var vertex = graph.entity(intersection.nodeId);
29770             var way1 = graph.entity(intersection.movedId);
29771             var way2 = graph.entity(intersection.unmovedId);
29772             var isEP1 = intersection.movedIsEP;
29773             var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
29774
29775             if (isEP1 && isEP2) return graph;
29776             var nodes1 = graph.childNodes(way1).filter(function (n) {
29777               return n !== vertex;
29778             });
29779             var nodes2 = graph.childNodes(way2).filter(function (n) {
29780               return n !== vertex;
29781             });
29782             if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
29783             if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
29784             var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
29785             var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
29786             var loc; // snap vertex to nearest edge (or some point between them)..
29787
29788             if (!isEP1 && !isEP2) {
29789               var epsilon = 1e-6,
29790                   maxIter = 10;
29791
29792               for (var i = 0; i < maxIter; i++) {
29793                 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
29794                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
29795                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
29796                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
29797               }
29798             } else if (!isEP1) {
29799               loc = edge1.loc;
29800             } else {
29801               loc = edge2.loc;
29802             }
29803
29804             graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
29805
29806             if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
29807               way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
29808               graph = graph.replace(way1);
29809             }
29810
29811             if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
29812               way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
29813               graph = graph.replace(way2);
29814             }
29815
29816             return graph;
29817           }
29818
29819           function cleanupIntersections(graph) {
29820             for (var i = 0; i < cache.intersections.length; i++) {
29821               var obj = cache.intersections[i];
29822               graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
29823               graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
29824               graph = unZorroIntersection(obj, graph);
29825               graph = removeDuplicateVertices(obj.movedId, graph);
29826               graph = removeDuplicateVertices(obj.unmovedId, graph);
29827             }
29828
29829             return graph;
29830           } // check if moving way endpoint can cross an unmoved way, if so limit delta..
29831
29832
29833           function limitDelta(graph) {
29834             function moveNode(loc) {
29835               return geoVecAdd(projection(loc), _delta);
29836             }
29837
29838             for (var i = 0; i < cache.intersections.length; i++) {
29839               var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
29840
29841               if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
29842
29843               if (!obj.movedIsEP) continue;
29844               var node = graph.entity(obj.nodeId);
29845               var start = projection(node.loc);
29846               var end = geoVecAdd(start, _delta);
29847               var movedNodes = graph.childNodes(graph.entity(obj.movedId));
29848               var movedPath = movedNodes.map(function (n) {
29849                 return moveNode(n.loc);
29850               });
29851               var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
29852               var unmovedPath = unmovedNodes.map(function (n) {
29853                 return projection(n.loc);
29854               });
29855               var hits = geoPathIntersections(movedPath, unmovedPath);
29856
29857               for (var j = 0; i < hits.length; i++) {
29858                 if (geoVecEqual(hits[j], end)) continue;
29859                 var edge = geoChooseEdge(unmovedNodes, end, projection);
29860                 _delta = geoVecSubtract(projection(edge.loc), start);
29861               }
29862             }
29863           }
29864
29865           var action = function action(graph) {
29866             if (_delta[0] === 0 && _delta[1] === 0) return graph;
29867             setupCache(graph);
29868
29869             if (cache.intersections.length) {
29870               limitDelta(graph);
29871             }
29872
29873             for (var i = 0; i < cache.nodes.length; i++) {
29874               var node = graph.entity(cache.nodes[i]);
29875               var start = projection(node.loc);
29876               var end = geoVecAdd(start, _delta);
29877               graph = graph.replace(node.move(projection.invert(end)));
29878             }
29879
29880             if (cache.intersections.length) {
29881               graph = cleanupIntersections(graph);
29882             }
29883
29884             return graph;
29885           };
29886
29887           action.delta = function () {
29888             return _delta;
29889           };
29890
29891           return action;
29892         }
29893
29894         function actionMoveMember(relationId, fromIndex, toIndex) {
29895           return function (graph) {
29896             return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
29897           };
29898         }
29899
29900         function actionMoveNode(nodeID, toLoc) {
29901           var action = function action(graph, t) {
29902             if (t === null || !isFinite(t)) t = 1;
29903             t = Math.min(Math.max(+t, 0), 1);
29904             var node = graph.entity(nodeID);
29905             return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
29906           };
29907
29908           action.transitionable = true;
29909           return action;
29910         }
29911
29912         function actionNoop() {
29913           return function (graph) {
29914             return graph;
29915           };
29916         }
29917
29918         function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
29919           var epsilon = ep || 1e-4;
29920           var threshold = degThresh || 13; // degrees within right or straight to alter
29921           // We test normalized dot products so we can compare as cos(angle)
29922
29923           var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
29924           var upperThreshold = Math.cos(threshold * Math.PI / 180);
29925
29926           var action = function action(graph, t) {
29927             if (t === null || !isFinite(t)) t = 1;
29928             t = Math.min(Math.max(+t, 0), 1);
29929             var way = graph.entity(wayID);
29930             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
29931
29932             if (way.tags.nonsquare) {
29933               var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
29934
29935               delete tags.nonsquare;
29936               way = way.update({
29937                 tags: tags
29938               });
29939             }
29940
29941             graph = graph.replace(way);
29942             var isClosed = way.isClosed();
29943             var nodes = graph.childNodes(way).slice(); // shallow copy
29944
29945             if (isClosed) nodes.pop();
29946
29947             if (vertexID !== undefined) {
29948               nodes = nodeSubset(nodes, vertexID, isClosed);
29949               if (nodes.length !== 3) return graph;
29950             } // note: all geometry functions here use the unclosed node/point/coord list
29951
29952
29953             var nodeCount = {};
29954             var points = [];
29955             var corner = {
29956               i: 0,
29957               dotp: 1
29958             };
29959             var node, point, loc, score, motions, i, j;
29960
29961             for (i = 0; i < nodes.length; i++) {
29962               node = nodes[i];
29963               nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
29964               points.push({
29965                 id: node.id,
29966                 coord: projection(node.loc)
29967               });
29968             }
29969
29970             if (points.length === 3) {
29971               // move only one vertex for right triangle
29972               for (i = 0; i < 1000; i++) {
29973                 motions = points.map(calcMotion);
29974                 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
29975                 score = corner.dotp;
29976
29977                 if (score < epsilon) {
29978                   break;
29979                 }
29980               }
29981
29982               node = graph.entity(nodes[corner.i].id);
29983               loc = projection.invert(points[corner.i].coord);
29984               graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
29985             } else {
29986               var straights = [];
29987               var simplified = []; // Remove points from nearly straight sections..
29988               // This produces a simplified shape to orthogonalize
29989
29990               for (i = 0; i < points.length; i++) {
29991                 point = points[i];
29992                 var dotp = 0;
29993
29994                 if (isClosed || i > 0 && i < points.length - 1) {
29995                   var a = points[(i - 1 + points.length) % points.length];
29996                   var b = points[(i + 1) % points.length];
29997                   dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
29998                 }
29999
30000                 if (dotp > upperThreshold) {
30001                   straights.push(point);
30002                 } else {
30003                   simplified.push(point);
30004                 }
30005               } // Orthogonalize the simplified shape
30006
30007
30008               var bestPoints = clonePoints(simplified);
30009               var originalPoints = clonePoints(simplified);
30010               score = Infinity;
30011
30012               for (i = 0; i < 1000; i++) {
30013                 motions = simplified.map(calcMotion);
30014
30015                 for (j = 0; j < motions.length; j++) {
30016                   simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
30017                 }
30018
30019                 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
30020
30021                 if (newScore < score) {
30022                   bestPoints = clonePoints(simplified);
30023                   score = newScore;
30024                 }
30025
30026                 if (score < epsilon) {
30027                   break;
30028                 }
30029               }
30030
30031               var bestCoords = bestPoints.map(function (p) {
30032                 return p.coord;
30033               });
30034               if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
30035
30036               for (i = 0; i < bestPoints.length; i++) {
30037                 point = bestPoints[i];
30038
30039                 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
30040                   node = graph.entity(point.id);
30041                   loc = projection.invert(point.coord);
30042                   graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
30043                 }
30044               } // move the nodes along straight segments
30045
30046
30047               for (i = 0; i < straights.length; i++) {
30048                 point = straights[i];
30049                 if (nodeCount[point.id] > 1) continue; // skip self-intersections
30050
30051                 node = graph.entity(point.id);
30052
30053                 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
30054                   // remove uninteresting points..
30055                   graph = actionDeleteNode(node.id)(graph);
30056                 } else {
30057                   // move interesting points to the nearest edge..
30058                   var choice = geoVecProject(point.coord, bestCoords);
30059
30060                   if (choice) {
30061                     loc = projection.invert(choice.target);
30062                     graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
30063                   }
30064                 }
30065               }
30066             }
30067
30068             return graph;
30069
30070             function clonePoints(array) {
30071               return array.map(function (p) {
30072                 return {
30073                   id: p.id,
30074                   coord: [p.coord[0], p.coord[1]]
30075                 };
30076               });
30077             }
30078
30079             function calcMotion(point, i, array) {
30080               // don't try to move the endpoints of a non-closed way.
30081               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)
30082
30083               if (nodeCount[array[i].id] > 1) return [0, 0];
30084               var a = array[(i - 1 + array.length) % array.length].coord;
30085               var origin = point.coord;
30086               var b = array[(i + 1) % array.length].coord;
30087               var p = geoVecSubtract(a, origin);
30088               var q = geoVecSubtract(b, origin);
30089               var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
30090               p = geoVecNormalize(p);
30091               q = geoVecNormalize(q);
30092               var dotp = p[0] * q[0] + p[1] * q[1];
30093               var val = Math.abs(dotp);
30094
30095               if (val < lowerThreshold) {
30096                 // nearly orthogonal
30097                 corner.i = i;
30098                 corner.dotp = val;
30099                 var vec = geoVecNormalize(geoVecAdd(p, q));
30100                 return geoVecScale(vec, 0.1 * dotp * scale);
30101               }
30102
30103               return [0, 0]; // do nothing
30104             }
30105           }; // if we are only orthogonalizing one vertex,
30106           // get that vertex and the previous and next
30107
30108
30109           function nodeSubset(nodes, vertexID, isClosed) {
30110             var first = isClosed ? 0 : 1;
30111             var last = isClosed ? nodes.length : nodes.length - 1;
30112
30113             for (var i = first; i < last; i++) {
30114               if (nodes[i].id === vertexID) {
30115                 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
30116               }
30117             }
30118
30119             return [];
30120           }
30121
30122           action.disabled = function (graph) {
30123             var way = graph.entity(wayID);
30124             way = way.removeNode(''); // sanity check - remove any consecutive duplicates
30125
30126             graph = graph.replace(way);
30127             var isClosed = way.isClosed();
30128             var nodes = graph.childNodes(way).slice(); // shallow copy
30129
30130             if (isClosed) nodes.pop();
30131             var allowStraightAngles = false;
30132
30133             if (vertexID !== undefined) {
30134               allowStraightAngles = true;
30135               nodes = nodeSubset(nodes, vertexID, isClosed);
30136               if (nodes.length !== 3) return 'end_vertex';
30137             }
30138
30139             var coords = nodes.map(function (n) {
30140               return projection(n.loc);
30141             });
30142             var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
30143
30144             if (score === null) {
30145               return 'not_squarish';
30146             } else if (score === 0) {
30147               return 'square_enough';
30148             } else {
30149               return false;
30150             }
30151           };
30152
30153           action.transitionable = true;
30154           return action;
30155         }
30156
30157         //
30158         // `turn` must be an `osmTurn` object
30159         // see osm/intersection.js, pathToTurn()
30160         //
30161         // This specifies a restriction of type `restriction` when traveling from
30162         // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
30163         // (The action does not check that these entities form a valid intersection.)
30164         //
30165         // From, to, and via ways should be split before calling this action.
30166         // (old versions of the code would split the ways here, but we no longer do it)
30167         //
30168         // For testing convenience, accepts a restrictionID to assign to the new
30169         // relation. Normally, this will be undefined and the relation will
30170         // automatically be assigned a new ID.
30171         //
30172
30173         function actionRestrictTurn(turn, restrictionType, restrictionID) {
30174           return function (graph) {
30175             var fromWay = graph.entity(turn.from.way);
30176             var toWay = graph.entity(turn.to.way);
30177             var viaNode = turn.via.node && graph.entity(turn.via.node);
30178             var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
30179               return graph.entity(id);
30180             });
30181             var members = [];
30182             members.push({
30183               id: fromWay.id,
30184               type: 'way',
30185               role: 'from'
30186             });
30187
30188             if (viaNode) {
30189               members.push({
30190                 id: viaNode.id,
30191                 type: 'node',
30192                 role: 'via'
30193               });
30194             } else if (viaWays) {
30195               viaWays.forEach(function (viaWay) {
30196                 members.push({
30197                   id: viaWay.id,
30198                   type: 'way',
30199                   role: 'via'
30200                 });
30201               });
30202             }
30203
30204             members.push({
30205               id: toWay.id,
30206               type: 'way',
30207               role: 'to'
30208             });
30209             return graph.replace(osmRelation({
30210               id: restrictionID,
30211               tags: {
30212                 type: 'restriction',
30213                 restriction: restrictionType
30214               },
30215               members: members
30216             }));
30217           };
30218         }
30219
30220         function actionRevert(id) {
30221           var action = function action(graph) {
30222             var entity = graph.hasEntity(id),
30223                 base = graph.base().entities[id];
30224
30225             if (entity && !base) {
30226               // entity will be removed..
30227               if (entity.type === 'node') {
30228                 graph.parentWays(entity).forEach(function (parent) {
30229                   parent = parent.removeNode(id);
30230                   graph = graph.replace(parent);
30231
30232                   if (parent.isDegenerate()) {
30233                     graph = actionDeleteWay(parent.id)(graph);
30234                   }
30235                 });
30236               }
30237
30238               graph.parentRelations(entity).forEach(function (parent) {
30239                 parent = parent.removeMembersWithID(id);
30240                 graph = graph.replace(parent);
30241
30242                 if (parent.isDegenerate()) {
30243                   graph = actionDeleteRelation(parent.id)(graph);
30244                 }
30245               });
30246             }
30247
30248             return graph.revert(id);
30249           };
30250
30251           return action;
30252         }
30253
30254         function actionRotate(rotateIds, pivot, angle, projection) {
30255           var action = function action(graph) {
30256             return graph.update(function (graph) {
30257               utilGetAllNodes(rotateIds, graph).forEach(function (node) {
30258                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
30259                 graph = graph.replace(node.move(projection.invert(point)));
30260               });
30261             });
30262           };
30263
30264           return action;
30265         }
30266
30267         function actionScale(ids, pivotLoc, scaleFactor, projection) {
30268           return function (graph) {
30269             return graph.update(function (graph) {
30270               var point, radial;
30271               utilGetAllNodes(ids, graph).forEach(function (node) {
30272                 point = projection(node.loc);
30273                 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
30274                 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
30275                 graph = graph.replace(node.move(projection.invert(point)));
30276               });
30277             });
30278           };
30279         }
30280
30281         /* Align nodes along their common axis */
30282
30283         function actionStraightenNodes(nodeIDs, projection) {
30284           function positionAlongWay(a, o, b) {
30285             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30286           } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
30287
30288
30289           function getEndpoints(points) {
30290             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30291             // The shape's surrounding rectangle has 2 axes of symmetry.
30292             // Snap points to the long axis
30293
30294             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30295             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30296             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30297             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30298             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30299
30300             if (isLong) {
30301               return [p1, q1];
30302             }
30303
30304             return [p2, q2];
30305           }
30306
30307           var action = function action(graph, t) {
30308             if (t === null || !isFinite(t)) t = 1;
30309             t = Math.min(Math.max(+t, 0), 1);
30310             var nodes = nodeIDs.map(function (id) {
30311               return graph.entity(id);
30312             });
30313             var points = nodes.map(function (n) {
30314               return projection(n.loc);
30315             });
30316             var endpoints = getEndpoints(points);
30317             var startPoint = endpoints[0];
30318             var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
30319
30320             for (var i = 0; i < points.length; i++) {
30321               var node = nodes[i];
30322               var point = points[i];
30323               var u = positionAlongWay(point, startPoint, endPoint);
30324               var point2 = geoVecInterp(startPoint, endPoint, u);
30325               var loc2 = projection.invert(point2);
30326               graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30327             }
30328
30329             return graph;
30330           };
30331
30332           action.disabled = function (graph) {
30333             var nodes = nodeIDs.map(function (id) {
30334               return graph.entity(id);
30335             });
30336             var points = nodes.map(function (n) {
30337               return projection(n.loc);
30338             });
30339             var endpoints = getEndpoints(points);
30340             var startPoint = endpoints[0];
30341             var endPoint = endpoints[1];
30342             var maxDistance = 0;
30343
30344             for (var i = 0; i < points.length; i++) {
30345               var point = points[i];
30346               var u = positionAlongWay(point, startPoint, endPoint);
30347               var p = geoVecInterp(startPoint, endPoint, u);
30348               var dist = geoVecLength(p, point);
30349
30350               if (!isNaN(dist) && dist > maxDistance) {
30351                 maxDistance = dist;
30352               }
30353             }
30354
30355             if (maxDistance < 0.0001) {
30356               return 'straight_enough';
30357             }
30358           };
30359
30360           action.transitionable = true;
30361           return action;
30362         }
30363
30364         /*
30365          * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
30366          */
30367
30368         function actionStraightenWay(selectedIDs, projection) {
30369           function positionAlongWay(a, o, b) {
30370             return geoVecDot(a, b, o) / geoVecDot(b, b, o);
30371           } // Return all selected ways as a continuous, ordered array of nodes
30372
30373
30374           function allNodes(graph) {
30375             var nodes = [];
30376             var startNodes = [];
30377             var endNodes = [];
30378             var remainingWays = [];
30379             var selectedWays = selectedIDs.filter(function (w) {
30380               return graph.entity(w).type === 'way';
30381             });
30382             var selectedNodes = selectedIDs.filter(function (n) {
30383               return graph.entity(n).type === 'node';
30384             });
30385
30386             for (var i = 0; i < selectedWays.length; i++) {
30387               var way = graph.entity(selectedWays[i]);
30388               nodes = way.nodes.slice(0);
30389               remainingWays.push(nodes);
30390               startNodes.push(nodes[0]);
30391               endNodes.push(nodes[nodes.length - 1]);
30392             } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
30393             //   and need to be removed so currNode difference calculation below works)
30394             // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
30395
30396
30397             startNodes = startNodes.filter(function (n) {
30398               return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
30399             });
30400             endNodes = endNodes.filter(function (n) {
30401               return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
30402             }); // Choose the initial endpoint to start from
30403
30404             var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
30405             var nextWay = [];
30406             nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
30407
30408             var getNextWay = function getNextWay(currNode, remainingWays) {
30409               return remainingWays.filter(function (way) {
30410                 return way[0] === currNode || way[way.length - 1] === currNode;
30411               })[0];
30412             }; // Add nodes to end of nodes array, until all ways are added
30413
30414
30415             while (remainingWays.length) {
30416               nextWay = getNextWay(currNode, remainingWays);
30417               remainingWays = utilArrayDifference(remainingWays, [nextWay]);
30418
30419               if (nextWay[0] !== currNode) {
30420                 nextWay.reverse();
30421               }
30422
30423               nodes = nodes.concat(nextWay);
30424               currNode = nodes[nodes.length - 1];
30425             } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
30426
30427
30428             if (selectedNodes.length === 2) {
30429               var startNodeIdx = nodes.indexOf(selectedNodes[0]);
30430               var endNodeIdx = nodes.indexOf(selectedNodes[1]);
30431               var sortedStartEnd = [startNodeIdx, endNodeIdx];
30432               sortedStartEnd.sort(function (a, b) {
30433                 return a - b;
30434               });
30435               nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
30436             }
30437
30438             return nodes.map(function (n) {
30439               return graph.entity(n);
30440             });
30441           }
30442
30443           function shouldKeepNode(node, graph) {
30444             return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
30445           }
30446
30447           var action = function action(graph, t) {
30448             if (t === null || !isFinite(t)) t = 1;
30449             t = Math.min(Math.max(+t, 0), 1);
30450             var nodes = allNodes(graph);
30451             var points = nodes.map(function (n) {
30452               return projection(n.loc);
30453             });
30454             var startPoint = points[0];
30455             var endPoint = points[points.length - 1];
30456             var toDelete = [];
30457             var i;
30458
30459             for (i = 1; i < points.length - 1; i++) {
30460               var node = nodes[i];
30461               var point = points[i];
30462
30463               if (t < 1 || shouldKeepNode(node, graph)) {
30464                 var u = positionAlongWay(point, startPoint, endPoint);
30465                 var p = geoVecInterp(startPoint, endPoint, u);
30466                 var loc2 = projection.invert(p);
30467                 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
30468               } else {
30469                 // safe to delete
30470                 if (toDelete.indexOf(node) === -1) {
30471                   toDelete.push(node);
30472                 }
30473               }
30474             }
30475
30476             for (i = 0; i < toDelete.length; i++) {
30477               graph = actionDeleteNode(toDelete[i].id)(graph);
30478             }
30479
30480             return graph;
30481           };
30482
30483           action.disabled = function (graph) {
30484             // check way isn't too bendy
30485             var nodes = allNodes(graph);
30486             var points = nodes.map(function (n) {
30487               return projection(n.loc);
30488             });
30489             var startPoint = points[0];
30490             var endPoint = points[points.length - 1];
30491             var threshold = 0.2 * geoVecLength(startPoint, endPoint);
30492             var i;
30493
30494             if (threshold === 0) {
30495               return 'too_bendy';
30496             }
30497
30498             var maxDistance = 0;
30499
30500             for (i = 1; i < points.length - 1; i++) {
30501               var point = points[i];
30502               var u = positionAlongWay(point, startPoint, endPoint);
30503               var p = geoVecInterp(startPoint, endPoint, u);
30504               var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
30505
30506               if (isNaN(dist) || dist > threshold) {
30507                 return 'too_bendy';
30508               } else if (dist > maxDistance) {
30509                 maxDistance = dist;
30510               }
30511             }
30512
30513             var keepingAllNodes = nodes.every(function (node, i) {
30514               return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
30515             });
30516
30517             if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
30518             keepingAllNodes) {
30519               return 'straight_enough';
30520             }
30521           };
30522
30523           action.transitionable = true;
30524           return action;
30525         }
30526
30527         //
30528         // `turn` must be an `osmTurn` object with a `restrictionID` property.
30529         // see osm/intersection.js, pathToTurn()
30530         //
30531
30532         function actionUnrestrictTurn(turn) {
30533           return function (graph) {
30534             return actionDeleteRelation(turn.restrictionID)(graph);
30535           };
30536         }
30537
30538         /* Reflect the given area around its axis of symmetry */
30539
30540         function actionReflect(reflectIds, projection) {
30541           var _useLongAxis = true;
30542
30543           var action = function action(graph, t) {
30544             if (t === null || !isFinite(t)) t = 1;
30545             t = Math.min(Math.max(+t, 0), 1);
30546             var nodes = utilGetAllNodes(reflectIds, graph);
30547             var points = nodes.map(function (n) {
30548               return projection(n.loc);
30549             });
30550             var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
30551             // The shape's surrounding rectangle has 2 axes of symmetry.
30552             // Reflect across the longer axis by default.
30553
30554             var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
30555             var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
30556             var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
30557             var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
30558             var p, q;
30559             var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
30560
30561             if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
30562               p = p1;
30563               q = q1;
30564             } else {
30565               p = p2;
30566               q = q2;
30567             } // reflect c across pq
30568             // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
30569
30570
30571             var dx = q[0] - p[0];
30572             var dy = q[1] - p[1];
30573             var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
30574             var b = 2 * dx * dy / (dx * dx + dy * dy);
30575
30576             for (var i = 0; i < nodes.length; i++) {
30577               var node = nodes[i];
30578               var c = projection(node.loc);
30579               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]];
30580               var loc2 = projection.invert(c2);
30581               node = node.move(geoVecInterp(node.loc, loc2, t));
30582               graph = graph.replace(node);
30583             }
30584
30585             return graph;
30586           };
30587
30588           action.useLongAxis = function (val) {
30589             if (!arguments.length) return _useLongAxis;
30590             _useLongAxis = val;
30591             return action;
30592           };
30593
30594           action.transitionable = true;
30595           return action;
30596         }
30597
30598         function actionUpgradeTags(entityId, oldTags, replaceTags) {
30599           return function (graph) {
30600             var entity = graph.entity(entityId);
30601             var tags = Object.assign({}, entity.tags); // shallow copy
30602
30603             var transferValue;
30604             var semiIndex;
30605
30606             for (var oldTagKey in oldTags) {
30607               if (!(oldTagKey in tags)) continue; // wildcard match
30608
30609               if (oldTags[oldTagKey] === '*') {
30610                 // note the value since we might need to transfer it
30611                 transferValue = tags[oldTagKey];
30612                 delete tags[oldTagKey]; // exact match
30613               } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
30614                 delete tags[oldTagKey]; // match is within semicolon-delimited values
30615               } else {
30616                 var vals = tags[oldTagKey].split(';').filter(Boolean);
30617                 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
30618
30619                 if (vals.length === 1 || oldIndex === -1) {
30620                   delete tags[oldTagKey];
30621                 } else {
30622                   if (replaceTags && replaceTags[oldTagKey]) {
30623                     // replacing a value within a semicolon-delimited value, note the index
30624                     semiIndex = oldIndex;
30625                   }
30626
30627                   vals.splice(oldIndex, 1);
30628                   tags[oldTagKey] = vals.join(';');
30629                 }
30630               }
30631             }
30632
30633             if (replaceTags) {
30634               for (var replaceKey in replaceTags) {
30635                 var replaceValue = replaceTags[replaceKey];
30636
30637                 if (replaceValue === '*') {
30638                   if (tags[replaceKey] && tags[replaceKey] !== 'no') {
30639                     // allow any pre-existing value except `no` (troll tag)
30640                     continue;
30641                   } else {
30642                     // otherwise assume `yes` is okay
30643                     tags[replaceKey] = 'yes';
30644                   }
30645                 } else if (replaceValue === '$1') {
30646                   tags[replaceKey] = transferValue;
30647                 } else {
30648                   if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
30649                     // don't override preexisting values
30650                     var existingVals = tags[replaceKey].split(';').filter(Boolean);
30651
30652                     if (existingVals.indexOf(replaceValue) === -1) {
30653                       existingVals.splice(semiIndex, 0, replaceValue);
30654                       tags[replaceKey] = existingVals.join(';');
30655                     }
30656                   } else {
30657                     tags[replaceKey] = replaceValue;
30658                   }
30659                 }
30660               }
30661             }
30662
30663             return graph.replace(entity.update({
30664               tags: tags
30665             }));
30666           };
30667         }
30668
30669         function behaviorEdit(context) {
30670           function behavior() {
30671             context.map().minzoom(context.minEditableZoom());
30672           }
30673
30674           behavior.off = function () {
30675             context.map().minzoom(0);
30676           };
30677
30678           return behavior;
30679         }
30680
30681         /*
30682            The hover behavior adds the `.hover` class on pointerover to all elements to which
30683            the identical datum is bound, and removes it on pointerout.
30684
30685            The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
30686            representation may consist of several elements scattered throughout the DOM hierarchy.
30687            Only one of these elements can have the :hover pseudo-class, but all of them will
30688            have the .hover class.
30689          */
30690
30691         function behaviorHover(context) {
30692           var dispatch$1 = dispatch('hover');
30693
30694           var _selection = select(null);
30695
30696           var _newNodeId = null;
30697           var _initialNodeID = null;
30698
30699           var _altDisables;
30700
30701           var _ignoreVertex;
30702
30703           var _targets = []; // use pointer events on supported platforms; fallback to mouse events
30704
30705           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
30706
30707           function keydown(d3_event) {
30708             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30709               _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
30710
30711               _selection.classed('hover-disabled', true);
30712
30713               dispatch$1.call('hover', this, null);
30714             }
30715           }
30716
30717           function keyup(d3_event) {
30718             if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
30719               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
30720
30721               _selection.classed('hover-disabled', false);
30722
30723               dispatch$1.call('hover', this, _targets);
30724             }
30725           }
30726
30727           function behavior(selection) {
30728             _selection = selection;
30729             _targets = [];
30730
30731             if (_initialNodeID) {
30732               _newNodeId = _initialNodeID;
30733               _initialNodeID = null;
30734             } else {
30735               _newNodeId = null;
30736             }
30737
30738             _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
30739             .on(_pointerPrefix + 'down.hover', pointerover);
30740
30741             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
30742
30743             function eventTarget(d3_event) {
30744               var datum = d3_event.target && d3_event.target.__data__;
30745               if (_typeof(datum) !== 'object') return null;
30746
30747               if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
30748                 return datum.properties.entity;
30749               }
30750
30751               return datum;
30752             }
30753
30754             function pointerover(d3_event) {
30755               // ignore mouse hovers with buttons pressed unless dragging
30756               if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
30757               var target = eventTarget(d3_event);
30758
30759               if (target && _targets.indexOf(target) === -1) {
30760                 _targets.push(target);
30761
30762                 updateHover(d3_event, _targets);
30763               }
30764             }
30765
30766             function pointerout(d3_event) {
30767               var target = eventTarget(d3_event);
30768
30769               var index = _targets.indexOf(target);
30770
30771               if (index !== -1) {
30772                 _targets.splice(index);
30773
30774                 updateHover(d3_event, _targets);
30775               }
30776             }
30777
30778             function allowsVertex(d) {
30779               return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30780             }
30781
30782             function modeAllowsHover(target) {
30783               var mode = context.mode();
30784
30785               if (mode.id === 'add-point') {
30786                 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
30787               }
30788
30789               return true;
30790             }
30791
30792             function updateHover(d3_event, targets) {
30793               _selection.selectAll('.hover').classed('hover', false);
30794
30795               _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30796
30797               var mode = context.mode();
30798
30799               if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
30800                 var node = targets.find(function (target) {
30801                   return target instanceof osmEntity && target.type === 'node';
30802                 });
30803                 _newNodeId = node && node.id;
30804               }
30805
30806               targets = targets.filter(function (datum) {
30807                 if (datum instanceof osmEntity) {
30808                   // If drawing a way, don't hover on a node that was just placed. #3974
30809                   return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
30810                 }
30811
30812                 return true;
30813               });
30814               var selector = '';
30815
30816               for (var i in targets) {
30817                 var datum = targets[i]; // What are we hovering over?
30818
30819                 if (datum.__featurehash__) {
30820                   // hovering custom data
30821                   selector += ', .data' + datum.__featurehash__;
30822                 } else if (datum instanceof QAItem) {
30823                   selector += ', .' + datum.service + '.itemId-' + datum.id;
30824                 } else if (datum instanceof osmNote) {
30825                   selector += ', .note-' + datum.id;
30826                 } else if (datum instanceof osmEntity) {
30827                   selector += ', .' + datum.id;
30828
30829                   if (datum.type === 'relation') {
30830                     for (var j in datum.members) {
30831                       selector += ', .' + datum.members[j].id;
30832                     }
30833                   }
30834                 }
30835               }
30836
30837               var suppressed = _altDisables && d3_event && d3_event.altKey;
30838
30839               if (selector.trim().length) {
30840                 // remove the first comma
30841                 selector = selector.slice(1);
30842
30843                 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
30844               }
30845
30846               dispatch$1.call('hover', this, !suppressed && targets);
30847             }
30848           }
30849
30850           behavior.off = function (selection) {
30851             selection.selectAll('.hover').classed('hover', false);
30852             selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
30853             selection.classed('hover-disabled', false);
30854             selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
30855             select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
30856           };
30857
30858           behavior.altDisables = function (val) {
30859             if (!arguments.length) return _altDisables;
30860             _altDisables = val;
30861             return behavior;
30862           };
30863
30864           behavior.ignoreVertex = function (val) {
30865             if (!arguments.length) return _ignoreVertex;
30866             _ignoreVertex = val;
30867             return behavior;
30868           };
30869
30870           behavior.initialNodeID = function (nodeId) {
30871             _initialNodeID = nodeId;
30872             return behavior;
30873           };
30874
30875           return utilRebind(behavior, dispatch$1, 'on');
30876         }
30877
30878         var _disableSpace = false;
30879         var _lastSpace = null;
30880         function behaviorDraw(context) {
30881           var dispatch$1 = dispatch('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
30882           var keybinding = utilKeybinding('draw');
30883
30884           var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
30885
30886           var _edit = behaviorEdit(context);
30887
30888           var _closeTolerance = 4;
30889           var _tolerance = 12;
30890           var _mouseLeave = false;
30891           var _lastMouse = null;
30892
30893           var _lastPointerUpEvent;
30894
30895           var _downPointer; // use pointer events on supported platforms; fallback to mouse events
30896
30897
30898           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
30899           // - `mode/drag_node.js` `datum()`
30900
30901
30902           function datum(d3_event) {
30903             var mode = context.mode();
30904             var isNote = mode && mode.id.indexOf('note') !== -1;
30905             if (d3_event.altKey || isNote) return {};
30906             var element;
30907
30908             if (d3_event.type === 'keydown') {
30909               element = _lastMouse && _lastMouse.target;
30910             } else {
30911               element = d3_event.target;
30912             } // When drawing, snap only to touch targets..
30913             // (this excludes area fills and active drawing elements)
30914
30915
30916             var d = element.__data__;
30917             return d && d.properties && d.properties.target ? d : {};
30918           }
30919
30920           function pointerdown(d3_event) {
30921             if (_downPointer) return;
30922             var pointerLocGetter = utilFastMouse(this);
30923             _downPointer = {
30924               id: d3_event.pointerId || 'mouse',
30925               pointerLocGetter: pointerLocGetter,
30926               downTime: +new Date(),
30927               downLoc: pointerLocGetter(d3_event)
30928             };
30929             dispatch$1.call('down', this, d3_event, datum(d3_event));
30930           }
30931
30932           function pointerup(d3_event) {
30933             if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
30934             var downPointer = _downPointer;
30935             _downPointer = null;
30936             _lastPointerUpEvent = d3_event;
30937             if (downPointer.isCancelled) return;
30938             var t2 = +new Date();
30939             var p2 = downPointer.pointerLocGetter(d3_event);
30940             var dist = geoVecLength(downPointer.downLoc, p2);
30941
30942             if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
30943               // Prevent a quick second click
30944               select(window).on('click.draw-block', function () {
30945                 d3_event.stopPropagation();
30946               }, true);
30947               context.map().dblclickZoomEnable(false);
30948               window.setTimeout(function () {
30949                 context.map().dblclickZoomEnable(true);
30950                 select(window).on('click.draw-block', null);
30951               }, 500);
30952               click(d3_event, p2);
30953             }
30954           }
30955
30956           function pointermove(d3_event) {
30957             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
30958               var p2 = _downPointer.pointerLocGetter(d3_event);
30959
30960               var dist = geoVecLength(_downPointer.downLoc, p2);
30961
30962               if (dist >= _closeTolerance) {
30963                 _downPointer.isCancelled = true;
30964                 dispatch$1.call('downcancel', this);
30965               }
30966             }
30967
30968             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
30969             // events immediately after non-mouse pointerup events; detect and ignore them.
30970
30971             if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
30972             _lastMouse = d3_event;
30973             dispatch$1.call('move', this, d3_event, datum(d3_event));
30974           }
30975
30976           function pointercancel(d3_event) {
30977             if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
30978               if (!_downPointer.isCancelled) {
30979                 dispatch$1.call('downcancel', this);
30980               }
30981
30982               _downPointer = null;
30983             }
30984           }
30985
30986           function mouseenter() {
30987             _mouseLeave = false;
30988           }
30989
30990           function mouseleave() {
30991             _mouseLeave = true;
30992           }
30993
30994           function allowsVertex(d) {
30995             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
30996           } // related code
30997           // - `mode/drag_node.js`     `doMove()`
30998           // - `behavior/draw.js`      `click()`
30999           // - `behavior/draw_way.js`  `move()`
31000
31001
31002           function click(d3_event, loc) {
31003             var d = datum(d3_event);
31004             var target = d && d.properties && d.properties.entity;
31005             var mode = context.mode();
31006
31007             if (target && target.type === 'node' && allowsVertex(target)) {
31008               // Snap to a node
31009               dispatch$1.call('clickNode', this, target, d);
31010               return;
31011             } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
31012               // Snap to a way
31013               var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
31014
31015               if (choice) {
31016                 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
31017                 dispatch$1.call('clickWay', this, choice.loc, edge, d);
31018                 return;
31019               }
31020             } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
31021               var locLatLng = context.projection.invert(loc);
31022               dispatch$1.call('click', this, locLatLng, d);
31023             }
31024           } // treat a spacebar press like a click
31025
31026
31027           function space(d3_event) {
31028             d3_event.preventDefault();
31029             d3_event.stopPropagation();
31030             var currSpace = context.map().mouse();
31031
31032             if (_disableSpace && _lastSpace) {
31033               var dist = geoVecLength(_lastSpace, currSpace);
31034
31035               if (dist > _tolerance) {
31036                 _disableSpace = false;
31037               }
31038             }
31039
31040             if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
31041
31042             _lastSpace = currSpace;
31043             _disableSpace = true;
31044             select(window).on('keyup.space-block', function () {
31045               d3_event.preventDefault();
31046               d3_event.stopPropagation();
31047               _disableSpace = false;
31048               select(window).on('keyup.space-block', null);
31049             }); // get the current mouse position
31050
31051             var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
31052             context.projection(context.map().center());
31053             click(d3_event, loc);
31054           }
31055
31056           function backspace(d3_event) {
31057             d3_event.preventDefault();
31058             dispatch$1.call('undo');
31059           }
31060
31061           function del(d3_event) {
31062             d3_event.preventDefault();
31063             dispatch$1.call('cancel');
31064           }
31065
31066           function ret(d3_event) {
31067             d3_event.preventDefault();
31068             dispatch$1.call('finish');
31069           }
31070
31071           function behavior(selection) {
31072             context.install(_hover);
31073             context.install(_edit);
31074             _downPointer = null;
31075             keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
31076             selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
31077             select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
31078             select(document).call(keybinding);
31079             return behavior;
31080           }
31081
31082           behavior.off = function (selection) {
31083             context.ui().sidebar.hover.cancel();
31084             context.uninstall(_hover);
31085             context.uninstall(_edit);
31086             selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
31087             select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
31088
31089             select(document).call(keybinding.unbind);
31090           };
31091
31092           behavior.hover = function () {
31093             return _hover;
31094           };
31095
31096           return utilRebind(behavior, dispatch$1, 'on');
31097         }
31098
31099         function initRange(domain, range) {
31100           switch (arguments.length) {
31101             case 0:
31102               break;
31103
31104             case 1:
31105               this.range(domain);
31106               break;
31107
31108             default:
31109               this.range(range).domain(domain);
31110               break;
31111           }
31112
31113           return this;
31114         }
31115
31116         function constants(x) {
31117           return function () {
31118             return x;
31119           };
31120         }
31121
31122         function number$1(x) {
31123           return +x;
31124         }
31125
31126         var unit = [0, 1];
31127         function identity$3(x) {
31128           return x;
31129         }
31130
31131         function normalize$1(a, b) {
31132           return (b -= a = +a) ? function (x) {
31133             return (x - a) / b;
31134           } : constants(isNaN(b) ? NaN : 0.5);
31135         }
31136
31137         function clamper(a, b) {
31138           var t;
31139           if (a > b) t = a, a = b, b = t;
31140           return function (x) {
31141             return Math.max(a, Math.min(b, x));
31142           };
31143         } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
31144         // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
31145
31146
31147         function bimap(domain, range, interpolate) {
31148           var d0 = domain[0],
31149               d1 = domain[1],
31150               r0 = range[0],
31151               r1 = range[1];
31152           if (d1 < d0) d0 = normalize$1(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize$1(d0, d1), r0 = interpolate(r0, r1);
31153           return function (x) {
31154             return r0(d0(x));
31155           };
31156         }
31157
31158         function polymap(domain, range, interpolate) {
31159           var j = Math.min(domain.length, range.length) - 1,
31160               d = new Array(j),
31161               r = new Array(j),
31162               i = -1; // Reverse descending domains.
31163
31164           if (domain[j] < domain[0]) {
31165             domain = domain.slice().reverse();
31166             range = range.slice().reverse();
31167           }
31168
31169           while (++i < j) {
31170             d[i] = normalize$1(domain[i], domain[i + 1]);
31171             r[i] = interpolate(range[i], range[i + 1]);
31172           }
31173
31174           return function (x) {
31175             var i = bisectRight(domain, x, 1, j) - 1;
31176             return r[i](d[i](x));
31177           };
31178         }
31179
31180         function copy(source, target) {
31181           return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
31182         }
31183         function transformer$1() {
31184           var domain = unit,
31185               range = unit,
31186               interpolate$1 = interpolate,
31187               transform,
31188               untransform,
31189               unknown,
31190               clamp = identity$3,
31191               piecewise,
31192               output,
31193               input;
31194
31195           function rescale() {
31196             var n = Math.min(domain.length, range.length);
31197             if (clamp !== identity$3) clamp = clamper(domain[0], domain[n - 1]);
31198             piecewise = n > 2 ? polymap : bimap;
31199             output = input = null;
31200             return scale;
31201           }
31202
31203           function scale(x) {
31204             return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate$1)))(transform(clamp(x)));
31205           }
31206
31207           scale.invert = function (y) {
31208             return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
31209           };
31210
31211           scale.domain = function (_) {
31212             return arguments.length ? (domain = Array.from(_, number$1), rescale()) : domain.slice();
31213           };
31214
31215           scale.range = function (_) {
31216             return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
31217           };
31218
31219           scale.rangeRound = function (_) {
31220             return range = Array.from(_), interpolate$1 = interpolateRound, rescale();
31221           };
31222
31223           scale.clamp = function (_) {
31224             return arguments.length ? (clamp = _ ? true : identity$3, rescale()) : clamp !== identity$3;
31225           };
31226
31227           scale.interpolate = function (_) {
31228             return arguments.length ? (interpolate$1 = _, rescale()) : interpolate$1;
31229           };
31230
31231           scale.unknown = function (_) {
31232             return arguments.length ? (unknown = _, scale) : unknown;
31233           };
31234
31235           return function (t, u) {
31236             transform = t, untransform = u;
31237             return rescale();
31238           };
31239         }
31240         function continuous() {
31241           return transformer$1()(identity$3, identity$3);
31242         }
31243
31244         function formatDecimal (x) {
31245           return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
31246         } // Computes the decimal coefficient and exponent of the specified number x with
31247         // significant digits p, where x is positive and p is in [1, 21] or undefined.
31248         // For example, formatDecimalParts(1.23) returns ["123", 0].
31249
31250         function formatDecimalParts(x, p) {
31251           if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
31252
31253           var i,
31254               coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
31255           // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
31256
31257           return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
31258         }
31259
31260         function exponent (x) {
31261           return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
31262         }
31263
31264         function formatGroup (grouping, thousands) {
31265           return function (value, width) {
31266             var i = value.length,
31267                 t = [],
31268                 j = 0,
31269                 g = grouping[0],
31270                 length = 0;
31271
31272             while (i > 0 && g > 0) {
31273               if (length + g + 1 > width) g = Math.max(1, width - length);
31274               t.push(value.substring(i -= g, i + g));
31275               if ((length += g + 1) > width) break;
31276               g = grouping[j = (j + 1) % grouping.length];
31277             }
31278
31279             return t.reverse().join(thousands);
31280           };
31281         }
31282
31283         function formatNumerals (numerals) {
31284           return function (value) {
31285             return value.replace(/[0-9]/g, function (i) {
31286               return numerals[+i];
31287             });
31288           };
31289         }
31290
31291         // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
31292         var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
31293         function formatSpecifier(specifier) {
31294           if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
31295           var match;
31296           return new FormatSpecifier({
31297             fill: match[1],
31298             align: match[2],
31299             sign: match[3],
31300             symbol: match[4],
31301             zero: match[5],
31302             width: match[6],
31303             comma: match[7],
31304             precision: match[8] && match[8].slice(1),
31305             trim: match[9],
31306             type: match[10]
31307           });
31308         }
31309         formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
31310
31311         function FormatSpecifier(specifier) {
31312           this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
31313           this.align = specifier.align === undefined ? ">" : specifier.align + "";
31314           this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
31315           this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
31316           this.zero = !!specifier.zero;
31317           this.width = specifier.width === undefined ? undefined : +specifier.width;
31318           this.comma = !!specifier.comma;
31319           this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
31320           this.trim = !!specifier.trim;
31321           this.type = specifier.type === undefined ? "" : specifier.type + "";
31322         }
31323
31324         FormatSpecifier.prototype.toString = function () {
31325           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;
31326         };
31327
31328         // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
31329         function formatTrim (s) {
31330           out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
31331             switch (s[i]) {
31332               case ".":
31333                 i0 = i1 = i;
31334                 break;
31335
31336               case "0":
31337                 if (i0 === 0) i0 = i;
31338                 i1 = i;
31339                 break;
31340
31341               default:
31342                 if (!+s[i]) break out;
31343                 if (i0 > 0) i0 = 0;
31344                 break;
31345             }
31346           }
31347
31348           return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
31349         }
31350
31351         // `thisNumberValue` abstract operation
31352         // https://tc39.github.io/ecma262/#sec-thisnumbervalue
31353         var thisNumberValue = function (value) {
31354           if (typeof value != 'number' && classofRaw(value) != 'Number') {
31355             throw TypeError('Incorrect invocation');
31356           }
31357           return +value;
31358         };
31359
31360         // `String.prototype.repeat` method implementation
31361         // https://tc39.github.io/ecma262/#sec-string.prototype.repeat
31362         var stringRepeat = ''.repeat || function repeat(count) {
31363           var str = String(requireObjectCoercible(this));
31364           var result = '';
31365           var n = toInteger(count);
31366           if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
31367           for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
31368           return result;
31369         };
31370
31371         var nativeToFixed = 1.0.toFixed;
31372         var floor$6 = Math.floor;
31373
31374         var pow$2 = function (x, n, acc) {
31375           return n === 0 ? acc : n % 2 === 1 ? pow$2(x, n - 1, acc * x) : pow$2(x * x, n / 2, acc);
31376         };
31377
31378         var log$2 = function (x) {
31379           var n = 0;
31380           var x2 = x;
31381           while (x2 >= 4096) {
31382             n += 12;
31383             x2 /= 4096;
31384           }
31385           while (x2 >= 2) {
31386             n += 1;
31387             x2 /= 2;
31388           } return n;
31389         };
31390
31391         var FORCED$c = nativeToFixed && (
31392           0.00008.toFixed(3) !== '0.000' ||
31393           0.9.toFixed(0) !== '1' ||
31394           1.255.toFixed(2) !== '1.25' ||
31395           1000000000000000128.0.toFixed(0) !== '1000000000000000128'
31396         ) || !fails(function () {
31397           // V8 ~ Android 4.3-
31398           nativeToFixed.call({});
31399         });
31400
31401         // `Number.prototype.toFixed` method
31402         // https://tc39.github.io/ecma262/#sec-number.prototype.tofixed
31403         _export({ target: 'Number', proto: true, forced: FORCED$c }, {
31404           // eslint-disable-next-line max-statements
31405           toFixed: function toFixed(fractionDigits) {
31406             var number = thisNumberValue(this);
31407             var fractDigits = toInteger(fractionDigits);
31408             var data = [0, 0, 0, 0, 0, 0];
31409             var sign = '';
31410             var result = '0';
31411             var e, z, j, k;
31412
31413             var multiply = function (n, c) {
31414               var index = -1;
31415               var c2 = c;
31416               while (++index < 6) {
31417                 c2 += n * data[index];
31418                 data[index] = c2 % 1e7;
31419                 c2 = floor$6(c2 / 1e7);
31420               }
31421             };
31422
31423             var divide = function (n) {
31424               var index = 6;
31425               var c = 0;
31426               while (--index >= 0) {
31427                 c += data[index];
31428                 data[index] = floor$6(c / n);
31429                 c = (c % n) * 1e7;
31430               }
31431             };
31432
31433             var dataToString = function () {
31434               var index = 6;
31435               var s = '';
31436               while (--index >= 0) {
31437                 if (s !== '' || index === 0 || data[index] !== 0) {
31438                   var t = String(data[index]);
31439                   s = s === '' ? t : s + stringRepeat.call('0', 7 - t.length) + t;
31440                 }
31441               } return s;
31442             };
31443
31444             if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
31445             // eslint-disable-next-line no-self-compare
31446             if (number != number) return 'NaN';
31447             if (number <= -1e21 || number >= 1e21) return String(number);
31448             if (number < 0) {
31449               sign = '-';
31450               number = -number;
31451             }
31452             if (number > 1e-21) {
31453               e = log$2(number * pow$2(2, 69, 1)) - 69;
31454               z = e < 0 ? number * pow$2(2, -e, 1) : number / pow$2(2, e, 1);
31455               z *= 0x10000000000000;
31456               e = 52 - e;
31457               if (e > 0) {
31458                 multiply(0, z);
31459                 j = fractDigits;
31460                 while (j >= 7) {
31461                   multiply(1e7, 0);
31462                   j -= 7;
31463                 }
31464                 multiply(pow$2(10, j, 1), 0);
31465                 j = e - 1;
31466                 while (j >= 23) {
31467                   divide(1 << 23);
31468                   j -= 23;
31469                 }
31470                 divide(1 << j);
31471                 multiply(1, 1);
31472                 divide(2);
31473                 result = dataToString();
31474               } else {
31475                 multiply(0, z);
31476                 multiply(1 << -e, 0);
31477                 result = dataToString() + stringRepeat.call('0', fractDigits);
31478               }
31479             }
31480             if (fractDigits > 0) {
31481               k = result.length;
31482               result = sign + (k <= fractDigits
31483                 ? '0.' + stringRepeat.call('0', fractDigits - k) + result
31484                 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
31485             } else {
31486               result = sign + result;
31487             } return result;
31488           }
31489         });
31490
31491         var nativeToPrecision = 1.0.toPrecision;
31492
31493         var FORCED$d = fails(function () {
31494           // IE7-
31495           return nativeToPrecision.call(1, undefined) !== '1';
31496         }) || !fails(function () {
31497           // V8 ~ Android 4.3-
31498           nativeToPrecision.call({});
31499         });
31500
31501         // `Number.prototype.toPrecision` method
31502         // https://tc39.github.io/ecma262/#sec-number.prototype.toprecision
31503         _export({ target: 'Number', proto: true, forced: FORCED$d }, {
31504           toPrecision: function toPrecision(precision) {
31505             return precision === undefined
31506               ? nativeToPrecision.call(thisNumberValue(this))
31507               : nativeToPrecision.call(thisNumberValue(this), precision);
31508           }
31509         });
31510
31511         var prefixExponent;
31512         function formatPrefixAuto (x, p) {
31513           var d = formatDecimalParts(x, p);
31514           if (!d) return x + "";
31515           var coefficient = d[0],
31516               exponent = d[1],
31517               i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
31518               n = coefficient.length;
31519           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!
31520         }
31521
31522         function formatRounded (x, p) {
31523           var d = formatDecimalParts(x, p);
31524           if (!d) return x + "";
31525           var coefficient = d[0],
31526               exponent = d[1];
31527           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");
31528         }
31529
31530         var formatTypes = {
31531           "%": function _(x, p) {
31532             return (x * 100).toFixed(p);
31533           },
31534           "b": function b(x) {
31535             return Math.round(x).toString(2);
31536           },
31537           "c": function c(x) {
31538             return x + "";
31539           },
31540           "d": formatDecimal,
31541           "e": function e(x, p) {
31542             return x.toExponential(p);
31543           },
31544           "f": function f(x, p) {
31545             return x.toFixed(p);
31546           },
31547           "g": function g(x, p) {
31548             return x.toPrecision(p);
31549           },
31550           "o": function o(x) {
31551             return Math.round(x).toString(8);
31552           },
31553           "p": function p(x, _p) {
31554             return formatRounded(x * 100, _p);
31555           },
31556           "r": formatRounded,
31557           "s": formatPrefixAuto,
31558           "X": function X(x) {
31559             return Math.round(x).toString(16).toUpperCase();
31560           },
31561           "x": function x(_x) {
31562             return Math.round(_x).toString(16);
31563           }
31564         };
31565
31566         function identity$4 (x) {
31567           return x;
31568         }
31569
31570         var map = Array.prototype.map,
31571             prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
31572         function formatLocale (locale) {
31573           var group = locale.grouping === undefined || locale.thousands === undefined ? identity$4 : formatGroup(map.call(locale.grouping, Number), locale.thousands + ""),
31574               currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
31575               currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
31576               decimal = locale.decimal === undefined ? "." : locale.decimal + "",
31577               numerals = locale.numerals === undefined ? identity$4 : formatNumerals(map.call(locale.numerals, String)),
31578               percent = locale.percent === undefined ? "%" : locale.percent + "",
31579               minus = locale.minus === undefined ? "−" : locale.minus + "",
31580               nan = locale.nan === undefined ? "NaN" : locale.nan + "";
31581
31582           function newFormat(specifier) {
31583             specifier = formatSpecifier(specifier);
31584             var fill = specifier.fill,
31585                 align = specifier.align,
31586                 sign = specifier.sign,
31587                 symbol = specifier.symbol,
31588                 zero = specifier.zero,
31589                 width = specifier.width,
31590                 comma = specifier.comma,
31591                 precision = specifier.precision,
31592                 trim = specifier.trim,
31593                 type = specifier.type; // The "n" type is an alias for ",g".
31594
31595             if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
31596             else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
31597
31598             if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
31599             // For SI-prefix, the suffix is lazily computed.
31600
31601             var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
31602                 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
31603             // Is this an integer type?
31604             // Can this type generate exponential notation?
31605
31606             var formatType = formatTypes[type],
31607                 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
31608             // or clamp the specified precision to the supported range.
31609             // For significant precision, it must be in [1, 21].
31610             // For fixed precision, it must be in [0, 20].
31611
31612             precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
31613
31614             function format(value) {
31615               var valuePrefix = prefix,
31616                   valueSuffix = suffix,
31617                   i,
31618                   n,
31619                   c;
31620
31621               if (type === "c") {
31622                 valueSuffix = formatType(value) + valueSuffix;
31623                 value = "";
31624               } else {
31625                 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
31626
31627                 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
31628
31629                 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
31630
31631                 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
31632
31633                 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
31634
31635                 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
31636                 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
31637                 // grouped, and fractional or exponential “suffix” part that is not.
31638
31639                 if (maybeSuffix) {
31640                   i = -1, n = value.length;
31641
31642                   while (++i < n) {
31643                     if (c = value.charCodeAt(i), 48 > c || c > 57) {
31644                       valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
31645                       value = value.slice(0, i);
31646                       break;
31647                     }
31648                   }
31649                 }
31650               } // If the fill character is not "0", grouping is applied before padding.
31651
31652
31653               if (comma && !zero) value = group(value, Infinity); // Compute the padding.
31654
31655               var length = valuePrefix.length + value.length + valueSuffix.length,
31656                   padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
31657
31658               if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
31659
31660               switch (align) {
31661                 case "<":
31662                   value = valuePrefix + value + valueSuffix + padding;
31663                   break;
31664
31665                 case "=":
31666                   value = valuePrefix + padding + value + valueSuffix;
31667                   break;
31668
31669                 case "^":
31670                   value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
31671                   break;
31672
31673                 default:
31674                   value = padding + valuePrefix + value + valueSuffix;
31675                   break;
31676               }
31677
31678               return numerals(value);
31679             }
31680
31681             format.toString = function () {
31682               return specifier + "";
31683             };
31684
31685             return format;
31686           }
31687
31688           function formatPrefix(specifier, value) {
31689             var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
31690                 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
31691                 k = Math.pow(10, -e),
31692                 prefix = prefixes[8 + e / 3];
31693             return function (value) {
31694               return f(k * value) + prefix;
31695             };
31696           }
31697
31698           return {
31699             format: newFormat,
31700             formatPrefix: formatPrefix
31701           };
31702         }
31703
31704         var locale;
31705         var format;
31706         var formatPrefix;
31707         defaultLocale({
31708           thousands: ",",
31709           grouping: [3],
31710           currency: ["$", ""]
31711         });
31712         function defaultLocale(definition) {
31713           locale = formatLocale(definition);
31714           format = locale.format;
31715           formatPrefix = locale.formatPrefix;
31716           return locale;
31717         }
31718
31719         function precisionFixed (step) {
31720           return Math.max(0, -exponent(Math.abs(step)));
31721         }
31722
31723         function precisionPrefix (step, value) {
31724           return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
31725         }
31726
31727         function precisionRound (step, max) {
31728           step = Math.abs(step), max = Math.abs(max) - step;
31729           return Math.max(0, exponent(max) - exponent(step)) + 1;
31730         }
31731
31732         function tickFormat(start, stop, count, specifier) {
31733           var step = tickStep(start, stop, count),
31734               precision;
31735           specifier = formatSpecifier(specifier == null ? ",f" : specifier);
31736
31737           switch (specifier.type) {
31738             case "s":
31739               {
31740                 var value = Math.max(Math.abs(start), Math.abs(stop));
31741                 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
31742                 return formatPrefix(specifier, value);
31743               }
31744
31745             case "":
31746             case "e":
31747             case "g":
31748             case "p":
31749             case "r":
31750               {
31751                 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
31752                 break;
31753               }
31754
31755             case "f":
31756             case "%":
31757               {
31758                 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
31759                 break;
31760               }
31761           }
31762
31763           return format(specifier);
31764         }
31765
31766         function linearish(scale) {
31767           var domain = scale.domain;
31768
31769           scale.ticks = function (count) {
31770             var d = domain();
31771             return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
31772           };
31773
31774           scale.tickFormat = function (count, specifier) {
31775             var d = domain();
31776             return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
31777           };
31778
31779           scale.nice = function (count) {
31780             if (count == null) count = 10;
31781             var d = domain();
31782             var i0 = 0;
31783             var i1 = d.length - 1;
31784             var start = d[i0];
31785             var stop = d[i1];
31786             var prestep;
31787             var step;
31788             var maxIter = 10;
31789
31790             if (stop < start) {
31791               step = start, start = stop, stop = step;
31792               step = i0, i0 = i1, i1 = step;
31793             }
31794
31795             while (maxIter-- > 0) {
31796               step = tickIncrement(start, stop, count);
31797
31798               if (step === prestep) {
31799                 d[i0] = start;
31800                 d[i1] = stop;
31801                 return domain(d);
31802               } else if (step > 0) {
31803                 start = Math.floor(start / step) * step;
31804                 stop = Math.ceil(stop / step) * step;
31805               } else if (step < 0) {
31806                 start = Math.ceil(start * step) / step;
31807                 stop = Math.floor(stop * step) / step;
31808               } else {
31809                 break;
31810               }
31811
31812               prestep = step;
31813             }
31814
31815             return scale;
31816           };
31817
31818           return scale;
31819         }
31820         function linear$2() {
31821           var scale = continuous();
31822
31823           scale.copy = function () {
31824             return copy(scale, linear$2());
31825           };
31826
31827           initRange.apply(scale, arguments);
31828           return linearish(scale);
31829         }
31830
31831         var nativeExpm1 = Math.expm1;
31832         var exp$1 = Math.exp;
31833
31834         // `Math.expm1` method implementation
31835         // https://tc39.github.io/ecma262/#sec-math.expm1
31836         var mathExpm1 = (!nativeExpm1
31837           // Old FF bug
31838           || nativeExpm1(10) > 22025.465794806719 || nativeExpm1(10) < 22025.4657948067165168
31839           // Tor Browser bug
31840           || nativeExpm1(-2e-17) != -2e-17
31841         ) ? function expm1(x) {
31842           return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
31843         } : nativeExpm1;
31844
31845         function quantize() {
31846           var x0 = 0,
31847               x1 = 1,
31848               n = 1,
31849               domain = [0.5],
31850               range = [0, 1],
31851               unknown;
31852
31853           function scale(x) {
31854             return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
31855           }
31856
31857           function rescale() {
31858             var i = -1;
31859             domain = new Array(n);
31860
31861             while (++i < n) {
31862               domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31863             }
31864
31865             return scale;
31866           }
31867
31868           scale.domain = function (_) {
31869             var _ref, _ref2;
31870
31871             return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
31872           };
31873
31874           scale.range = function (_) {
31875             return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
31876           };
31877
31878           scale.invertExtent = function (y) {
31879             var i = range.indexOf(y);
31880             return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
31881           };
31882
31883           scale.unknown = function (_) {
31884             return arguments.length ? (unknown = _, scale) : scale;
31885           };
31886
31887           scale.thresholds = function () {
31888             return domain.slice();
31889           };
31890
31891           scale.copy = function () {
31892             return quantize().domain([x0, x1]).range(range).unknown(unknown);
31893           };
31894
31895           return initRange.apply(linearish(scale), arguments);
31896         }
31897
31898         // https://github.com/tc39/proposal-string-pad-start-end
31899
31900
31901
31902
31903         var ceil$1 = Math.ceil;
31904
31905         // `String.prototype.{ padStart, padEnd }` methods implementation
31906         var createMethod$6 = function (IS_END) {
31907           return function ($this, maxLength, fillString) {
31908             var S = String(requireObjectCoercible($this));
31909             var stringLength = S.length;
31910             var fillStr = fillString === undefined ? ' ' : String(fillString);
31911             var intMaxLength = toLength(maxLength);
31912             var fillLen, stringFiller;
31913             if (intMaxLength <= stringLength || fillStr == '') return S;
31914             fillLen = intMaxLength - stringLength;
31915             stringFiller = stringRepeat.call(fillStr, ceil$1(fillLen / fillStr.length));
31916             if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
31917             return IS_END ? S + stringFiller : stringFiller + S;
31918           };
31919         };
31920
31921         var stringPad = {
31922           // `String.prototype.padStart` method
31923           // https://tc39.github.io/ecma262/#sec-string.prototype.padstart
31924           start: createMethod$6(false),
31925           // `String.prototype.padEnd` method
31926           // https://tc39.github.io/ecma262/#sec-string.prototype.padend
31927           end: createMethod$6(true)
31928         };
31929
31930         var padStart = stringPad.start;
31931
31932         var abs$3 = Math.abs;
31933         var DatePrototype$1 = Date.prototype;
31934         var getTime$1 = DatePrototype$1.getTime;
31935         var nativeDateToISOString = DatePrototype$1.toISOString;
31936
31937         // `Date.prototype.toISOString` method implementation
31938         // https://tc39.github.io/ecma262/#sec-date.prototype.toisostring
31939         // PhantomJS / old WebKit fails here:
31940         var dateToIsoString = (fails(function () {
31941           return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
31942         }) || !fails(function () {
31943           nativeDateToISOString.call(new Date(NaN));
31944         })) ? function toISOString() {
31945           if (!isFinite(getTime$1.call(this))) throw RangeError('Invalid time value');
31946           var date = this;
31947           var year = date.getUTCFullYear();
31948           var milliseconds = date.getUTCMilliseconds();
31949           var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
31950           return sign + padStart(abs$3(year), sign ? 6 : 4, 0) +
31951             '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
31952             '-' + padStart(date.getUTCDate(), 2, 0) +
31953             'T' + padStart(date.getUTCHours(), 2, 0) +
31954             ':' + padStart(date.getUTCMinutes(), 2, 0) +
31955             ':' + padStart(date.getUTCSeconds(), 2, 0) +
31956             '.' + padStart(milliseconds, 3, 0) +
31957             'Z';
31958         } : nativeDateToISOString;
31959
31960         // `Date.prototype.toISOString` method
31961         // https://tc39.github.io/ecma262/#sec-date.prototype.toisostring
31962         // PhantomJS / old WebKit has a broken implementations
31963         _export({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== dateToIsoString }, {
31964           toISOString: dateToIsoString
31965         });
31966
31967         function behaviorBreathe() {
31968           var duration = 800;
31969           var steps = 4;
31970           var selector = '.selected.shadow, .selected .shadow';
31971
31972           var _selected = select(null);
31973
31974           var _classed = '';
31975           var _params = {};
31976           var _done = false;
31977
31978           var _timer;
31979
31980           function ratchetyInterpolator(a, b, steps, units) {
31981             a = parseFloat(a);
31982             b = parseFloat(b);
31983             var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
31984             return function (t) {
31985               return String(sample(t)) + (units || '');
31986             };
31987           }
31988
31989           function reset(selection) {
31990             selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
31991           }
31992
31993           function setAnimationParams(transition, fromTo) {
31994             var toFrom = fromTo === 'from' ? 'to' : 'from';
31995             transition.styleTween('stroke-opacity', function (d) {
31996               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
31997             }).styleTween('stroke-width', function (d) {
31998               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
31999             }).styleTween('fill-opacity', function (d) {
32000               return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
32001             }).styleTween('r', function (d) {
32002               return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
32003             });
32004           }
32005
32006           function calcAnimationParams(selection) {
32007             selection.call(reset).each(function (d) {
32008               var s = select(this);
32009               var tag = s.node().tagName;
32010               var p = {
32011                 'from': {},
32012                 'to': {}
32013               };
32014               var opacity;
32015               var width; // determine base opacity and width
32016
32017               if (tag === 'circle') {
32018                 opacity = parseFloat(s.style('fill-opacity') || 0.5);
32019                 width = parseFloat(s.style('r') || 15.5);
32020               } else {
32021                 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
32022                 width = parseFloat(s.style('stroke-width') || 10);
32023               } // calculate from/to interpolation params..
32024
32025
32026               p.tag = tag;
32027               p.from.opacity = opacity * 0.6;
32028               p.to.opacity = opacity * 1.25;
32029               p.from.width = width * 0.7;
32030               p.to.width = width * (tag === 'circle' ? 1.5 : 1);
32031               _params[d.id] = p;
32032             });
32033           }
32034
32035           function run(surface, fromTo) {
32036             var toFrom = fromTo === 'from' ? 'to' : 'from';
32037             var currSelected = surface.selectAll(selector);
32038             var currClassed = surface.attr('class');
32039
32040             if (_done || currSelected.empty()) {
32041               _selected.call(reset);
32042
32043               _selected = select(null);
32044               return;
32045             }
32046
32047             if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
32048               _selected.call(reset);
32049
32050               _classed = currClassed;
32051               _selected = currSelected.call(calcAnimationParams);
32052             }
32053
32054             var didCallNextRun = false;
32055
32056             _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
32057               // `end` event is called for each selected element, but we want
32058               // it to run only once
32059               if (!didCallNextRun) {
32060                 surface.call(run, toFrom);
32061                 didCallNextRun = true;
32062               } // if entity was deselected, remove breathe styling
32063
32064
32065               if (!select(this).classed('selected')) {
32066                 reset(select(this));
32067               }
32068             });
32069           }
32070
32071           function behavior(surface) {
32072             _done = false;
32073             _timer = timer(function () {
32074               // wait for elements to actually become selected
32075               if (surface.selectAll(selector).empty()) {
32076                 return false;
32077               }
32078
32079               surface.call(run, 'from');
32080
32081               _timer.stop();
32082
32083               return true;
32084             }, 20);
32085           }
32086
32087           behavior.restartIfNeeded = function (surface) {
32088             if (_selected.empty()) {
32089               surface.call(run, 'from');
32090
32091               if (_timer) {
32092                 _timer.stop();
32093               }
32094             }
32095           };
32096
32097           behavior.off = function () {
32098             _done = true;
32099
32100             if (_timer) {
32101               _timer.stop();
32102             }
32103
32104             _selected.interrupt().call(reset);
32105           };
32106
32107           return behavior;
32108         }
32109
32110         /* Creates a keybinding behavior for an operation */
32111         function behaviorOperation(context) {
32112           var _operation;
32113
32114           function keypress(d3_event) {
32115             // prevent operations during low zoom selection
32116             if (!context.map().withinEditableZoom()) return;
32117             if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
32118             d3_event.preventDefault();
32119
32120             var disabled = _operation.disabled();
32121
32122             if (disabled) {
32123               context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
32124             } else {
32125               context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
32126               if (_operation.point) _operation.point(null);
32127
32128               _operation();
32129             }
32130           }
32131
32132           function behavior() {
32133             if (_operation && _operation.available()) {
32134               context.keybinding().on(_operation.keys, keypress);
32135             }
32136
32137             return behavior;
32138           }
32139
32140           behavior.off = function () {
32141             context.keybinding().off(_operation.keys);
32142           };
32143
32144           behavior.which = function (_) {
32145             if (!arguments.length) return _operation;
32146             _operation = _;
32147             return behavior;
32148           };
32149
32150           return behavior;
32151         }
32152
32153         function operationCircularize(context, selectedIDs) {
32154           var _extent;
32155
32156           var _actions = selectedIDs.map(getAction).filter(Boolean);
32157
32158           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32159
32160           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32161             return n.loc;
32162           });
32163
32164           function getAction(entityID) {
32165             var entity = context.entity(entityID);
32166             if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
32167
32168             if (!_extent) {
32169               _extent = entity.extent(context.graph());
32170             } else {
32171               _extent = _extent.extend(entity.extent(context.graph()));
32172             }
32173
32174             return actionCircularize(entityID, context.projection);
32175           }
32176
32177           var operation = function operation() {
32178             if (!_actions.length) return;
32179
32180             var combinedAction = function combinedAction(graph, t) {
32181               _actions.forEach(function (action) {
32182                 if (!action.disabled(graph)) {
32183                   graph = action(graph, t);
32184                 }
32185               });
32186
32187               return graph;
32188             };
32189
32190             combinedAction.transitionable = true;
32191             context.perform(combinedAction, operation.annotation());
32192             window.setTimeout(function () {
32193               context.validator().validate();
32194             }, 300); // after any transition
32195           };
32196
32197           operation.available = function () {
32198             return _actions.length && selectedIDs.length === _actions.length;
32199           }; // don't cache this because the visible extent could change
32200
32201
32202           operation.disabled = function () {
32203             if (!_actions.length) return '';
32204
32205             var actionDisableds = _actions.map(function (action) {
32206               return action.disabled(context.graph());
32207             }).filter(Boolean);
32208
32209             if (actionDisableds.length === _actions.length) {
32210               // none of the features can be circularized
32211               if (new Set(actionDisableds).size > 1) {
32212                 return 'multiple_blockers';
32213               }
32214
32215               return actionDisableds[0];
32216             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
32217               return 'too_large';
32218             } else if (someMissing()) {
32219               return 'not_downloaded';
32220             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32221               return 'connected_to_hidden';
32222             }
32223
32224             return false;
32225
32226             function someMissing() {
32227               if (context.inIntro()) return false;
32228               var osm = context.connection();
32229
32230               if (osm) {
32231                 var missing = _coords.filter(function (loc) {
32232                   return !osm.isDataLoaded(loc);
32233                 });
32234
32235                 if (missing.length) {
32236                   missing.forEach(function (loc) {
32237                     context.loadTileAtLoc(loc);
32238                   });
32239                   return true;
32240                 }
32241               }
32242
32243               return false;
32244             }
32245           };
32246
32247           operation.tooltip = function () {
32248             var disable = operation.disabled();
32249             return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
32250           };
32251
32252           operation.annotation = function () {
32253             return _t('operations.circularize.annotation.feature', {
32254               n: _actions.length
32255             });
32256           };
32257
32258           operation.id = 'circularize';
32259           operation.keys = [_t('operations.circularize.key')];
32260           operation.title = _t('operations.circularize.title');
32261           operation.behavior = behaviorOperation(context).which(operation);
32262           return operation;
32263         }
32264
32265         // For example, ⌘Z -> Ctrl+Z
32266
32267         var uiCmd = function uiCmd(code) {
32268           var detected = utilDetect();
32269
32270           if (detected.os === 'mac') {
32271             return code;
32272           }
32273
32274           if (detected.os === 'win') {
32275             if (code === '⌘⇧Z') return 'Ctrl+Y';
32276           }
32277
32278           var result = '',
32279               replacements = {
32280             '⌘': 'Ctrl',
32281             '⇧': 'Shift',
32282             '⌥': 'Alt',
32283             '⌫': 'Backspace',
32284             '⌦': 'Delete'
32285           };
32286
32287           for (var i = 0; i < code.length; i++) {
32288             if (code[i] in replacements) {
32289               result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
32290             } else {
32291               result += code[i];
32292             }
32293           }
32294
32295           return result;
32296         }; // return a display-focused string for a given keyboard code
32297
32298         uiCmd.display = function (code) {
32299           if (code.length !== 1) return code;
32300           var detected = utilDetect();
32301           var mac = detected.os === 'mac';
32302           var replacements = {
32303             '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
32304             '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
32305             '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
32306             '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
32307             '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
32308             '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
32309             '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
32310             '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
32311             '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
32312             '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
32313             '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
32314             '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
32315             '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
32316           };
32317           return replacements[code] || code;
32318         };
32319
32320         function operationDelete(context, selectedIDs) {
32321           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32322           var action = actionDeleteMultiple(selectedIDs);
32323           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32324           var coords = nodes.map(function (n) {
32325             return n.loc;
32326           });
32327           var extent = utilTotalExtent(selectedIDs, context.graph());
32328
32329           var operation = function operation() {
32330             var nextSelectedID;
32331             var nextSelectedLoc;
32332
32333             if (selectedIDs.length === 1) {
32334               var id = selectedIDs[0];
32335               var entity = context.entity(id);
32336               var geometry = entity.geometry(context.graph());
32337               var parents = context.graph().parentWays(entity);
32338               var parent = parents[0]; // Select the next closest node in the way.
32339
32340               if (geometry === 'vertex') {
32341                 var nodes = parent.nodes;
32342                 var i = nodes.indexOf(id);
32343
32344                 if (i === 0) {
32345                   i++;
32346                 } else if (i === nodes.length - 1) {
32347                   i--;
32348                 } else {
32349                   var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
32350                   var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
32351                   i = a < b ? i - 1 : i + 1;
32352                 }
32353
32354                 nextSelectedID = nodes[i];
32355                 nextSelectedLoc = context.entity(nextSelectedID).loc;
32356               }
32357             }
32358
32359             context.perform(action, operation.annotation());
32360             context.validator().validate();
32361
32362             if (nextSelectedID && nextSelectedLoc) {
32363               if (context.hasEntity(nextSelectedID)) {
32364                 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
32365               } else {
32366                 context.map().centerEase(nextSelectedLoc);
32367                 context.enter(modeBrowse(context));
32368               }
32369             } else {
32370               context.enter(modeBrowse(context));
32371             }
32372           };
32373
32374           operation.available = function () {
32375             return true;
32376           };
32377
32378           operation.disabled = function () {
32379             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32380               return 'too_large';
32381             } else if (someMissing()) {
32382               return 'not_downloaded';
32383             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32384               return 'connected_to_hidden';
32385             } else if (selectedIDs.some(protectedMember)) {
32386               return 'part_of_relation';
32387             } else if (selectedIDs.some(incompleteRelation)) {
32388               return 'incomplete_relation';
32389             } else if (selectedIDs.some(hasWikidataTag)) {
32390               return 'has_wikidata_tag';
32391             }
32392
32393             return false;
32394
32395             function someMissing() {
32396               if (context.inIntro()) return false;
32397               var osm = context.connection();
32398
32399               if (osm) {
32400                 var missing = coords.filter(function (loc) {
32401                   return !osm.isDataLoaded(loc);
32402                 });
32403
32404                 if (missing.length) {
32405                   missing.forEach(function (loc) {
32406                     context.loadTileAtLoc(loc);
32407                   });
32408                   return true;
32409                 }
32410               }
32411
32412               return false;
32413             }
32414
32415             function hasWikidataTag(id) {
32416               var entity = context.entity(id);
32417               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
32418             }
32419
32420             function incompleteRelation(id) {
32421               var entity = context.entity(id);
32422               return entity.type === 'relation' && !entity.isComplete(context.graph());
32423             }
32424
32425             function protectedMember(id) {
32426               var entity = context.entity(id);
32427               if (entity.type !== 'way') return false;
32428               var parents = context.graph().parentRelations(entity);
32429
32430               for (var i = 0; i < parents.length; i++) {
32431                 var parent = parents[i];
32432                 var type = parent.tags.type;
32433                 var role = parent.memberById(id).role || 'outer';
32434
32435                 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
32436                   return true;
32437                 }
32438               }
32439
32440               return false;
32441             }
32442           };
32443
32444           operation.tooltip = function () {
32445             var disable = operation.disabled();
32446             return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
32447           };
32448
32449           operation.annotation = function () {
32450             return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
32451               n: selectedIDs.length
32452             });
32453           };
32454
32455           operation.id = 'delete';
32456           operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
32457           operation.title = _t('operations.delete.title');
32458           operation.behavior = behaviorOperation(context).which(operation);
32459           return operation;
32460         }
32461
32462         function operationOrthogonalize(context, selectedIDs) {
32463           var _extent;
32464
32465           var _type;
32466
32467           var _actions = selectedIDs.map(chooseAction).filter(Boolean);
32468
32469           var _amount = _actions.length === 1 ? 'single' : 'multiple';
32470
32471           var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
32472             return n.loc;
32473           });
32474
32475           function chooseAction(entityID) {
32476             var entity = context.entity(entityID);
32477             var geometry = entity.geometry(context.graph());
32478
32479             if (!_extent) {
32480               _extent = entity.extent(context.graph());
32481             } else {
32482               _extent = _extent.extend(entity.extent(context.graph()));
32483             } // square a line/area
32484
32485
32486             if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
32487               if (_type && _type !== 'feature') return null;
32488               _type = 'feature';
32489               return actionOrthogonalize(entityID, context.projection); // square a single vertex
32490             } else if (geometry === 'vertex') {
32491               if (_type && _type !== 'corner') return null;
32492               _type = 'corner';
32493               var graph = context.graph();
32494               var parents = graph.parentWays(entity);
32495
32496               if (parents.length === 1) {
32497                 var way = parents[0];
32498
32499                 if (way.nodes.indexOf(entityID) !== -1) {
32500                   return actionOrthogonalize(way.id, context.projection, entityID);
32501                 }
32502               }
32503             }
32504
32505             return null;
32506           }
32507
32508           var operation = function operation() {
32509             if (!_actions.length) return;
32510
32511             var combinedAction = function combinedAction(graph, t) {
32512               _actions.forEach(function (action) {
32513                 if (!action.disabled(graph)) {
32514                   graph = action(graph, t);
32515                 }
32516               });
32517
32518               return graph;
32519             };
32520
32521             combinedAction.transitionable = true;
32522             context.perform(combinedAction, operation.annotation());
32523             window.setTimeout(function () {
32524               context.validator().validate();
32525             }, 300); // after any transition
32526           };
32527
32528           operation.available = function () {
32529             return _actions.length && selectedIDs.length === _actions.length;
32530           }; // don't cache this because the visible extent could change
32531
32532
32533           operation.disabled = function () {
32534             if (!_actions.length) return '';
32535
32536             var actionDisableds = _actions.map(function (action) {
32537               return action.disabled(context.graph());
32538             }).filter(Boolean);
32539
32540             if (actionDisableds.length === _actions.length) {
32541               // none of the features can be squared
32542               if (new Set(actionDisableds).size > 1) {
32543                 return 'multiple_blockers';
32544               }
32545
32546               return actionDisableds[0];
32547             } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
32548               return 'too_large';
32549             } else if (someMissing()) {
32550               return 'not_downloaded';
32551             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32552               return 'connected_to_hidden';
32553             }
32554
32555             return false;
32556
32557             function someMissing() {
32558               if (context.inIntro()) return false;
32559               var osm = context.connection();
32560
32561               if (osm) {
32562                 var missing = _coords.filter(function (loc) {
32563                   return !osm.isDataLoaded(loc);
32564                 });
32565
32566                 if (missing.length) {
32567                   missing.forEach(function (loc) {
32568                     context.loadTileAtLoc(loc);
32569                   });
32570                   return true;
32571                 }
32572               }
32573
32574               return false;
32575             }
32576           };
32577
32578           operation.tooltip = function () {
32579             var disable = operation.disabled();
32580             return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
32581           };
32582
32583           operation.annotation = function () {
32584             return _t('operations.orthogonalize.annotation.' + _type, {
32585               n: _actions.length
32586             });
32587           };
32588
32589           operation.id = 'orthogonalize';
32590           operation.keys = [_t('operations.orthogonalize.key')];
32591           operation.title = _t('operations.orthogonalize.title');
32592           operation.behavior = behaviorOperation(context).which(operation);
32593           return operation;
32594         }
32595
32596         function operationReflectShort(context, selectedIDs) {
32597           return operationReflect(context, selectedIDs, 'short');
32598         }
32599         function operationReflectLong(context, selectedIDs) {
32600           return operationReflect(context, selectedIDs, 'long');
32601         }
32602         function operationReflect(context, selectedIDs, axis) {
32603           axis = axis || 'long';
32604           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32605           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32606           var coords = nodes.map(function (n) {
32607             return n.loc;
32608           });
32609           var extent = utilTotalExtent(selectedIDs, context.graph());
32610
32611           var operation = function operation() {
32612             var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
32613             context.perform(action, operation.annotation());
32614             window.setTimeout(function () {
32615               context.validator().validate();
32616             }, 300); // after any transition
32617           };
32618
32619           operation.available = function () {
32620             return nodes.length >= 3;
32621           }; // don't cache this because the visible extent could change
32622
32623
32624           operation.disabled = function () {
32625             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32626               return 'too_large';
32627             } else if (someMissing()) {
32628               return 'not_downloaded';
32629             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32630               return 'connected_to_hidden';
32631             } else if (selectedIDs.some(incompleteRelation)) {
32632               return 'incomplete_relation';
32633             }
32634
32635             return false;
32636
32637             function someMissing() {
32638               if (context.inIntro()) return false;
32639               var osm = context.connection();
32640
32641               if (osm) {
32642                 var missing = coords.filter(function (loc) {
32643                   return !osm.isDataLoaded(loc);
32644                 });
32645
32646                 if (missing.length) {
32647                   missing.forEach(function (loc) {
32648                     context.loadTileAtLoc(loc);
32649                   });
32650                   return true;
32651                 }
32652               }
32653
32654               return false;
32655             }
32656
32657             function incompleteRelation(id) {
32658               var entity = context.entity(id);
32659               return entity.type === 'relation' && !entity.isComplete(context.graph());
32660             }
32661           };
32662
32663           operation.tooltip = function () {
32664             var disable = operation.disabled();
32665             return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
32666           };
32667
32668           operation.annotation = function () {
32669             return _t('operations.reflect.annotation.' + axis + '.feature', {
32670               n: selectedIDs.length
32671             });
32672           };
32673
32674           operation.id = 'reflect-' + axis;
32675           operation.keys = [_t('operations.reflect.key.' + axis)];
32676           operation.title = _t('operations.reflect.title.' + axis);
32677           operation.behavior = behaviorOperation(context).which(operation);
32678           return operation;
32679         }
32680
32681         function operationMove(context, selectedIDs) {
32682           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32683           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32684           var coords = nodes.map(function (n) {
32685             return n.loc;
32686           });
32687           var extent = utilTotalExtent(selectedIDs, context.graph());
32688
32689           var operation = function operation() {
32690             context.enter(modeMove(context, selectedIDs));
32691           };
32692
32693           operation.available = function () {
32694             return selectedIDs.length > 1 || context.entity(selectedIDs[0]).type !== 'node';
32695           };
32696
32697           operation.disabled = function () {
32698             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32699               return 'too_large';
32700             } else if (someMissing()) {
32701               return 'not_downloaded';
32702             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32703               return 'connected_to_hidden';
32704             } else if (selectedIDs.some(incompleteRelation)) {
32705               return 'incomplete_relation';
32706             }
32707
32708             return false;
32709
32710             function someMissing() {
32711               if (context.inIntro()) return false;
32712               var osm = context.connection();
32713
32714               if (osm) {
32715                 var missing = coords.filter(function (loc) {
32716                   return !osm.isDataLoaded(loc);
32717                 });
32718
32719                 if (missing.length) {
32720                   missing.forEach(function (loc) {
32721                     context.loadTileAtLoc(loc);
32722                   });
32723                   return true;
32724                 }
32725               }
32726
32727               return false;
32728             }
32729
32730             function incompleteRelation(id) {
32731               var entity = context.entity(id);
32732               return entity.type === 'relation' && !entity.isComplete(context.graph());
32733             }
32734           };
32735
32736           operation.tooltip = function () {
32737             var disable = operation.disabled();
32738             return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
32739           };
32740
32741           operation.annotation = function () {
32742             return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
32743               n: selectedIDs.length
32744             });
32745           };
32746
32747           operation.id = 'move';
32748           operation.keys = [_t('operations.move.key')];
32749           operation.title = _t('operations.move.title');
32750           operation.behavior = behaviorOperation(context).which(operation);
32751           operation.mouseOnly = true;
32752           return operation;
32753         }
32754
32755         function modeRotate(context, entityIDs) {
32756           var mode = {
32757             id: 'rotate',
32758             button: 'browse'
32759           };
32760           var keybinding = utilKeybinding('rotate');
32761           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];
32762           var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
32763             n: entityIDs.length
32764           });
32765
32766           var _prevGraph;
32767
32768           var _prevAngle;
32769
32770           var _prevTransform;
32771
32772           var _pivot;
32773
32774           function doRotate() {
32775             var fn;
32776
32777             if (context.graph() !== _prevGraph) {
32778               fn = context.perform;
32779             } else {
32780               fn = context.replace;
32781             } // projection changed, recalculate _pivot
32782
32783
32784             var projection = context.projection;
32785             var currTransform = projection.transform();
32786
32787             if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
32788               var nodes = utilGetAllNodes(entityIDs, context.graph());
32789               var points = nodes.map(function (n) {
32790                 return projection(n.loc);
32791               });
32792               _pivot = getPivot(points);
32793               _prevAngle = undefined;
32794             }
32795
32796             var currMouse = context.map().mouse();
32797             var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
32798             if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
32799             var delta = currAngle - _prevAngle;
32800             fn(actionRotate(entityIDs, _pivot, delta, projection));
32801             _prevTransform = currTransform;
32802             _prevAngle = currAngle;
32803             _prevGraph = context.graph();
32804           }
32805
32806           function getPivot(points) {
32807             var _pivot;
32808
32809             if (points.length === 1) {
32810               _pivot = points[0];
32811             } else if (points.length === 2) {
32812               _pivot = geoVecInterp(points[0], points[1], 0.5);
32813             } else {
32814               var polygonHull = d3_polygonHull(points);
32815
32816               if (polygonHull.length === 2) {
32817                 _pivot = geoVecInterp(points[0], points[1], 0.5);
32818               } else {
32819                 _pivot = d3_polygonCentroid(d3_polygonHull(points));
32820               }
32821             }
32822
32823             return _pivot;
32824           }
32825
32826           function finish(d3_event) {
32827             d3_event.stopPropagation();
32828             context.replace(actionNoop(), annotation);
32829             context.enter(modeSelect(context, entityIDs));
32830           }
32831
32832           function cancel() {
32833             context.pop();
32834             context.enter(modeSelect(context, entityIDs));
32835           }
32836
32837           function undone() {
32838             context.enter(modeBrowse(context));
32839           }
32840
32841           mode.enter = function () {
32842             context.features().forceVisible(entityIDs);
32843             behaviors.forEach(context.install);
32844             context.surface().on('mousemove.rotate', doRotate).on('click.rotate', finish);
32845             context.history().on('undone.rotate', undone);
32846             keybinding.on('⎋', cancel).on('↩', finish);
32847             select(document).call(keybinding);
32848           };
32849
32850           mode.exit = function () {
32851             behaviors.forEach(context.uninstall);
32852             context.surface().on('mousemove.rotate', null).on('click.rotate', null);
32853             context.history().on('undone.rotate', null);
32854             select(document).call(keybinding.unbind);
32855             context.features().forceVisible([]);
32856           };
32857
32858           mode.selectedIDs = function () {
32859             if (!arguments.length) return entityIDs; // no assign
32860
32861             return mode;
32862           };
32863
32864           return mode;
32865         }
32866
32867         function operationRotate(context, selectedIDs) {
32868           var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
32869           var nodes = utilGetAllNodes(selectedIDs, context.graph());
32870           var coords = nodes.map(function (n) {
32871             return n.loc;
32872           });
32873           var extent = utilTotalExtent(selectedIDs, context.graph());
32874
32875           var operation = function operation() {
32876             context.enter(modeRotate(context, selectedIDs));
32877           };
32878
32879           operation.available = function () {
32880             return nodes.length >= 2;
32881           };
32882
32883           operation.disabled = function () {
32884             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
32885               return 'too_large';
32886             } else if (someMissing()) {
32887               return 'not_downloaded';
32888             } else if (selectedIDs.some(context.hasHiddenConnections)) {
32889               return 'connected_to_hidden';
32890             } else if (selectedIDs.some(incompleteRelation)) {
32891               return 'incomplete_relation';
32892             }
32893
32894             return false;
32895
32896             function someMissing() {
32897               if (context.inIntro()) return false;
32898               var osm = context.connection();
32899
32900               if (osm) {
32901                 var missing = coords.filter(function (loc) {
32902                   return !osm.isDataLoaded(loc);
32903                 });
32904
32905                 if (missing.length) {
32906                   missing.forEach(function (loc) {
32907                     context.loadTileAtLoc(loc);
32908                   });
32909                   return true;
32910                 }
32911               }
32912
32913               return false;
32914             }
32915
32916             function incompleteRelation(id) {
32917               var entity = context.entity(id);
32918               return entity.type === 'relation' && !entity.isComplete(context.graph());
32919             }
32920           };
32921
32922           operation.tooltip = function () {
32923             var disable = operation.disabled();
32924             return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
32925           };
32926
32927           operation.annotation = function () {
32928             return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
32929               n: selectedIDs.length
32930             });
32931           };
32932
32933           operation.id = 'rotate';
32934           operation.keys = [_t('operations.rotate.key')];
32935           operation.title = _t('operations.rotate.title');
32936           operation.behavior = behaviorOperation(context).which(operation);
32937           operation.mouseOnly = true;
32938           return operation;
32939         }
32940
32941         function modeMove(context, entityIDs, baseGraph) {
32942           var mode = {
32943             id: 'move',
32944             button: 'browse'
32945           };
32946           var keybinding = utilKeybinding('move');
32947           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];
32948           var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
32949             n: entityIDs.length
32950           });
32951
32952           var _prevGraph;
32953
32954           var _cache;
32955
32956           var _origin;
32957
32958           var _nudgeInterval;
32959
32960           function doMove(nudge) {
32961             nudge = nudge || [0, 0];
32962             var fn;
32963
32964             if (_prevGraph !== context.graph()) {
32965               _cache = {};
32966               _origin = context.map().mouseCoordinates();
32967               fn = context.perform;
32968             } else {
32969               fn = context.overwrite;
32970             }
32971
32972             var currMouse = context.map().mouse();
32973             var origMouse = context.projection(_origin);
32974             var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
32975             fn(actionMove(entityIDs, delta, context.projection, _cache));
32976             _prevGraph = context.graph();
32977           }
32978
32979           function startNudge(nudge) {
32980             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
32981             _nudgeInterval = window.setInterval(function () {
32982               context.map().pan(nudge);
32983               doMove(nudge);
32984             }, 50);
32985           }
32986
32987           function stopNudge() {
32988             if (_nudgeInterval) {
32989               window.clearInterval(_nudgeInterval);
32990               _nudgeInterval = null;
32991             }
32992           }
32993
32994           function move() {
32995             doMove();
32996             var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
32997
32998             if (nudge) {
32999               startNudge(nudge);
33000             } else {
33001               stopNudge();
33002             }
33003           }
33004
33005           function finish(d3_event) {
33006             d3_event.stopPropagation();
33007             context.replace(actionNoop(), annotation);
33008             context.enter(modeSelect(context, entityIDs));
33009             stopNudge();
33010           }
33011
33012           function cancel() {
33013             if (baseGraph) {
33014               while (context.graph() !== baseGraph) {
33015                 context.pop();
33016               }
33017
33018               context.enter(modeBrowse(context));
33019             } else {
33020               context.pop();
33021               context.enter(modeSelect(context, entityIDs));
33022             }
33023
33024             stopNudge();
33025           }
33026
33027           function undone() {
33028             context.enter(modeBrowse(context));
33029           }
33030
33031           mode.enter = function () {
33032             _origin = context.map().mouseCoordinates();
33033             _prevGraph = null;
33034             _cache = {};
33035             context.features().forceVisible(entityIDs);
33036             behaviors.forEach(context.install);
33037             context.surface().on('mousemove.move', move).on('click.move', finish);
33038             context.history().on('undone.move', undone);
33039             keybinding.on('⎋', cancel).on('↩', finish);
33040             select(document).call(keybinding);
33041           };
33042
33043           mode.exit = function () {
33044             stopNudge();
33045             behaviors.forEach(function (behavior) {
33046               context.uninstall(behavior);
33047             });
33048             context.surface().on('mousemove.move', null).on('click.move', null);
33049             context.history().on('undone.move', null);
33050             select(document).call(keybinding.unbind);
33051             context.features().forceVisible([]);
33052           };
33053
33054           mode.selectedIDs = function () {
33055             if (!arguments.length) return entityIDs; // no assign
33056
33057             return mode;
33058           };
33059
33060           return mode;
33061         }
33062
33063         function behaviorPaste(context) {
33064           function doPaste(d3_event) {
33065             // prevent paste during low zoom selection
33066             if (!context.map().withinEditableZoom()) return;
33067             d3_event.preventDefault();
33068             var baseGraph = context.graph();
33069             var mouse = context.map().mouse();
33070             var projection = context.projection;
33071             var viewport = geoExtent(projection.clipExtent()).polygon();
33072             if (!geoPointInPolygon(mouse, viewport)) return;
33073             var oldIDs = context.copyIDs();
33074             if (!oldIDs.length) return;
33075             var extent = geoExtent();
33076             var oldGraph = context.copyGraph();
33077             var newIDs = [];
33078             var action = actionCopyEntities(oldIDs, oldGraph);
33079             context.perform(action);
33080             var copies = action.copies();
33081             var originals = new Set();
33082             Object.values(copies).forEach(function (entity) {
33083               originals.add(entity.id);
33084             });
33085
33086             for (var id in copies) {
33087               var oldEntity = oldGraph.entity(id);
33088               var newEntity = copies[id];
33089
33090               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
33091
33092
33093               var parents = context.graph().parentWays(newEntity);
33094               var parentCopied = parents.some(function (parent) {
33095                 return originals.has(parent.id);
33096               });
33097
33098               if (!parentCopied) {
33099                 newIDs.push(newEntity.id);
33100               }
33101             } // Put pasted objects where mouse pointer is..
33102
33103
33104             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
33105             var delta = geoVecSubtract(mouse, copyPoint);
33106             context.perform(actionMove(newIDs, delta, projection));
33107             context.enter(modeMove(context, newIDs, baseGraph));
33108           }
33109
33110           function behavior() {
33111             context.keybinding().on(uiCmd('⌘V'), doPaste);
33112             return behavior;
33113           }
33114
33115           behavior.off = function () {
33116             context.keybinding().off(uiCmd('⌘V'));
33117           };
33118
33119           return behavior;
33120         }
33121
33122         // `String.prototype.repeat` method
33123         // https://tc39.github.io/ecma262/#sec-string.prototype.repeat
33124         _export({ target: 'String', proto: true }, {
33125           repeat: stringRepeat
33126         });
33127
33128         /*
33129             `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
33130
33131             * The `origin` function is expected to return an [x, y] tuple rather than an
33132               {x, y} object.
33133             * The events are `start`, `move`, and `end`.
33134               (https://github.com/mbostock/d3/issues/563)
33135             * The `start` event is not dispatched until the first cursor movement occurs.
33136               (https://github.com/mbostock/d3/pull/368)
33137             * The `move` event has a `point` and `delta` [x, y] tuple properties rather
33138               than `x`, `y`, `dx`, and `dy` properties.
33139             * The `end` event is not dispatched if no movement occurs.
33140             * An `off` function is available that unbinds the drag's internal event handlers.
33141          */
33142
33143         function behaviorDrag() {
33144           var dispatch$1 = dispatch('start', 'move', 'end'); // see also behaviorSelect
33145
33146           var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
33147
33148           var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
33149
33150           var _origin = null;
33151           var _selector = '';
33152
33153           var _targetNode;
33154
33155           var _targetEntity;
33156
33157           var _surface;
33158
33159           var _pointerId; // use pointer events on supported platforms; fallback to mouse events
33160
33161
33162           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
33163
33164           var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
33165
33166           var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
33167             var selection$1 = selection();
33168             var select = selection$1.style(d3_event_userSelectProperty);
33169             selection$1.style(d3_event_userSelectProperty, 'none');
33170             return function () {
33171               selection$1.style(d3_event_userSelectProperty, select);
33172             };
33173           };
33174
33175           function pointerdown(d3_event) {
33176             if (_pointerId) return;
33177             _pointerId = d3_event.pointerId || 'mouse';
33178             _targetNode = this; // only force reflow once per drag
33179
33180             var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
33181             var offset;
33182             var startOrigin = pointerLocGetter(d3_event);
33183             var started = false;
33184             var selectEnable = d3_event_userSelectSuppress();
33185             select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
33186
33187             if (_origin) {
33188               offset = _origin.call(_targetNode, _targetEntity);
33189               offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
33190             } else {
33191               offset = [0, 0];
33192             }
33193
33194             d3_event.stopPropagation();
33195
33196             function pointermove(d3_event) {
33197               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33198               var p = pointerLocGetter(d3_event);
33199
33200               if (!started) {
33201                 var dist = geoVecLength(startOrigin, p);
33202                 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
33203
33204                 if (dist < tolerance) return;
33205                 started = true;
33206                 dispatch$1.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
33207                 // a midpoint will convert the target to a node.
33208               } else {
33209                 startOrigin = p;
33210                 d3_event.stopPropagation();
33211                 d3_event.preventDefault();
33212                 var dx = p[0] - startOrigin[0];
33213                 var dy = p[1] - startOrigin[1];
33214                 dispatch$1.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
33215               }
33216             }
33217
33218             function pointerup(d3_event) {
33219               if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
33220               _pointerId = null;
33221
33222               if (started) {
33223                 dispatch$1.call('end', this, d3_event, _targetEntity);
33224                 d3_event.preventDefault();
33225               }
33226
33227               select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33228               selectEnable();
33229             }
33230           }
33231
33232           function behavior(selection) {
33233             var matchesSelector = utilPrefixDOMProperty('matchesSelector');
33234             var delegate = pointerdown;
33235
33236             if (_selector) {
33237               delegate = function delegate(d3_event) {
33238                 var root = this;
33239                 var target = d3_event.target;
33240
33241                 for (; target && target !== root; target = target.parentNode) {
33242                   var datum = target.__data__;
33243                   _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
33244
33245                   if (_targetEntity && target[matchesSelector](_selector)) {
33246                     return pointerdown.call(target, d3_event);
33247                   }
33248                 }
33249               };
33250             }
33251
33252             selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
33253           }
33254
33255           behavior.off = function (selection) {
33256             selection.on(_pointerPrefix + 'down.drag' + _selector, null);
33257           };
33258
33259           behavior.selector = function (_) {
33260             if (!arguments.length) return _selector;
33261             _selector = _;
33262             return behavior;
33263           };
33264
33265           behavior.origin = function (_) {
33266             if (!arguments.length) return _origin;
33267             _origin = _;
33268             return behavior;
33269           };
33270
33271           behavior.cancel = function () {
33272             select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
33273             return behavior;
33274           };
33275
33276           behavior.targetNode = function (_) {
33277             if (!arguments.length) return _targetNode;
33278             _targetNode = _;
33279             return behavior;
33280           };
33281
33282           behavior.targetEntity = function (_) {
33283             if (!arguments.length) return _targetEntity;
33284             _targetEntity = _;
33285             return behavior;
33286           };
33287
33288           behavior.surface = function (_) {
33289             if (!arguments.length) return _surface;
33290             _surface = _;
33291             return behavior;
33292           };
33293
33294           return utilRebind(behavior, dispatch$1, 'on');
33295         }
33296
33297         function modeDragNode(context) {
33298           var mode = {
33299             id: 'drag-node',
33300             button: 'browse'
33301           };
33302           var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
33303           var edit = behaviorEdit(context);
33304
33305           var _nudgeInterval;
33306
33307           var _restoreSelectedIDs = [];
33308           var _wasMidpoint = false;
33309           var _isCancelled = false;
33310
33311           var _activeEntity;
33312
33313           var _startLoc;
33314
33315           var _lastLoc;
33316
33317           function startNudge(d3_event, entity, nudge) {
33318             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
33319             _nudgeInterval = window.setInterval(function () {
33320               context.map().pan(nudge);
33321               doMove(d3_event, entity, nudge);
33322             }, 50);
33323           }
33324
33325           function stopNudge() {
33326             if (_nudgeInterval) {
33327               window.clearInterval(_nudgeInterval);
33328               _nudgeInterval = null;
33329             }
33330           }
33331
33332           function moveAnnotation(entity) {
33333             return _t('operations.move.annotation.' + entity.geometry(context.graph()));
33334           }
33335
33336           function connectAnnotation(nodeEntity, targetEntity) {
33337             var nodeGeometry = nodeEntity.geometry(context.graph());
33338             var targetGeometry = targetEntity.geometry(context.graph());
33339
33340             if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
33341               var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
33342               var targetParentWayIDs = context.graph().parentWays(targetEntity);
33343               var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
33344
33345               if (sharedParentWays.length !== 0) {
33346                 // if the nodes are next to each other, they are merged
33347                 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
33348                   return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
33349                 }
33350
33351                 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
33352               }
33353             }
33354
33355             return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
33356           }
33357
33358           function shouldSnapToNode(target) {
33359             if (!_activeEntity) return false;
33360             return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
33361           }
33362
33363           function origin(entity) {
33364             return context.projection(entity.loc);
33365           }
33366
33367           function keydown(d3_event) {
33368             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33369               if (context.surface().classed('nope')) {
33370                 context.surface().classed('nope-suppressed', true);
33371               }
33372
33373               context.surface().classed('nope', false).classed('nope-disabled', true);
33374             }
33375           }
33376
33377           function keyup(d3_event) {
33378             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
33379               if (context.surface().classed('nope-suppressed')) {
33380                 context.surface().classed('nope', true);
33381               }
33382
33383               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
33384             }
33385           }
33386
33387           function start(d3_event, entity) {
33388             _wasMidpoint = entity.type === 'midpoint';
33389             var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
33390             _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
33391
33392             if (_isCancelled) {
33393               if (hasHidden) {
33394                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
33395               }
33396
33397               return drag.cancel();
33398             }
33399
33400             if (_wasMidpoint) {
33401               var midpoint = entity;
33402               entity = osmNode();
33403               context.perform(actionAddMidpoint(midpoint, entity));
33404               entity = context.entity(entity.id); // get post-action entity
33405
33406               var vertex = context.surface().selectAll('.' + entity.id);
33407               drag.targetNode(vertex.node()).targetEntity(entity);
33408             } else {
33409               context.perform(actionNoop());
33410             }
33411
33412             _activeEntity = entity;
33413             _startLoc = entity.loc;
33414             hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
33415             context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
33416             context.enter(mode);
33417           } // related code
33418           // - `behavior/draw.js` `datum()`
33419
33420
33421           function datum(d3_event) {
33422             if (!d3_event || d3_event.altKey) {
33423               return {};
33424             } else {
33425               // When dragging, snap only to touch targets..
33426               // (this excludes area fills and active drawing elements)
33427               var d = d3_event.target.__data__;
33428               return d && d.properties && d.properties.target ? d : {};
33429             }
33430           }
33431
33432           function doMove(d3_event, entity, nudge) {
33433             nudge = nudge || [0, 0];
33434             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
33435             var currMouse = geoVecSubtract(currPoint, nudge);
33436             var loc = context.projection.invert(currMouse);
33437             var target, edge;
33438
33439             if (!_nudgeInterval) {
33440               // If not nudging at the edge of the viewport, try to snap..
33441               // related code
33442               // - `mode/drag_node.js`     `doMove()`
33443               // - `behavior/draw.js`      `click()`
33444               // - `behavior/draw_way.js`  `move()`
33445               var d = datum(d3_event);
33446               target = d && d.properties && d.properties.entity;
33447               var targetLoc = target && target.loc;
33448               var targetNodes = d && d.properties && d.properties.nodes;
33449
33450               if (targetLoc) {
33451                 // snap to node/vertex - a point target with `.loc`
33452                 if (shouldSnapToNode(target)) {
33453                   loc = targetLoc;
33454                 }
33455               } else if (targetNodes) {
33456                 // snap to way - a line target with `.nodes`
33457                 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
33458
33459                 if (edge) {
33460                   loc = edge.loc;
33461                 }
33462               }
33463             }
33464
33465             context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
33466
33467             var isInvalid = false; // Check if this connection to `target` could cause relations to break..
33468
33469             if (target) {
33470               isInvalid = hasRelationConflict(entity, target, edge, context.graph());
33471             } // Check if this drag causes the geometry to break..
33472
33473
33474             if (!isInvalid) {
33475               isInvalid = hasInvalidGeometry(entity, context.graph());
33476             }
33477
33478             var nope = context.surface().classed('nope');
33479
33480             if (isInvalid === 'relation' || isInvalid === 'restriction') {
33481               if (!nope) {
33482                 // about to nope - show hint
33483                 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
33484                   relation: _mainPresetIndex.item('type/restriction').name()
33485                 }))();
33486               }
33487             } else if (isInvalid) {
33488               var errorID = isInvalid === 'line' ? 'lines' : 'areas';
33489               context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
33490             } else {
33491               if (nope) {
33492                 // about to un-nope, remove hint
33493                 context.ui().flash.duration(1).label('')();
33494               }
33495             }
33496
33497             var nopeDisabled = context.surface().classed('nope-disabled');
33498
33499             if (nopeDisabled) {
33500               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
33501             } else {
33502               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
33503             }
33504
33505             _lastLoc = loc;
33506           } // Uses `actionConnect.disabled()` to know whether this connection is ok..
33507
33508
33509           function hasRelationConflict(entity, target, edge, graph) {
33510             var testGraph = graph.update(); // copy
33511             // if snapping to way - add midpoint there and consider that the target..
33512
33513             if (edge) {
33514               var midpoint = osmNode();
33515               var action = actionAddMidpoint({
33516                 loc: edge.loc,
33517                 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
33518               }, midpoint);
33519               testGraph = action(testGraph);
33520               target = midpoint;
33521             } // can we connect to it?
33522
33523
33524             var ids = [entity.id, target.id];
33525             return actionConnect(ids).disabled(testGraph);
33526           }
33527
33528           function hasInvalidGeometry(entity, graph) {
33529             var parents = graph.parentWays(entity);
33530             var i, j, k;
33531
33532             for (i = 0; i < parents.length; i++) {
33533               var parent = parents[i];
33534               var nodes = [];
33535               var activeIndex = null; // which multipolygon ring contains node being dragged
33536               // test any parent multipolygons for valid geometry
33537
33538               var relations = graph.parentRelations(parent);
33539
33540               for (j = 0; j < relations.length; j++) {
33541                 if (!relations[j].isMultipolygon()) continue;
33542                 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
33543
33544                 for (k = 0; k < rings.length; k++) {
33545                   nodes = rings[k].nodes;
33546
33547                   if (nodes.find(function (n) {
33548                     return n.id === entity.id;
33549                   })) {
33550                     activeIndex = k;
33551
33552                     if (geoHasSelfIntersections(nodes, entity.id)) {
33553                       return 'multipolygonMember';
33554                     }
33555                   }
33556
33557                   rings[k].coords = nodes.map(function (n) {
33558                     return n.loc;
33559                   });
33560                 } // test active ring for intersections with other rings in the multipolygon
33561
33562
33563                 for (k = 0; k < rings.length; k++) {
33564                   if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
33565
33566                   if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
33567                     return 'multipolygonRing';
33568                   }
33569                 }
33570               } // If we still haven't tested this node's parent way for self-intersections.
33571               // (because it's not a member of a multipolygon), test it now.
33572
33573
33574               if (activeIndex === null) {
33575                 nodes = parent.nodes.map(function (nodeID) {
33576                   return graph.entity(nodeID);
33577                 });
33578
33579                 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
33580                   return parent.geometry(graph);
33581                 }
33582               }
33583             }
33584
33585             return false;
33586           }
33587
33588           function move(d3_event, entity, point) {
33589             if (_isCancelled) return;
33590             d3_event.stopPropagation();
33591             context.surface().classed('nope-disabled', d3_event.altKey);
33592             _lastLoc = context.projection.invert(point);
33593             doMove(d3_event, entity);
33594             var nudge = geoViewportEdge(point, context.map().dimensions());
33595
33596             if (nudge) {
33597               startNudge(d3_event, entity, nudge);
33598             } else {
33599               stopNudge();
33600             }
33601           }
33602
33603           function end(d3_event, entity) {
33604             if (_isCancelled) return;
33605             var wasPoint = entity.geometry(context.graph()) === 'point';
33606             var d = datum(d3_event);
33607             var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
33608             var target = d && d.properties && d.properties.entity; // entity to snap to
33609
33610             if (nope) {
33611               // bounce back
33612               context.perform(_actionBounceBack(entity.id, _startLoc));
33613             } else if (target && target.type === 'way') {
33614               var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
33615               context.replace(actionAddMidpoint({
33616                 loc: choice.loc,
33617                 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
33618               }, entity), connectAnnotation(entity, target));
33619             } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
33620               context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
33621             } else if (_wasMidpoint) {
33622               context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
33623             } else {
33624               context.replace(actionNoop(), moveAnnotation(entity));
33625             }
33626
33627             if (wasPoint) {
33628               context.enter(modeSelect(context, [entity.id]));
33629             } else {
33630               var reselection = _restoreSelectedIDs.filter(function (id) {
33631                 return context.graph().hasEntity(id);
33632               });
33633
33634               if (reselection.length) {
33635                 context.enter(modeSelect(context, reselection));
33636               } else {
33637                 context.enter(modeBrowse(context));
33638               }
33639             }
33640           }
33641
33642           function _actionBounceBack(nodeID, toLoc) {
33643             var moveNode = actionMoveNode(nodeID, toLoc);
33644
33645             var action = function action(graph, t) {
33646               // last time through, pop off the bounceback perform.
33647               // it will then overwrite the initial perform with a moveNode that does nothing
33648               if (t === 1) context.pop();
33649               return moveNode(graph, t);
33650             };
33651
33652             action.transitionable = true;
33653             return action;
33654           }
33655
33656           function cancel() {
33657             drag.cancel();
33658             context.enter(modeBrowse(context));
33659           }
33660
33661           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);
33662
33663           mode.enter = function () {
33664             context.install(hover);
33665             context.install(edit);
33666             select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
33667             context.history().on('undone.drag-node', cancel);
33668           };
33669
33670           mode.exit = function () {
33671             context.ui().sidebar.hover.cancel();
33672             context.uninstall(hover);
33673             context.uninstall(edit);
33674             select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
33675             context.history().on('undone.drag-node', null);
33676             _activeEntity = null;
33677             context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
33678             stopNudge();
33679           };
33680
33681           mode.selectedIDs = function () {
33682             if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
33683
33684             return mode;
33685           };
33686
33687           mode.activeID = function () {
33688             if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
33689
33690             return mode;
33691           };
33692
33693           mode.restoreSelectedIDs = function (_) {
33694             if (!arguments.length) return _restoreSelectedIDs;
33695             _restoreSelectedIDs = _;
33696             return mode;
33697           };
33698
33699           mode.behavior = drag;
33700           return mode;
33701         }
33702
33703         // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
33704         var NON_GENERIC = !!nativePromiseConstructor && fails(function () {
33705           nativePromiseConstructor.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
33706         });
33707
33708         // `Promise.prototype.finally` method
33709         // https://tc39.github.io/ecma262/#sec-promise.prototype.finally
33710         _export({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
33711           'finally': function (onFinally) {
33712             var C = speciesConstructor(this, getBuiltIn('Promise'));
33713             var isFunction = typeof onFinally == 'function';
33714             return this.then(
33715               isFunction ? function (x) {
33716                 return promiseResolve(C, onFinally()).then(function () { return x; });
33717               } : onFinally,
33718               isFunction ? function (e) {
33719                 return promiseResolve(C, onFinally()).then(function () { throw e; });
33720               } : onFinally
33721             );
33722           }
33723         });
33724
33725         // patch native Promise.prototype for native async functions
33726         if ( typeof nativePromiseConstructor == 'function' && !nativePromiseConstructor.prototype['finally']) {
33727           redefine(nativePromiseConstructor.prototype, 'finally', getBuiltIn('Promise').prototype['finally']);
33728         }
33729
33730         // @@search logic
33731         fixRegexpWellKnownSymbolLogic('search', 1, function (SEARCH, nativeSearch, maybeCallNative) {
33732           return [
33733             // `String.prototype.search` method
33734             // https://tc39.github.io/ecma262/#sec-string.prototype.search
33735             function search(regexp) {
33736               var O = requireObjectCoercible(this);
33737               var searcher = regexp == undefined ? undefined : regexp[SEARCH];
33738               return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
33739             },
33740             // `RegExp.prototype[@@search]` method
33741             // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@search
33742             function (regexp) {
33743               var res = maybeCallNative(nativeSearch, regexp, this);
33744               if (res.done) return res.value;
33745
33746               var rx = anObject(regexp);
33747               var S = String(this);
33748
33749               var previousLastIndex = rx.lastIndex;
33750               if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
33751               var result = regexpExecAbstract(rx, S);
33752               if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
33753               return result === null ? -1 : result.index;
33754             }
33755           ];
33756         });
33757
33758         function quickselect$1(arr, k, left, right, compare) {
33759           quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
33760         }
33761
33762         function quickselectStep(arr, k, left, right, compare) {
33763           while (right > left) {
33764             if (right - left > 600) {
33765               var n = right - left + 1;
33766               var m = k - left + 1;
33767               var z = Math.log(n);
33768               var s = 0.5 * Math.exp(2 * z / 3);
33769               var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
33770               var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
33771               var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
33772               quickselectStep(arr, k, newLeft, newRight, compare);
33773             }
33774
33775             var t = arr[k];
33776             var i = left;
33777             var j = right;
33778             swap$1(arr, left, k);
33779             if (compare(arr[right], t) > 0) swap$1(arr, left, right);
33780
33781             while (i < j) {
33782               swap$1(arr, i, j);
33783               i++;
33784               j--;
33785
33786               while (compare(arr[i], t) < 0) {
33787                 i++;
33788               }
33789
33790               while (compare(arr[j], t) > 0) {
33791                 j--;
33792               }
33793             }
33794
33795             if (compare(arr[left], t) === 0) swap$1(arr, left, j);else {
33796               j++;
33797               swap$1(arr, j, right);
33798             }
33799             if (j <= k) left = j + 1;
33800             if (k <= j) right = j - 1;
33801           }
33802         }
33803
33804         function swap$1(arr, i, j) {
33805           var tmp = arr[i];
33806           arr[i] = arr[j];
33807           arr[j] = tmp;
33808         }
33809
33810         function defaultCompare(a, b) {
33811           return a < b ? -1 : a > b ? 1 : 0;
33812         }
33813
33814         var RBush = /*#__PURE__*/function () {
33815           function RBush() {
33816             var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
33817
33818             _classCallCheck(this, RBush);
33819
33820             // max entries in a node is 9 by default; min node fill is 40% for best performance
33821             this._maxEntries = Math.max(4, maxEntries);
33822             this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
33823             this.clear();
33824           }
33825
33826           _createClass(RBush, [{
33827             key: "all",
33828             value: function all() {
33829               return this._all(this.data, []);
33830             }
33831           }, {
33832             key: "search",
33833             value: function search(bbox) {
33834               var node = this.data;
33835               var result = [];
33836               if (!intersects(bbox, node)) return result;
33837               var toBBox = this.toBBox;
33838               var nodesToSearch = [];
33839
33840               while (node) {
33841                 for (var i = 0; i < node.children.length; i++) {
33842                   var child = node.children[i];
33843                   var childBBox = node.leaf ? toBBox(child) : child;
33844
33845                   if (intersects(bbox, childBBox)) {
33846                     if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
33847                   }
33848                 }
33849
33850                 node = nodesToSearch.pop();
33851               }
33852
33853               return result;
33854             }
33855           }, {
33856             key: "collides",
33857             value: function collides(bbox) {
33858               var node = this.data;
33859               if (!intersects(bbox, node)) return false;
33860               var nodesToSearch = [];
33861
33862               while (node) {
33863                 for (var i = 0; i < node.children.length; i++) {
33864                   var child = node.children[i];
33865                   var childBBox = node.leaf ? this.toBBox(child) : child;
33866
33867                   if (intersects(bbox, childBBox)) {
33868                     if (node.leaf || contains(bbox, childBBox)) return true;
33869                     nodesToSearch.push(child);
33870                   }
33871                 }
33872
33873                 node = nodesToSearch.pop();
33874               }
33875
33876               return false;
33877             }
33878           }, {
33879             key: "load",
33880             value: function load(data) {
33881               if (!(data && data.length)) return this;
33882
33883               if (data.length < this._minEntries) {
33884                 for (var i = 0; i < data.length; i++) {
33885                   this.insert(data[i]);
33886                 }
33887
33888                 return this;
33889               } // recursively build the tree with the given data from scratch using OMT algorithm
33890
33891
33892               var node = this._build(data.slice(), 0, data.length - 1, 0);
33893
33894               if (!this.data.children.length) {
33895                 // save as is if tree is empty
33896                 this.data = node;
33897               } else if (this.data.height === node.height) {
33898                 // split root if trees have the same height
33899                 this._splitRoot(this.data, node);
33900               } else {
33901                 if (this.data.height < node.height) {
33902                   // swap trees if inserted one is bigger
33903                   var tmpNode = this.data;
33904                   this.data = node;
33905                   node = tmpNode;
33906                 } // insert the small tree into the large tree at appropriate level
33907
33908
33909                 this._insert(node, this.data.height - node.height - 1, true);
33910               }
33911
33912               return this;
33913             }
33914           }, {
33915             key: "insert",
33916             value: function insert(item) {
33917               if (item) this._insert(item, this.data.height - 1);
33918               return this;
33919             }
33920           }, {
33921             key: "clear",
33922             value: function clear() {
33923               this.data = createNode([]);
33924               return this;
33925             }
33926           }, {
33927             key: "remove",
33928             value: function remove(item, equalsFn) {
33929               if (!item) return this;
33930               var node = this.data;
33931               var bbox = this.toBBox(item);
33932               var path = [];
33933               var indexes = [];
33934               var i, parent, goingUp; // depth-first iterative tree traversal
33935
33936               while (node || path.length) {
33937                 if (!node) {
33938                   // go up
33939                   node = path.pop();
33940                   parent = path[path.length - 1];
33941                   i = indexes.pop();
33942                   goingUp = true;
33943                 }
33944
33945                 if (node.leaf) {
33946                   // check current node
33947                   var index = findItem(item, node.children, equalsFn);
33948
33949                   if (index !== -1) {
33950                     // item found, remove the item and condense tree upwards
33951                     node.children.splice(index, 1);
33952                     path.push(node);
33953
33954                     this._condense(path);
33955
33956                     return this;
33957                   }
33958                 }
33959
33960                 if (!goingUp && !node.leaf && contains(node, bbox)) {
33961                   // go down
33962                   path.push(node);
33963                   indexes.push(i);
33964                   i = 0;
33965                   parent = node;
33966                   node = node.children[0];
33967                 } else if (parent) {
33968                   // go right
33969                   i++;
33970                   node = parent.children[i];
33971                   goingUp = false;
33972                 } else node = null; // nothing found
33973
33974               }
33975
33976               return this;
33977             }
33978           }, {
33979             key: "toBBox",
33980             value: function toBBox(item) {
33981               return item;
33982             }
33983           }, {
33984             key: "compareMinX",
33985             value: function compareMinX(a, b) {
33986               return a.minX - b.minX;
33987             }
33988           }, {
33989             key: "compareMinY",
33990             value: function compareMinY(a, b) {
33991               return a.minY - b.minY;
33992             }
33993           }, {
33994             key: "toJSON",
33995             value: function toJSON() {
33996               return this.data;
33997             }
33998           }, {
33999             key: "fromJSON",
34000             value: function fromJSON(data) {
34001               this.data = data;
34002               return this;
34003             }
34004           }, {
34005             key: "_all",
34006             value: function _all(node, result) {
34007               var nodesToSearch = [];
34008
34009               while (node) {
34010                 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
34011                 node = nodesToSearch.pop();
34012               }
34013
34014               return result;
34015             }
34016           }, {
34017             key: "_build",
34018             value: function _build(items, left, right, height) {
34019               var N = right - left + 1;
34020               var M = this._maxEntries;
34021               var node;
34022
34023               if (N <= M) {
34024                 // reached leaf level; return leaf
34025                 node = createNode(items.slice(left, right + 1));
34026                 calcBBox(node, this.toBBox);
34027                 return node;
34028               }
34029
34030               if (!height) {
34031                 // target height of the bulk-loaded tree
34032                 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
34033
34034                 M = Math.ceil(N / Math.pow(M, height - 1));
34035               }
34036
34037               node = createNode([]);
34038               node.leaf = false;
34039               node.height = height; // split the items into M mostly square tiles
34040
34041               var N2 = Math.ceil(N / M);
34042               var N1 = N2 * Math.ceil(Math.sqrt(M));
34043               multiSelect(items, left, right, N1, this.compareMinX);
34044
34045               for (var i = left; i <= right; i += N1) {
34046                 var right2 = Math.min(i + N1 - 1, right);
34047                 multiSelect(items, i, right2, N2, this.compareMinY);
34048
34049                 for (var j = i; j <= right2; j += N2) {
34050                   var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
34051
34052                   node.children.push(this._build(items, j, right3, height - 1));
34053                 }
34054               }
34055
34056               calcBBox(node, this.toBBox);
34057               return node;
34058             }
34059           }, {
34060             key: "_chooseSubtree",
34061             value: function _chooseSubtree(bbox, node, level, path) {
34062               while (true) {
34063                 path.push(node);
34064                 if (node.leaf || path.length - 1 === level) break;
34065                 var minArea = Infinity;
34066                 var minEnlargement = Infinity;
34067                 var targetNode = void 0;
34068
34069                 for (var i = 0; i < node.children.length; i++) {
34070                   var child = node.children[i];
34071                   var area = bboxArea(child);
34072                   var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
34073
34074                   if (enlargement < minEnlargement) {
34075                     minEnlargement = enlargement;
34076                     minArea = area < minArea ? area : minArea;
34077                     targetNode = child;
34078                   } else if (enlargement === minEnlargement) {
34079                     // otherwise choose one with the smallest area
34080                     if (area < minArea) {
34081                       minArea = area;
34082                       targetNode = child;
34083                     }
34084                   }
34085                 }
34086
34087                 node = targetNode || node.children[0];
34088               }
34089
34090               return node;
34091             }
34092           }, {
34093             key: "_insert",
34094             value: function _insert(item, level, isNode) {
34095               var bbox = isNode ? item : this.toBBox(item);
34096               var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
34097
34098               var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
34099
34100
34101               node.children.push(item);
34102               extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
34103
34104               while (level >= 0) {
34105                 if (insertPath[level].children.length > this._maxEntries) {
34106                   this._split(insertPath, level);
34107
34108                   level--;
34109                 } else break;
34110               } // adjust bboxes along the insertion path
34111
34112
34113               this._adjustParentBBoxes(bbox, insertPath, level);
34114             } // split overflowed node into two
34115
34116           }, {
34117             key: "_split",
34118             value: function _split(insertPath, level) {
34119               var node = insertPath[level];
34120               var M = node.children.length;
34121               var m = this._minEntries;
34122
34123               this._chooseSplitAxis(node, m, M);
34124
34125               var splitIndex = this._chooseSplitIndex(node, m, M);
34126
34127               var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
34128               newNode.height = node.height;
34129               newNode.leaf = node.leaf;
34130               calcBBox(node, this.toBBox);
34131               calcBBox(newNode, this.toBBox);
34132               if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
34133             }
34134           }, {
34135             key: "_splitRoot",
34136             value: function _splitRoot(node, newNode) {
34137               // split root node
34138               this.data = createNode([node, newNode]);
34139               this.data.height = node.height + 1;
34140               this.data.leaf = false;
34141               calcBBox(this.data, this.toBBox);
34142             }
34143           }, {
34144             key: "_chooseSplitIndex",
34145             value: function _chooseSplitIndex(node, m, M) {
34146               var index;
34147               var minOverlap = Infinity;
34148               var minArea = Infinity;
34149
34150               for (var i = m; i <= M - m; i++) {
34151                 var bbox1 = distBBox(node, 0, i, this.toBBox);
34152                 var bbox2 = distBBox(node, i, M, this.toBBox);
34153                 var overlap = intersectionArea(bbox1, bbox2);
34154                 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
34155
34156                 if (overlap < minOverlap) {
34157                   minOverlap = overlap;
34158                   index = i;
34159                   minArea = area < minArea ? area : minArea;
34160                 } else if (overlap === minOverlap) {
34161                   // otherwise choose distribution with minimum area
34162                   if (area < minArea) {
34163                     minArea = area;
34164                     index = i;
34165                   }
34166                 }
34167               }
34168
34169               return index || M - m;
34170             } // sorts node children by the best axis for split
34171
34172           }, {
34173             key: "_chooseSplitAxis",
34174             value: function _chooseSplitAxis(node, m, M) {
34175               var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
34176               var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
34177
34178               var xMargin = this._allDistMargin(node, m, M, compareMinX);
34179
34180               var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
34181               // otherwise it's already sorted by minY
34182
34183
34184               if (xMargin < yMargin) node.children.sort(compareMinX);
34185             } // total margin of all possible split distributions where each node is at least m full
34186
34187           }, {
34188             key: "_allDistMargin",
34189             value: function _allDistMargin(node, m, M, compare) {
34190               node.children.sort(compare);
34191               var toBBox = this.toBBox;
34192               var leftBBox = distBBox(node, 0, m, toBBox);
34193               var rightBBox = distBBox(node, M - m, M, toBBox);
34194               var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
34195
34196               for (var i = m; i < M - m; i++) {
34197                 var child = node.children[i];
34198                 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
34199                 margin += bboxMargin(leftBBox);
34200               }
34201
34202               for (var _i = M - m - 1; _i >= m; _i--) {
34203                 var _child = node.children[_i];
34204                 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
34205                 margin += bboxMargin(rightBBox);
34206               }
34207
34208               return margin;
34209             }
34210           }, {
34211             key: "_adjustParentBBoxes",
34212             value: function _adjustParentBBoxes(bbox, path, level) {
34213               // adjust bboxes along the given tree path
34214               for (var i = level; i >= 0; i--) {
34215                 extend$1(path[i], bbox);
34216               }
34217             }
34218           }, {
34219             key: "_condense",
34220             value: function _condense(path) {
34221               // go through the path, removing empty nodes and updating bboxes
34222               for (var i = path.length - 1, siblings; i >= 0; i--) {
34223                 if (path[i].children.length === 0) {
34224                   if (i > 0) {
34225                     siblings = path[i - 1].children;
34226                     siblings.splice(siblings.indexOf(path[i]), 1);
34227                   } else this.clear();
34228                 } else calcBBox(path[i], this.toBBox);
34229               }
34230             }
34231           }]);
34232
34233           return RBush;
34234         }();
34235
34236         function findItem(item, items, equalsFn) {
34237           if (!equalsFn) return items.indexOf(item);
34238
34239           for (var i = 0; i < items.length; i++) {
34240             if (equalsFn(item, items[i])) return i;
34241           }
34242
34243           return -1;
34244         } // calculate node's bbox from bboxes of its children
34245
34246
34247         function calcBBox(node, toBBox) {
34248           distBBox(node, 0, node.children.length, toBBox, node);
34249         } // min bounding rectangle of node children from k to p-1
34250
34251
34252         function distBBox(node, k, p, toBBox, destNode) {
34253           if (!destNode) destNode = createNode(null);
34254           destNode.minX = Infinity;
34255           destNode.minY = Infinity;
34256           destNode.maxX = -Infinity;
34257           destNode.maxY = -Infinity;
34258
34259           for (var i = k; i < p; i++) {
34260             var child = node.children[i];
34261             extend$1(destNode, node.leaf ? toBBox(child) : child);
34262           }
34263
34264           return destNode;
34265         }
34266
34267         function extend$1(a, b) {
34268           a.minX = Math.min(a.minX, b.minX);
34269           a.minY = Math.min(a.minY, b.minY);
34270           a.maxX = Math.max(a.maxX, b.maxX);
34271           a.maxY = Math.max(a.maxY, b.maxY);
34272           return a;
34273         }
34274
34275         function compareNodeMinX(a, b) {
34276           return a.minX - b.minX;
34277         }
34278
34279         function compareNodeMinY(a, b) {
34280           return a.minY - b.minY;
34281         }
34282
34283         function bboxArea(a) {
34284           return (a.maxX - a.minX) * (a.maxY - a.minY);
34285         }
34286
34287         function bboxMargin(a) {
34288           return a.maxX - a.minX + (a.maxY - a.minY);
34289         }
34290
34291         function enlargedArea(a, b) {
34292           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));
34293         }
34294
34295         function intersectionArea(a, b) {
34296           var minX = Math.max(a.minX, b.minX);
34297           var minY = Math.max(a.minY, b.minY);
34298           var maxX = Math.min(a.maxX, b.maxX);
34299           var maxY = Math.min(a.maxY, b.maxY);
34300           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
34301         }
34302
34303         function contains(a, b) {
34304           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
34305         }
34306
34307         function intersects(a, b) {
34308           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
34309         }
34310
34311         function createNode(children) {
34312           return {
34313             children: children,
34314             height: 1,
34315             leaf: true,
34316             minX: Infinity,
34317             minY: Infinity,
34318             maxX: -Infinity,
34319             maxY: -Infinity
34320           };
34321         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
34322         // combines selection algorithm with binary divide & conquer approach
34323
34324
34325         function multiSelect(arr, left, right, n, compare) {
34326           var stack = [left, right];
34327
34328           while (stack.length) {
34329             right = stack.pop();
34330             left = stack.pop();
34331             if (right - left <= n) continue;
34332             var mid = left + Math.ceil((right - left) / n / 2) * n;
34333             quickselect$1(arr, mid, left, right, compare);
34334             stack.push(left, mid, mid, right);
34335           }
34336         }
34337
34338         var tiler = utilTiler();
34339         var dispatch$1 = dispatch('loaded');
34340         var _tileZoom = 14;
34341         var _krUrlRoot = 'https://www.keepright.at';
34342         var _krData = {
34343           errorTypes: {},
34344           localizeStrings: {}
34345         }; // This gets reassigned if reset
34346
34347         var _cache;
34348
34349         var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
34350         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];
34351
34352         function abortRequest(controller) {
34353           if (controller) {
34354             controller.abort();
34355           }
34356         }
34357
34358         function abortUnwantedRequests(cache, tiles) {
34359           Object.keys(cache.inflightTile).forEach(function (k) {
34360             var wanted = tiles.find(function (tile) {
34361               return k === tile.id;
34362             });
34363
34364             if (!wanted) {
34365               abortRequest(cache.inflightTile[k]);
34366               delete cache.inflightTile[k];
34367             }
34368           });
34369         }
34370
34371         function encodeIssueRtree(d) {
34372           return {
34373             minX: d.loc[0],
34374             minY: d.loc[1],
34375             maxX: d.loc[0],
34376             maxY: d.loc[1],
34377             data: d
34378           };
34379         } // Replace or remove QAItem from rtree
34380
34381
34382         function updateRtree(item, replace) {
34383           _cache.rtree.remove(item, function (a, b) {
34384             return a.data.id === b.data.id;
34385           });
34386
34387           if (replace) {
34388             _cache.rtree.insert(item);
34389           }
34390         }
34391
34392         function tokenReplacements(d) {
34393           if (!(d instanceof QAItem)) return;
34394           var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
34395           var replacements = {};
34396           var issueTemplate = _krData.errorTypes[d.whichType];
34397
34398           if (!issueTemplate) {
34399             /* eslint-disable no-console */
34400             console.log('No Template: ', d.whichType);
34401             console.log('  ', d.description);
34402             /* eslint-enable no-console */
34403
34404             return;
34405           } // some descriptions are just fixed text
34406
34407
34408           if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
34409
34410           var errorRegex = new RegExp(issueTemplate.regex, 'i');
34411           var errorMatch = errorRegex.exec(d.description);
34412
34413           if (!errorMatch) {
34414             /* eslint-disable no-console */
34415             console.log('Unmatched: ', d.whichType);
34416             console.log('  ', d.description);
34417             console.log('  ', errorRegex);
34418             /* eslint-enable no-console */
34419
34420             return;
34421           }
34422
34423           for (var i = 1; i < errorMatch.length; i++) {
34424             // skip first
34425             var capture = errorMatch[i];
34426             var idType = void 0;
34427             idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
34428
34429             if (idType && capture) {
34430               // link IDs if present in the capture
34431               capture = parseError(capture, idType);
34432             } else if (htmlRegex.test(capture)) {
34433               // escape any html in non-IDs
34434               capture = '\\' + capture + '\\';
34435             } else {
34436               var compare = capture.toLowerCase();
34437
34438               if (_krData.localizeStrings[compare]) {
34439                 // some replacement strings can be localized
34440                 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34441               }
34442             }
34443
34444             replacements['var' + i] = capture;
34445           }
34446
34447           return replacements;
34448         }
34449
34450         function parseError(capture, idType) {
34451           var compare = capture.toLowerCase();
34452
34453           if (_krData.localizeStrings[compare]) {
34454             // some replacement strings can be localized
34455             capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
34456           }
34457
34458           switch (idType) {
34459             // link a string like "this node"
34460             case 'this':
34461               capture = linkErrorObject(capture);
34462               break;
34463
34464             case 'url':
34465               capture = linkURL(capture);
34466               break;
34467             // link an entity ID
34468
34469             case 'n':
34470             case 'w':
34471             case 'r':
34472               capture = linkEntity(idType + capture);
34473               break;
34474             // some errors have more complex ID lists/variance
34475
34476             case '20':
34477               capture = parse20(capture);
34478               break;
34479
34480             case '211':
34481               capture = parse211(capture);
34482               break;
34483
34484             case '231':
34485               capture = parse231(capture);
34486               break;
34487
34488             case '294':
34489               capture = parse294(capture);
34490               break;
34491
34492             case '370':
34493               capture = parse370(capture);
34494               break;
34495           }
34496
34497           return capture;
34498
34499           function linkErrorObject(d) {
34500             return "<a class=\"error_object_link\">".concat(d, "</a>");
34501           }
34502
34503           function linkEntity(d) {
34504             return "<a class=\"error_entity_link\">".concat(d, "</a>");
34505           }
34506
34507           function linkURL(d) {
34508             return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
34509           } // arbitrary node list of form: #ID, #ID, #ID...
34510
34511
34512           function parse211(capture) {
34513             var newList = [];
34514             var items = capture.split(', ');
34515             items.forEach(function (item) {
34516               // ID has # at the front
34517               var id = linkEntity('n' + item.slice(1));
34518               newList.push(id);
34519             });
34520             return newList.join(', ');
34521           } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
34522
34523
34524           function parse231(capture) {
34525             var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
34526
34527             var items = capture.split('),');
34528             items.forEach(function (item) {
34529               var match = item.match(/\#(\d+)\((.+)\)?/);
34530
34531               if (match !== null && match.length > 2) {
34532                 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
34533                   layer: match[2]
34534                 }));
34535               }
34536             });
34537             return newList.join(', ');
34538           } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
34539
34540
34541           function parse294(capture) {
34542             var newList = [];
34543             var items = capture.split(',');
34544             items.forEach(function (item) {
34545               // item of form "from/to node/relation #ID"
34546               item = item.split(' '); // to/from role is more clear in quotes
34547
34548               var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
34549
34550               var idType = item[1].slice(0, 1); // ID has # at the front
34551
34552               var id = item[2].slice(1);
34553               id = linkEntity(idType + id);
34554               newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
34555             });
34556             return newList.join(', ');
34557           } // may or may not include the string "(including the name 'name')"
34558
34559
34560           function parse370(capture) {
34561             if (!capture) return '';
34562             var match = capture.match(/\(including the name (\'.+\')\)/);
34563
34564             if (match && match.length) {
34565               return _t('QA.keepRight.errorTypes.370.including_the_name', {
34566                 name: match[1]
34567               });
34568             }
34569
34570             return '';
34571           } // arbitrary node list of form: #ID,#ID,#ID...
34572
34573
34574           function parse20(capture) {
34575             var newList = [];
34576             var items = capture.split(',');
34577             items.forEach(function (item) {
34578               // ID has # at the front
34579               var id = linkEntity('n' + item.slice(1));
34580               newList.push(id);
34581             });
34582             return newList.join(', ');
34583           }
34584         }
34585
34586         var serviceKeepRight = {
34587           title: 'keepRight',
34588           init: function init() {
34589             _mainFileFetcher.get('keepRight').then(function (d) {
34590               return _krData = d;
34591             });
34592
34593             if (!_cache) {
34594               this.reset();
34595             }
34596
34597             this.event = utilRebind(this, dispatch$1, 'on');
34598           },
34599           reset: function reset() {
34600             if (_cache) {
34601               Object.values(_cache.inflightTile).forEach(abortRequest);
34602             }
34603
34604             _cache = {
34605               data: {},
34606               loadedTile: {},
34607               inflightTile: {},
34608               inflightPost: {},
34609               closed: {},
34610               rtree: new RBush()
34611             };
34612           },
34613           // KeepRight API:  http://osm.mueschelsoft.de/keepright/interfacing.php
34614           loadIssues: function loadIssues(projection) {
34615             var _this = this;
34616
34617             var options = {
34618               format: 'geojson',
34619               ch: _krRuleset
34620             }; // determine the needed tiles to cover the view
34621
34622             var tiles = tiler.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
34623
34624             abortUnwantedRequests(_cache, tiles); // issue new requests..
34625
34626             tiles.forEach(function (tile) {
34627               if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
34628
34629               var _tile$extent$rectangl = tile.extent.rectangle(),
34630                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34631                   left = _tile$extent$rectangl2[0],
34632                   top = _tile$extent$rectangl2[1],
34633                   right = _tile$extent$rectangl2[2],
34634                   bottom = _tile$extent$rectangl2[3];
34635
34636               var params = Object.assign({}, options, {
34637                 left: left,
34638                 bottom: bottom,
34639                 right: right,
34640                 top: top
34641               });
34642               var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
34643               var controller = new AbortController();
34644               _cache.inflightTile[tile.id] = controller;
34645               d3_json(url, {
34646                 signal: controller.signal
34647               }).then(function (data) {
34648                 delete _cache.inflightTile[tile.id];
34649                 _cache.loadedTile[tile.id] = true;
34650
34651                 if (!data || !data.features || !data.features.length) {
34652                   throw new Error('No Data');
34653                 }
34654
34655                 data.features.forEach(function (feature) {
34656                   var _feature$properties = feature.properties,
34657                       itemType = _feature$properties.error_type,
34658                       id = _feature$properties.error_id,
34659                       _feature$properties$c = _feature$properties.comment,
34660                       comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
34661                       objectId = _feature$properties.object_id,
34662                       objectType = _feature$properties.object_type,
34663                       schema = _feature$properties.schema,
34664                       title = _feature$properties.title;
34665                   var loc = feature.geometry.coordinates,
34666                       _feature$properties$d = feature.properties.description,
34667                       description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
34668                   //  Error 191 = "highway-highway"
34669                   //  Error 190 = "intersections without junctions"  (parent)
34670
34671                   var issueTemplate = _krData.errorTypes[itemType];
34672                   var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
34673
34674                   var whichType = issueTemplate ? itemType : parentIssueType;
34675                   var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
34676                   // This is done to make them easier to linkify and translate.
34677
34678                   switch (whichType) {
34679                     case '170':
34680                       description = "This feature has a FIXME tag: ".concat(description);
34681                       break;
34682
34683                     case '292':
34684                     case '293':
34685                       description = description.replace('A turn-', 'This turn-');
34686                       break;
34687
34688                     case '294':
34689                     case '295':
34690                     case '296':
34691                     case '297':
34692                     case '298':
34693                       description = "This turn-restriction~".concat(description);
34694                       break;
34695
34696                     case '300':
34697                       description = 'This highway is missing a maxspeed tag';
34698                       break;
34699
34700                     case '411':
34701                     case '412':
34702                     case '413':
34703                       description = "This feature~".concat(description);
34704                       break;
34705                   } // move markers slightly so it doesn't obscure the geometry,
34706                   // then move markers away from other coincident markers
34707
34708
34709                   var coincident = false;
34710
34711                   do {
34712                     // first time, move marker up. after that, move marker right.
34713                     var delta = coincident ? [0.00001, 0] : [0, 0.00001];
34714                     loc = geoVecAdd(loc, delta);
34715                     var bbox = geoExtent(loc).bbox();
34716                     coincident = _cache.rtree.search(bbox).length;
34717                   } while (coincident);
34718
34719                   var d = new QAItem(loc, _this, itemType, id, {
34720                     comment: comment,
34721                     description: description,
34722                     whichType: whichType,
34723                     parentIssueType: parentIssueType,
34724                     severity: whichTemplate.severity || 'error',
34725                     objectId: objectId,
34726                     objectType: objectType,
34727                     schema: schema,
34728                     title: title
34729                   });
34730                   d.replacements = tokenReplacements(d);
34731                   _cache.data[id] = d;
34732
34733                   _cache.rtree.insert(encodeIssueRtree(d));
34734                 });
34735                 dispatch$1.call('loaded');
34736               })["catch"](function () {
34737                 delete _cache.inflightTile[tile.id];
34738                 _cache.loadedTile[tile.id] = true;
34739               });
34740             });
34741           },
34742           postUpdate: function postUpdate(d, callback) {
34743             var _this2 = this;
34744
34745             if (_cache.inflightPost[d.id]) {
34746               return callback({
34747                 message: 'Error update already inflight',
34748                 status: -2
34749               }, d);
34750             }
34751
34752             var params = {
34753               schema: d.schema,
34754               id: d.id
34755             };
34756
34757             if (d.newStatus) {
34758               params.st = d.newStatus;
34759             }
34760
34761             if (d.newComment !== undefined) {
34762               params.co = d.newComment;
34763             } // NOTE: This throws a CORS err, but it seems successful.
34764             // We don't care too much about the response, so this is fine.
34765
34766
34767             var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
34768             var controller = new AbortController();
34769             _cache.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
34770             // (worst case scenario the request truly fails and issue will show up if iD restarts)
34771
34772             d3_json(url, {
34773               signal: controller.signal
34774             })["finally"](function () {
34775               delete _cache.inflightPost[d.id];
34776
34777               if (d.newStatus === 'ignore') {
34778                 // ignore permanently (false positive)
34779                 _this2.removeItem(d);
34780               } else if (d.newStatus === 'ignore_t') {
34781                 // ignore temporarily (error fixed)
34782                 _this2.removeItem(d);
34783
34784                 _cache.closed["".concat(d.schema, ":").concat(d.id)] = true;
34785               } else {
34786                 d = _this2.replaceItem(d.update({
34787                   comment: d.newComment,
34788                   newComment: undefined,
34789                   newState: undefined
34790                 }));
34791               }
34792
34793               if (callback) callback(null, d);
34794             });
34795           },
34796           // Get all cached QAItems covering the viewport
34797           getItems: function getItems(projection) {
34798             var viewport = projection.clipExtent();
34799             var min = [viewport[0][0], viewport[1][1]];
34800             var max = [viewport[1][0], viewport[0][1]];
34801             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
34802             return _cache.rtree.search(bbox).map(function (d) {
34803               return d.data;
34804             });
34805           },
34806           // Get a QAItem from cache
34807           // NOTE: Don't change method name until UI v3 is merged
34808           getError: function getError(id) {
34809             return _cache.data[id];
34810           },
34811           // Replace a single QAItem in the cache
34812           replaceItem: function replaceItem(item) {
34813             if (!(item instanceof QAItem) || !item.id) return;
34814             _cache.data[item.id] = item;
34815             updateRtree(encodeIssueRtree(item), true); // true = replace
34816
34817             return item;
34818           },
34819           // Remove a single QAItem from the cache
34820           removeItem: function removeItem(item) {
34821             if (!(item instanceof QAItem) || !item.id) return;
34822             delete _cache.data[item.id];
34823             updateRtree(encodeIssueRtree(item), false); // false = remove
34824           },
34825           issueURL: function issueURL(item) {
34826             return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
34827           },
34828           // Get an array of issues closed during this session.
34829           // Used to populate `closed:keepright` changeset tag
34830           getClosedIDs: function getClosedIDs() {
34831             return Object.keys(_cache.closed).sort();
34832           }
34833         };
34834
34835         var tiler$1 = utilTiler();
34836         var dispatch$2 = dispatch('loaded');
34837         var _tileZoom$1 = 14;
34838         var _impOsmUrls = {
34839           ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
34840           mr: 'https://grab.community.improve-osm.org/missingGeoService',
34841           tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
34842         };
34843         var _impOsmData = {
34844           icons: {}
34845         }; // This gets reassigned if reset
34846
34847         var _cache$1;
34848
34849         function abortRequest$1(i) {
34850           Object.values(i).forEach(function (controller) {
34851             if (controller) {
34852               controller.abort();
34853             }
34854           });
34855         }
34856
34857         function abortUnwantedRequests$1(cache, tiles) {
34858           Object.keys(cache.inflightTile).forEach(function (k) {
34859             var wanted = tiles.find(function (tile) {
34860               return k === tile.id;
34861             });
34862
34863             if (!wanted) {
34864               abortRequest$1(cache.inflightTile[k]);
34865               delete cache.inflightTile[k];
34866             }
34867           });
34868         }
34869
34870         function encodeIssueRtree$1(d) {
34871           return {
34872             minX: d.loc[0],
34873             minY: d.loc[1],
34874             maxX: d.loc[0],
34875             maxY: d.loc[1],
34876             data: d
34877           };
34878         } // Replace or remove QAItem from rtree
34879
34880
34881         function updateRtree$1(item, replace) {
34882           _cache$1.rtree.remove(item, function (a, b) {
34883             return a.data.id === b.data.id;
34884           });
34885
34886           if (replace) {
34887             _cache$1.rtree.insert(item);
34888           }
34889         }
34890
34891         function linkErrorObject(d) {
34892           return "<a class=\"error_object_link\">".concat(d, "</a>");
34893         }
34894
34895         function linkEntity(d) {
34896           return "<a class=\"error_entity_link\">".concat(d, "</a>");
34897         }
34898
34899         function pointAverage(points) {
34900           if (points.length) {
34901             var sum = points.reduce(function (acc, point) {
34902               return geoVecAdd(acc, [point.lon, point.lat]);
34903             }, [0, 0]);
34904             return geoVecScale(sum, 1 / points.length);
34905           } else {
34906             return [0, 0];
34907           }
34908         }
34909
34910         function relativeBearing(p1, p2) {
34911           var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
34912
34913           if (angle < 0) {
34914             angle += 2 * Math.PI;
34915           } // Return degrees
34916
34917
34918           return angle * 180 / Math.PI;
34919         } // Assuming range [0,360)
34920
34921
34922         function cardinalDirection(bearing) {
34923           var dir = 45 * Math.round(bearing / 45);
34924           var compass = {
34925             0: 'north',
34926             45: 'northeast',
34927             90: 'east',
34928             135: 'southeast',
34929             180: 'south',
34930             225: 'southwest',
34931             270: 'west',
34932             315: 'northwest',
34933             360: 'north'
34934           };
34935           return _t("QA.improveOSM.directions.".concat(compass[dir]));
34936         } // Errors shouldn't obscure each other
34937
34938
34939         function preventCoincident(loc, bumpUp) {
34940           var coincident = false;
34941
34942           do {
34943             // first time, move marker up. after that, move marker right.
34944             var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
34945             loc = geoVecAdd(loc, delta);
34946             var bbox = geoExtent(loc).bbox();
34947             coincident = _cache$1.rtree.search(bbox).length;
34948           } while (coincident);
34949
34950           return loc;
34951         }
34952
34953         var serviceImproveOSM = {
34954           title: 'improveOSM',
34955           init: function init() {
34956             _mainFileFetcher.get('qa_data').then(function (d) {
34957               return _impOsmData = d.improveOSM;
34958             });
34959
34960             if (!_cache$1) {
34961               this.reset();
34962             }
34963
34964             this.event = utilRebind(this, dispatch$2, 'on');
34965           },
34966           reset: function reset() {
34967             if (_cache$1) {
34968               Object.values(_cache$1.inflightTile).forEach(abortRequest$1);
34969             }
34970
34971             _cache$1 = {
34972               data: {},
34973               loadedTile: {},
34974               inflightTile: {},
34975               inflightPost: {},
34976               closed: {},
34977               rtree: new RBush()
34978             };
34979           },
34980           loadIssues: function loadIssues(projection) {
34981             var _this = this;
34982
34983             var options = {
34984               client: 'iD',
34985               status: 'OPEN',
34986               zoom: '19' // Use a high zoom so that clusters aren't returned
34987
34988             }; // determine the needed tiles to cover the view
34989
34990             var tiles = tiler$1.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
34991
34992             abortUnwantedRequests$1(_cache$1, tiles); // issue new requests..
34993
34994             tiles.forEach(function (tile) {
34995               if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
34996
34997               var _tile$extent$rectangl = tile.extent.rectangle(),
34998                   _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
34999                   east = _tile$extent$rectangl2[0],
35000                   north = _tile$extent$rectangl2[1],
35001                   west = _tile$extent$rectangl2[2],
35002                   south = _tile$extent$rectangl2[3];
35003
35004               var params = Object.assign({}, options, {
35005                 east: east,
35006                 south: south,
35007                 west: west,
35008                 north: north
35009               }); // 3 separate requests to store for each tile
35010
35011               var requests = {};
35012               Object.keys(_impOsmUrls).forEach(function (k) {
35013                 // We exclude WATER from missing geometry as it doesn't seem useful
35014                 // We use most confident one-way and turn restrictions only, still have false positives
35015                 var kParams = Object.assign({}, params, k === 'mr' ? {
35016                   type: 'PARKING,ROAD,BOTH,PATH'
35017                 } : {
35018                   confidenceLevel: 'C1'
35019                 });
35020                 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
35021                 var controller = new AbortController();
35022                 requests[k] = controller;
35023                 d3_json(url, {
35024                   signal: controller.signal
35025                 }).then(function (data) {
35026                   delete _cache$1.inflightTile[tile.id][k];
35027
35028                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
35029                     delete _cache$1.inflightTile[tile.id];
35030                     _cache$1.loadedTile[tile.id] = true;
35031                   } // Road segments at high zoom == oneways
35032
35033
35034                   if (data.roadSegments) {
35035                     data.roadSegments.forEach(function (feature) {
35036                       // Position error at the approximate middle of the segment
35037                       var points = feature.points,
35038                           wayId = feature.wayId,
35039                           fromNodeId = feature.fromNodeId,
35040                           toNodeId = feature.toNodeId;
35041                       var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
35042                       var mid = points.length / 2;
35043                       var loc; // Even number of points, find midpoint of the middle two
35044                       // Odd number of points, use position of very middle point
35045
35046                       if (mid % 1 === 0) {
35047                         loc = pointAverage([points[mid - 1], points[mid]]);
35048                       } else {
35049                         mid = points[Math.floor(mid)];
35050                         loc = [mid.lon, mid.lat];
35051                       } // One-ways can land on same segment in opposite direction
35052
35053
35054                       loc = preventCoincident(loc, false);
35055                       var d = new QAItem(loc, _this, k, itemId, {
35056                         issueKey: k,
35057                         // used as a category
35058                         identifier: {
35059                           // used to post changes
35060                           wayId: wayId,
35061                           fromNodeId: fromNodeId,
35062                           toNodeId: toNodeId
35063                         },
35064                         objectId: wayId,
35065                         objectType: 'way'
35066                       }); // Variables used in the description
35067
35068                       d.replacements = {
35069                         percentage: feature.percentOfTrips,
35070                         num_trips: feature.numberOfTrips,
35071                         highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
35072                         from_node: linkEntity('n' + feature.fromNodeId),
35073                         to_node: linkEntity('n' + feature.toNodeId)
35074                       };
35075                       _cache$1.data[d.id] = d;
35076
35077                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35078                     });
35079                   } // Tiles at high zoom == missing roads
35080
35081
35082                   if (data.tiles) {
35083                     data.tiles.forEach(function (feature) {
35084                       var type = feature.type,
35085                           x = feature.x,
35086                           y = feature.y,
35087                           numberOfTrips = feature.numberOfTrips;
35088                       var geoType = type.toLowerCase();
35089                       var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
35090                       // Missing geometry could happen to land on another error
35091
35092                       var loc = pointAverage(feature.points);
35093                       loc = preventCoincident(loc, false);
35094                       var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
35095                         issueKey: k,
35096                         identifier: {
35097                           x: x,
35098                           y: y
35099                         }
35100                       });
35101                       d.replacements = {
35102                         num_trips: numberOfTrips,
35103                         geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
35104                       }; // -1 trips indicates data came from a 3rd party
35105
35106                       if (numberOfTrips === -1) {
35107                         d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
35108                       }
35109
35110                       _cache$1.data[d.id] = d;
35111
35112                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35113                     });
35114                   } // Entities at high zoom == turn restrictions
35115
35116
35117                   if (data.entities) {
35118                     data.entities.forEach(function (feature) {
35119                       var point = feature.point,
35120                           id = feature.id,
35121                           segments = feature.segments,
35122                           numberOfPasses = feature.numberOfPasses,
35123                           turnType = feature.turnType;
35124                       var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
35125                       // We also want to bump the error up so node is accessible
35126
35127                       var loc = preventCoincident([point.lon, point.lat], true); // Elements are presented in a strange way
35128
35129                       var ids = id.split(',');
35130                       var from_way = ids[0];
35131                       var via_node = ids[3];
35132                       var to_way = ids[2].split(':')[1];
35133                       var d = new QAItem(loc, _this, k, itemId, {
35134                         issueKey: k,
35135                         identifier: id,
35136                         objectId: via_node,
35137                         objectType: 'node'
35138                       }); // Travel direction along from_way clarifies the turn restriction
35139
35140                       var _segments$0$points = _slicedToArray(segments[0].points, 2),
35141                           p1 = _segments$0$points[0],
35142                           p2 = _segments$0$points[1];
35143
35144                       var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
35145
35146                       d.replacements = {
35147                         num_passed: numberOfPasses,
35148                         num_trips: segments[0].numberOfTrips,
35149                         turn_restriction: turnType.toLowerCase(),
35150                         from_way: linkEntity('w' + from_way),
35151                         to_way: linkEntity('w' + to_way),
35152                         travel_direction: dir_of_travel,
35153                         junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
35154                       };
35155                       _cache$1.data[d.id] = d;
35156
35157                       _cache$1.rtree.insert(encodeIssueRtree$1(d));
35158
35159                       dispatch$2.call('loaded');
35160                     });
35161                   }
35162                 })["catch"](function () {
35163                   delete _cache$1.inflightTile[tile.id][k];
35164
35165                   if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
35166                     delete _cache$1.inflightTile[tile.id];
35167                     _cache$1.loadedTile[tile.id] = true;
35168                   }
35169                 });
35170               });
35171               _cache$1.inflightTile[tile.id] = requests;
35172             });
35173           },
35174           getComments: function getComments(item) {
35175             var _this2 = this;
35176
35177             // If comments already retrieved no need to do so again
35178             if (item.comments) {
35179               return Promise.resolve(item);
35180             }
35181
35182             var key = item.issueKey;
35183             var qParams = {};
35184
35185             if (key === 'ow') {
35186               qParams = item.identifier;
35187             } else if (key === 'mr') {
35188               qParams.tileX = item.identifier.x;
35189               qParams.tileY = item.identifier.y;
35190             } else if (key === 'tr') {
35191               qParams.targetId = item.identifier;
35192             }
35193
35194             var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
35195
35196             var cacheComments = function cacheComments(data) {
35197               // Assign directly for immediate use afterwards
35198               // comments are served newest to oldest
35199               item.comments = data.comments ? data.comments.reverse() : [];
35200
35201               _this2.replaceItem(item);
35202             };
35203
35204             return d3_json(url).then(cacheComments).then(function () {
35205               return item;
35206             });
35207           },
35208           postUpdate: function postUpdate(d, callback) {
35209             if (!serviceOsm.authenticated()) {
35210               // Username required in payload
35211               return callback({
35212                 message: 'Not Authenticated',
35213                 status: -3
35214               }, d);
35215             }
35216
35217             if (_cache$1.inflightPost[d.id]) {
35218               return callback({
35219                 message: 'Error update already inflight',
35220                 status: -2
35221               }, d);
35222             } // Payload can only be sent once username is established
35223
35224
35225             serviceOsm.userDetails(sendPayload.bind(this));
35226
35227             function sendPayload(err, user) {
35228               var _this3 = this;
35229
35230               if (err) {
35231                 return callback(err, d);
35232               }
35233
35234               var key = d.issueKey;
35235               var url = "".concat(_impOsmUrls[key], "/comment");
35236               var payload = {
35237                 username: user.display_name,
35238                 targetIds: [d.identifier]
35239               };
35240
35241               if (d.newStatus) {
35242                 payload.status = d.newStatus;
35243                 payload.text = 'status changed';
35244               } // Comment take place of default text
35245
35246
35247               if (d.newComment) {
35248                 payload.text = d.newComment;
35249               }
35250
35251               var controller = new AbortController();
35252               _cache$1.inflightPost[d.id] = controller;
35253               var options = {
35254                 method: 'POST',
35255                 signal: controller.signal,
35256                 body: JSON.stringify(payload)
35257               };
35258               d3_json(url, options).then(function () {
35259                 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
35260
35261                 if (!d.newStatus) {
35262                   var now = new Date();
35263                   var comments = d.comments ? d.comments : [];
35264                   comments.push({
35265                     username: payload.username,
35266                     text: payload.text,
35267                     timestamp: now.getTime() / 1000
35268                   });
35269
35270                   _this3.replaceItem(d.update({
35271                     comments: comments,
35272                     newComment: undefined
35273                   }));
35274                 } else {
35275                   _this3.removeItem(d);
35276
35277                   if (d.newStatus === 'SOLVED') {
35278                     // Keep track of the number of issues closed per type to tag the changeset
35279                     if (!(d.issueKey in _cache$1.closed)) {
35280                       _cache$1.closed[d.issueKey] = 0;
35281                     }
35282
35283                     _cache$1.closed[d.issueKey] += 1;
35284                   }
35285                 }
35286
35287                 if (callback) callback(null, d);
35288               })["catch"](function (err) {
35289                 delete _cache$1.inflightPost[d.id];
35290                 if (callback) callback(err.message);
35291               });
35292             }
35293           },
35294           // Get all cached QAItems covering the viewport
35295           getItems: function getItems(projection) {
35296             var viewport = projection.clipExtent();
35297             var min = [viewport[0][0], viewport[1][1]];
35298             var max = [viewport[1][0], viewport[0][1]];
35299             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
35300             return _cache$1.rtree.search(bbox).map(function (d) {
35301               return d.data;
35302             });
35303           },
35304           // Get a QAItem from cache
35305           // NOTE: Don't change method name until UI v3 is merged
35306           getError: function getError(id) {
35307             return _cache$1.data[id];
35308           },
35309           // get the name of the icon to display for this item
35310           getIcon: function getIcon(itemType) {
35311             return _impOsmData.icons[itemType];
35312           },
35313           // Replace a single QAItem in the cache
35314           replaceItem: function replaceItem(issue) {
35315             if (!(issue instanceof QAItem) || !issue.id) return;
35316             _cache$1.data[issue.id] = issue;
35317             updateRtree$1(encodeIssueRtree$1(issue), true); // true = replace
35318
35319             return issue;
35320           },
35321           // Remove a single QAItem from the cache
35322           removeItem: function removeItem(issue) {
35323             if (!(issue instanceof QAItem) || !issue.id) return;
35324             delete _cache$1.data[issue.id];
35325             updateRtree$1(encodeIssueRtree$1(issue), false); // false = remove
35326           },
35327           // Used to populate `closed:improveosm:*` changeset tags
35328           getClosedCounts: function getClosedCounts() {
35329             return _cache$1.closed;
35330           }
35331         };
35332
35333         var quot = /"/g;
35334
35335         // B.2.3.2.1 CreateHTML(string, tag, attribute, value)
35336         // https://tc39.github.io/ecma262/#sec-createhtml
35337         var createHtml = function (string, tag, attribute, value) {
35338           var S = String(requireObjectCoercible(string));
35339           var p1 = '<' + tag;
35340           if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '&quot;') + '"';
35341           return p1 + '>' + S + '</' + tag + '>';
35342         };
35343
35344         // check the existence of a method, lowercase
35345         // of a tag and escaping quotes in arguments
35346         var stringHtmlForced = function (METHOD_NAME) {
35347           return fails(function () {
35348             var test = ''[METHOD_NAME]('"');
35349             return test !== test.toLowerCase() || test.split('"').length > 3;
35350           });
35351         };
35352
35353         // `String.prototype.link` method
35354         // https://tc39.github.io/ecma262/#sec-string.prototype.link
35355         _export({ target: 'String', proto: true, forced: stringHtmlForced('link') }, {
35356           link: function link(url) {
35357             return createHtml(this, 'a', 'href', url);
35358           }
35359         });
35360
35361         var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
35362
35363
35364
35365
35366
35367
35368         var nativeEndsWith = ''.endsWith;
35369         var min$8 = Math.min;
35370
35371         var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('endsWith');
35372         // https://github.com/zloirock/core-js/pull/702
35373         var MDN_POLYFILL_BUG =  !CORRECT_IS_REGEXP_LOGIC && !!function () {
35374           var descriptor = getOwnPropertyDescriptor$4(String.prototype, 'endsWith');
35375           return descriptor && !descriptor.writable;
35376         }();
35377
35378         // `String.prototype.endsWith` method
35379         // https://tc39.github.io/ecma262/#sec-string.prototype.endswith
35380         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
35381           endsWith: function endsWith(searchString /* , endPosition = @length */) {
35382             var that = String(requireObjectCoercible(this));
35383             notARegexp(searchString);
35384             var endPosition = arguments.length > 1 ? arguments[1] : undefined;
35385             var len = toLength(that.length);
35386             var end = endPosition === undefined ? len : min$8(toLength(endPosition), len);
35387             var search = String(searchString);
35388             return nativeEndsWith
35389               ? nativeEndsWith.call(that, search, end)
35390               : that.slice(end - search.length, end) === search;
35391           }
35392         });
35393
35394         var getOwnPropertyDescriptor$5 = objectGetOwnPropertyDescriptor.f;
35395
35396
35397
35398
35399
35400
35401         var nativeStartsWith = ''.startsWith;
35402         var min$9 = Math.min;
35403
35404         var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegexpLogic('startsWith');
35405         // https://github.com/zloirock/core-js/pull/702
35406         var MDN_POLYFILL_BUG$1 =  !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
35407           var descriptor = getOwnPropertyDescriptor$5(String.prototype, 'startsWith');
35408           return descriptor && !descriptor.writable;
35409         }();
35410
35411         // `String.prototype.startsWith` method
35412         // https://tc39.github.io/ecma262/#sec-string.prototype.startswith
35413         _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
35414           startsWith: function startsWith(searchString /* , position = 0 */) {
35415             var that = String(requireObjectCoercible(this));
35416             notARegexp(searchString);
35417             var index = toLength(min$9(arguments.length > 1 ? arguments[1] : undefined, that.length));
35418             var search = String(searchString);
35419             return nativeStartsWith
35420               ? nativeStartsWith.call(that, search, index)
35421               : that.slice(index, index + search.length) === search;
35422           }
35423         });
35424
35425         var $trimEnd = stringTrim.end;
35426
35427
35428         var FORCED$e = stringTrimForced('trimEnd');
35429
35430         var trimEnd = FORCED$e ? function trimEnd() {
35431           return $trimEnd(this);
35432         } : ''.trimEnd;
35433
35434         // `String.prototype.{ trimEnd, trimRight }` methods
35435         // https://github.com/tc39/ecmascript-string-left-right-trim
35436         _export({ target: 'String', proto: true, forced: FORCED$e }, {
35437           trimEnd: trimEnd,
35438           trimRight: trimEnd
35439         });
35440
35441         var defaults = createCommonjsModule(function (module) {
35442           function getDefaults() {
35443             return {
35444               baseUrl: null,
35445               breaks: false,
35446               gfm: true,
35447               headerIds: true,
35448               headerPrefix: '',
35449               highlight: null,
35450               langPrefix: 'language-',
35451               mangle: true,
35452               pedantic: false,
35453               renderer: null,
35454               sanitize: false,
35455               sanitizer: null,
35456               silent: false,
35457               smartLists: false,
35458               smartypants: false,
35459               tokenizer: null,
35460               walkTokens: null,
35461               xhtml: false
35462             };
35463           }
35464
35465           function changeDefaults(newDefaults) {
35466             module.exports.defaults = newDefaults;
35467           }
35468
35469           module.exports = {
35470             defaults: getDefaults(),
35471             getDefaults: getDefaults,
35472             changeDefaults: changeDefaults
35473           };
35474         });
35475
35476         /**
35477          * Helpers
35478          */
35479         var escapeTest = /[&<>"']/;
35480         var escapeReplace = /[&<>"']/g;
35481         var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
35482         var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
35483         var escapeReplacements = {
35484           '&': '&amp;',
35485           '<': '&lt;',
35486           '>': '&gt;',
35487           '"': '&quot;',
35488           "'": '&#39;'
35489         };
35490
35491         var getEscapeReplacement = function getEscapeReplacement(ch) {
35492           return escapeReplacements[ch];
35493         };
35494
35495         function escape$1(html, encode) {
35496           if (encode) {
35497             if (escapeTest.test(html)) {
35498               return html.replace(escapeReplace, getEscapeReplacement);
35499             }
35500           } else {
35501             if (escapeTestNoEncode.test(html)) {
35502               return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
35503             }
35504           }
35505
35506           return html;
35507         }
35508
35509         var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
35510
35511         function unescape$1(html) {
35512           // explicitly match decimal, hex, and named HTML entities
35513           return html.replace(unescapeTest, function (_, n) {
35514             n = n.toLowerCase();
35515             if (n === 'colon') return ':';
35516
35517             if (n.charAt(0) === '#') {
35518               return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
35519             }
35520
35521             return '';
35522           });
35523         }
35524
35525         var caret = /(^|[^\[])\^/g;
35526
35527         function edit(regex, opt) {
35528           regex = regex.source || regex;
35529           opt = opt || '';
35530           var obj = {
35531             replace: function replace(name, val) {
35532               val = val.source || val;
35533               val = val.replace(caret, '$1');
35534               regex = regex.replace(name, val);
35535               return obj;
35536             },
35537             getRegex: function getRegex() {
35538               return new RegExp(regex, opt);
35539             }
35540           };
35541           return obj;
35542         }
35543
35544         var nonWordAndColonTest = /[^\w:]/g;
35545         var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
35546
35547         function cleanUrl(sanitize, base, href) {
35548           if (sanitize) {
35549             var prot;
35550
35551             try {
35552               prot = decodeURIComponent(unescape$1(href)).replace(nonWordAndColonTest, '').toLowerCase();
35553             } catch (e) {
35554               return null;
35555             }
35556
35557             if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
35558               return null;
35559             }
35560           }
35561
35562           if (base && !originIndependentUrl.test(href)) {
35563             href = resolveUrl(base, href);
35564           }
35565
35566           try {
35567             href = encodeURI(href).replace(/%25/g, '%');
35568           } catch (e) {
35569             return null;
35570           }
35571
35572           return href;
35573         }
35574
35575         var baseUrls = {};
35576         var justDomain = /^[^:]+:\/*[^/]*$/;
35577         var protocol = /^([^:]+:)[\s\S]*$/;
35578         var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
35579
35580         function resolveUrl(base, href) {
35581           if (!baseUrls[' ' + base]) {
35582             // we can ignore everything in base after the last slash of its path component,
35583             // but we might need to add _that_
35584             // https://tools.ietf.org/html/rfc3986#section-3
35585             if (justDomain.test(base)) {
35586               baseUrls[' ' + base] = base + '/';
35587             } else {
35588               baseUrls[' ' + base] = rtrim$1(base, '/', true);
35589             }
35590           }
35591
35592           base = baseUrls[' ' + base];
35593           var relativeBase = base.indexOf(':') === -1;
35594
35595           if (href.substring(0, 2) === '//') {
35596             if (relativeBase) {
35597               return href;
35598             }
35599
35600             return base.replace(protocol, '$1') + href;
35601           } else if (href.charAt(0) === '/') {
35602             if (relativeBase) {
35603               return href;
35604             }
35605
35606             return base.replace(domain, '$1') + href;
35607           } else {
35608             return base + href;
35609           }
35610         }
35611
35612         var noopTest = {
35613           exec: function noopTest() {}
35614         };
35615
35616         function merge$1(obj) {
35617           var i = 1,
35618               target,
35619               key;
35620
35621           for (; i < arguments.length; i++) {
35622             target = arguments[i];
35623
35624             for (key in target) {
35625               if (Object.prototype.hasOwnProperty.call(target, key)) {
35626                 obj[key] = target[key];
35627               }
35628             }
35629           }
35630
35631           return obj;
35632         }
35633
35634         function splitCells(tableRow, count) {
35635           // ensure that every cell-delimiting pipe has a space
35636           // before it to distinguish it from an escaped pipe
35637           var row = tableRow.replace(/\|/g, function (match, offset, str) {
35638             var escaped = false,
35639                 curr = offset;
35640
35641             while (--curr >= 0 && str[curr] === '\\') {
35642               escaped = !escaped;
35643             }
35644
35645             if (escaped) {
35646               // odd number of slashes means | is escaped
35647               // so we leave it alone
35648               return '|';
35649             } else {
35650               // add space before unescaped |
35651               return ' |';
35652             }
35653           }),
35654               cells = row.split(/ \|/);
35655           var i = 0;
35656
35657           if (cells.length > count) {
35658             cells.splice(count);
35659           } else {
35660             while (cells.length < count) {
35661               cells.push('');
35662             }
35663           }
35664
35665           for (; i < cells.length; i++) {
35666             // leading or trailing whitespace is ignored per the gfm spec
35667             cells[i] = cells[i].trim().replace(/\\\|/g, '|');
35668           }
35669
35670           return cells;
35671         } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
35672         // /c*$/ is vulnerable to REDOS.
35673         // invert: Remove suffix of non-c chars instead. Default falsey.
35674
35675
35676         function rtrim$1(str, c, invert) {
35677           var l = str.length;
35678
35679           if (l === 0) {
35680             return '';
35681           } // Length of suffix matching the invert condition.
35682
35683
35684           var suffLen = 0; // Step left until we fail to match the invert condition.
35685
35686           while (suffLen < l) {
35687             var currChar = str.charAt(l - suffLen - 1);
35688
35689             if (currChar === c && !invert) {
35690               suffLen++;
35691             } else if (currChar !== c && invert) {
35692               suffLen++;
35693             } else {
35694               break;
35695             }
35696           }
35697
35698           return str.substr(0, l - suffLen);
35699         }
35700
35701         function findClosingBracket(str, b) {
35702           if (str.indexOf(b[1]) === -1) {
35703             return -1;
35704           }
35705
35706           var l = str.length;
35707           var level = 0,
35708               i = 0;
35709
35710           for (; i < l; i++) {
35711             if (str[i] === '\\') {
35712               i++;
35713             } else if (str[i] === b[0]) {
35714               level++;
35715             } else if (str[i] === b[1]) {
35716               level--;
35717
35718               if (level < 0) {
35719                 return i;
35720               }
35721             }
35722           }
35723
35724           return -1;
35725         }
35726
35727         function checkSanitizeDeprecation(opt) {
35728           if (opt && opt.sanitize && !opt.silent) {
35729             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');
35730           }
35731         } // copied from https://stackoverflow.com/a/5450113/806777
35732
35733
35734         function repeatString(pattern, count) {
35735           if (count < 1) {
35736             return '';
35737           }
35738
35739           var result = '';
35740
35741           while (count > 1) {
35742             if (count & 1) {
35743               result += pattern;
35744             }
35745
35746             count >>= 1;
35747             pattern += pattern;
35748           }
35749
35750           return result + pattern;
35751         }
35752
35753         var helpers = {
35754           escape: escape$1,
35755           unescape: unescape$1,
35756           edit: edit,
35757           cleanUrl: cleanUrl,
35758           resolveUrl: resolveUrl,
35759           noopTest: noopTest,
35760           merge: merge$1,
35761           splitCells: splitCells,
35762           rtrim: rtrim$1,
35763           findClosingBracket: findClosingBracket,
35764           checkSanitizeDeprecation: checkSanitizeDeprecation,
35765           repeatString: repeatString
35766         };
35767
35768         var defaults$1 = defaults.defaults;
35769         var rtrim$2 = helpers.rtrim,
35770             splitCells$1 = helpers.splitCells,
35771             _escape = helpers.escape,
35772             findClosingBracket$1 = helpers.findClosingBracket;
35773
35774         function outputLink(cap, link, raw) {
35775           var href = link.href;
35776           var title = link.title ? _escape(link.title) : null;
35777           var text = cap[1].replace(/\\([\[\]])/g, '$1');
35778
35779           if (cap[0].charAt(0) !== '!') {
35780             return {
35781               type: 'link',
35782               raw: raw,
35783               href: href,
35784               title: title,
35785               text: text
35786             };
35787           } else {
35788             return {
35789               type: 'image',
35790               raw: raw,
35791               href: href,
35792               title: title,
35793               text: _escape(text)
35794             };
35795           }
35796         }
35797
35798         function indentCodeCompensation(raw, text) {
35799           var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
35800
35801           if (matchIndentToCode === null) {
35802             return text;
35803           }
35804
35805           var indentToCode = matchIndentToCode[1];
35806           return text.split('\n').map(function (node) {
35807             var matchIndentInNode = node.match(/^\s+/);
35808
35809             if (matchIndentInNode === null) {
35810               return node;
35811             }
35812
35813             var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
35814                 indentInNode = _matchIndentInNode[0];
35815
35816             if (indentInNode.length >= indentToCode.length) {
35817               return node.slice(indentToCode.length);
35818             }
35819
35820             return node;
35821           }).join('\n');
35822         }
35823         /**
35824          * Tokenizer
35825          */
35826
35827
35828         var Tokenizer_1 = /*#__PURE__*/function () {
35829           function Tokenizer(options) {
35830             _classCallCheck(this, Tokenizer);
35831
35832             this.options = options || defaults$1;
35833           }
35834
35835           _createClass(Tokenizer, [{
35836             key: "space",
35837             value: function space(src) {
35838               var cap = this.rules.block.newline.exec(src);
35839
35840               if (cap) {
35841                 if (cap[0].length > 1) {
35842                   return {
35843                     type: 'space',
35844                     raw: cap[0]
35845                   };
35846                 }
35847
35848                 return {
35849                   raw: '\n'
35850                 };
35851               }
35852             }
35853           }, {
35854             key: "code",
35855             value: function code(src, tokens) {
35856               var cap = this.rules.block.code.exec(src);
35857
35858               if (cap) {
35859                 var lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
35860
35861                 if (lastToken && lastToken.type === 'paragraph') {
35862                   return {
35863                     raw: cap[0],
35864                     text: cap[0].trimRight()
35865                   };
35866                 }
35867
35868                 var text = cap[0].replace(/^ {4}/gm, '');
35869                 return {
35870                   type: 'code',
35871                   raw: cap[0],
35872                   codeBlockStyle: 'indented',
35873                   text: !this.options.pedantic ? rtrim$2(text, '\n') : text
35874                 };
35875               }
35876             }
35877           }, {
35878             key: "fences",
35879             value: function fences(src) {
35880               var cap = this.rules.block.fences.exec(src);
35881
35882               if (cap) {
35883                 var raw = cap[0];
35884                 var text = indentCodeCompensation(raw, cap[3] || '');
35885                 return {
35886                   type: 'code',
35887                   raw: raw,
35888                   lang: cap[2] ? cap[2].trim() : cap[2],
35889                   text: text
35890                 };
35891               }
35892             }
35893           }, {
35894             key: "heading",
35895             value: function heading(src) {
35896               var cap = this.rules.block.heading.exec(src);
35897
35898               if (cap) {
35899                 return {
35900                   type: 'heading',
35901                   raw: cap[0],
35902                   depth: cap[1].length,
35903                   text: cap[2]
35904                 };
35905               }
35906             }
35907           }, {
35908             key: "nptable",
35909             value: function nptable(src) {
35910               var cap = this.rules.block.nptable.exec(src);
35911
35912               if (cap) {
35913                 var item = {
35914                   type: 'table',
35915                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
35916                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
35917                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
35918                   raw: cap[0]
35919                 };
35920
35921                 if (item.header.length === item.align.length) {
35922                   var l = item.align.length;
35923                   var i;
35924
35925                   for (i = 0; i < l; i++) {
35926                     if (/^ *-+: *$/.test(item.align[i])) {
35927                       item.align[i] = 'right';
35928                     } else if (/^ *:-+: *$/.test(item.align[i])) {
35929                       item.align[i] = 'center';
35930                     } else if (/^ *:-+ *$/.test(item.align[i])) {
35931                       item.align[i] = 'left';
35932                     } else {
35933                       item.align[i] = null;
35934                     }
35935                   }
35936
35937                   l = item.cells.length;
35938
35939                   for (i = 0; i < l; i++) {
35940                     item.cells[i] = splitCells$1(item.cells[i], item.header.length);
35941                   }
35942
35943                   return item;
35944                 }
35945               }
35946             }
35947           }, {
35948             key: "hr",
35949             value: function hr(src) {
35950               var cap = this.rules.block.hr.exec(src);
35951
35952               if (cap) {
35953                 return {
35954                   type: 'hr',
35955                   raw: cap[0]
35956                 };
35957               }
35958             }
35959           }, {
35960             key: "blockquote",
35961             value: function blockquote(src) {
35962               var cap = this.rules.block.blockquote.exec(src);
35963
35964               if (cap) {
35965                 var text = cap[0].replace(/^ *> ?/gm, '');
35966                 return {
35967                   type: 'blockquote',
35968                   raw: cap[0],
35969                   text: text
35970                 };
35971               }
35972             }
35973           }, {
35974             key: "list",
35975             value: function list(src) {
35976               var cap = this.rules.block.list.exec(src);
35977
35978               if (cap) {
35979                 var raw = cap[0];
35980                 var bull = cap[2];
35981                 var isordered = bull.length > 1;
35982                 var list = {
35983                   type: 'list',
35984                   raw: raw,
35985                   ordered: isordered,
35986                   start: isordered ? +bull.slice(0, -1) : '',
35987                   loose: false,
35988                   items: []
35989                 }; // Get each top-level item.
35990
35991                 var itemMatch = cap[0].match(this.rules.block.item);
35992                 var next = false,
35993                     item,
35994                     space,
35995                     bcurr,
35996                     bnext,
35997                     addBack,
35998                     loose,
35999                     istask,
36000                     ischecked;
36001                 var l = itemMatch.length;
36002                 bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
36003
36004                 for (var i = 0; i < l; i++) {
36005                   item = itemMatch[i];
36006                   raw = item; // Determine whether the next list item belongs here.
36007                   // Backpedal if it does not belong in this list.
36008
36009                   if (i !== l - 1) {
36010                     bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
36011
36012                     if (bnext[1].length > bcurr[0].length || bnext[1].length > 3) {
36013                       // nested list
36014                       itemMatch.splice(i, 2, itemMatch[i] + '\n' + itemMatch[i + 1]);
36015                       i--;
36016                       l--;
36017                       continue;
36018                     } else {
36019                       if ( // different bullet style
36020                       !this.options.pedantic || this.options.smartLists ? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1] : isordered === (bnext[2].length === 1)) {
36021                         addBack = itemMatch.slice(i + 1).join('\n');
36022                         list.raw = list.raw.substring(0, list.raw.length - addBack.length);
36023                         i = l - 1;
36024                       }
36025                     }
36026
36027                     bcurr = bnext;
36028                   } // Remove the list item's bullet
36029                   // so it is seen as the next token.
36030
36031
36032                   space = item.length;
36033                   item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
36034                   // list item contains. Hacky.
36035
36036                   if (~item.indexOf('\n ')) {
36037                     space -= item.length;
36038                     item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
36039                   } // Determine whether item is loose or not.
36040                   // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
36041                   // for discount behavior.
36042
36043
36044                   loose = next || /\n\n(?!\s*$)/.test(item);
36045
36046                   if (i !== l - 1) {
36047                     next = item.charAt(item.length - 1) === '\n';
36048                     if (!loose) loose = next;
36049                   }
36050
36051                   if (loose) {
36052                     list.loose = true;
36053                   } // Check for task list items
36054
36055
36056                   istask = /^\[[ xX]\] /.test(item);
36057                   ischecked = undefined;
36058
36059                   if (istask) {
36060                     ischecked = item[1] !== ' ';
36061                     item = item.replace(/^\[[ xX]\] +/, '');
36062                   }
36063
36064                   list.items.push({
36065                     type: 'list_item',
36066                     raw: raw,
36067                     task: istask,
36068                     checked: ischecked,
36069                     loose: loose,
36070                     text: item
36071                   });
36072                 }
36073
36074                 return list;
36075               }
36076             }
36077           }, {
36078             key: "html",
36079             value: function html(src) {
36080               var cap = this.rules.block.html.exec(src);
36081
36082               if (cap) {
36083                 return {
36084                   type: this.options.sanitize ? 'paragraph' : 'html',
36085                   raw: cap[0],
36086                   pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
36087                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36088                 };
36089               }
36090             }
36091           }, {
36092             key: "def",
36093             value: function def(src) {
36094               var cap = this.rules.block.def.exec(src);
36095
36096               if (cap) {
36097                 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
36098                 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
36099                 return {
36100                   tag: tag,
36101                   raw: cap[0],
36102                   href: cap[2],
36103                   title: cap[3]
36104                 };
36105               }
36106             }
36107           }, {
36108             key: "table",
36109             value: function table(src) {
36110               var cap = this.rules.block.table.exec(src);
36111
36112               if (cap) {
36113                 var item = {
36114                   type: 'table',
36115                   header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')),
36116                   align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
36117                   cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
36118                 };
36119
36120                 if (item.header.length === item.align.length) {
36121                   item.raw = cap[0];
36122                   var l = item.align.length;
36123                   var i;
36124
36125                   for (i = 0; i < l; i++) {
36126                     if (/^ *-+: *$/.test(item.align[i])) {
36127                       item.align[i] = 'right';
36128                     } else if (/^ *:-+: *$/.test(item.align[i])) {
36129                       item.align[i] = 'center';
36130                     } else if (/^ *:-+ *$/.test(item.align[i])) {
36131                       item.align[i] = 'left';
36132                     } else {
36133                       item.align[i] = null;
36134                     }
36135                   }
36136
36137                   l = item.cells.length;
36138
36139                   for (i = 0; i < l; i++) {
36140                     item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
36141                   }
36142
36143                   return item;
36144                 }
36145               }
36146             }
36147           }, {
36148             key: "lheading",
36149             value: function lheading(src) {
36150               var cap = this.rules.block.lheading.exec(src);
36151
36152               if (cap) {
36153                 return {
36154                   type: 'heading',
36155                   raw: cap[0],
36156                   depth: cap[2].charAt(0) === '=' ? 1 : 2,
36157                   text: cap[1]
36158                 };
36159               }
36160             }
36161           }, {
36162             key: "paragraph",
36163             value: function paragraph(src) {
36164               var cap = this.rules.block.paragraph.exec(src);
36165
36166               if (cap) {
36167                 return {
36168                   type: 'paragraph',
36169                   raw: cap[0],
36170                   text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
36171                 };
36172               }
36173             }
36174           }, {
36175             key: "text",
36176             value: function text(src, tokens) {
36177               var cap = this.rules.block.text.exec(src);
36178
36179               if (cap) {
36180                 var lastToken = tokens[tokens.length - 1];
36181
36182                 if (lastToken && lastToken.type === 'text') {
36183                   return {
36184                     raw: cap[0],
36185                     text: cap[0]
36186                   };
36187                 }
36188
36189                 return {
36190                   type: 'text',
36191                   raw: cap[0],
36192                   text: cap[0]
36193                 };
36194               }
36195             }
36196           }, {
36197             key: "escape",
36198             value: function escape(src) {
36199               var cap = this.rules.inline.escape.exec(src);
36200
36201               if (cap) {
36202                 return {
36203                   type: 'escape',
36204                   raw: cap[0],
36205                   text: _escape(cap[1])
36206                 };
36207               }
36208             }
36209           }, {
36210             key: "tag",
36211             value: function tag(src, inLink, inRawBlock) {
36212               var cap = this.rules.inline.tag.exec(src);
36213
36214               if (cap) {
36215                 if (!inLink && /^<a /i.test(cap[0])) {
36216                   inLink = true;
36217                 } else if (inLink && /^<\/a>/i.test(cap[0])) {
36218                   inLink = false;
36219                 }
36220
36221                 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36222                   inRawBlock = true;
36223                 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
36224                   inRawBlock = false;
36225                 }
36226
36227                 return {
36228                   type: this.options.sanitize ? 'text' : 'html',
36229                   raw: cap[0],
36230                   inLink: inLink,
36231                   inRawBlock: inRawBlock,
36232                   text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
36233                 };
36234               }
36235             }
36236           }, {
36237             key: "link",
36238             value: function link(src) {
36239               var cap = this.rules.inline.link.exec(src);
36240
36241               if (cap) {
36242                 var lastParenIndex = findClosingBracket$1(cap[2], '()');
36243
36244                 if (lastParenIndex > -1) {
36245                   var start = cap[0].indexOf('!') === 0 ? 5 : 4;
36246                   var linkLen = start + cap[1].length + lastParenIndex;
36247                   cap[2] = cap[2].substring(0, lastParenIndex);
36248                   cap[0] = cap[0].substring(0, linkLen).trim();
36249                   cap[3] = '';
36250                 }
36251
36252                 var href = cap[2];
36253                 var title = '';
36254
36255                 if (this.options.pedantic) {
36256                   var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
36257
36258                   if (link) {
36259                     href = link[1];
36260                     title = link[3];
36261                   } else {
36262                     title = '';
36263                   }
36264                 } else {
36265                   title = cap[3] ? cap[3].slice(1, -1) : '';
36266                 }
36267
36268                 href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
36269                 var token = outputLink(cap, {
36270                   href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
36271                   title: title ? title.replace(this.rules.inline._escapes, '$1') : title
36272                 }, cap[0]);
36273                 return token;
36274               }
36275             }
36276           }, {
36277             key: "reflink",
36278             value: function reflink(src, links) {
36279               var cap;
36280
36281               if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
36282                 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
36283                 link = links[link.toLowerCase()];
36284
36285                 if (!link || !link.href) {
36286                   var text = cap[0].charAt(0);
36287                   return {
36288                     type: 'text',
36289                     raw: text,
36290                     text: text
36291                   };
36292                 }
36293
36294                 var token = outputLink(cap, link, cap[0]);
36295                 return token;
36296               }
36297             }
36298           }, {
36299             key: "strong",
36300             value: function strong(src, maskedSrc) {
36301               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36302               var match = this.rules.inline.strong.start.exec(src);
36303
36304               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36305                 maskedSrc = maskedSrc.slice(-1 * src.length);
36306                 var endReg = match[0] === '**' ? this.rules.inline.strong.endAst : this.rules.inline.strong.endUnd;
36307                 endReg.lastIndex = 0;
36308                 var cap;
36309
36310                 while ((match = endReg.exec(maskedSrc)) != null) {
36311                   cap = this.rules.inline.strong.middle.exec(maskedSrc.slice(0, match.index + 3));
36312
36313                   if (cap) {
36314                     return {
36315                       type: 'strong',
36316                       raw: src.slice(0, cap[0].length),
36317                       text: src.slice(2, cap[0].length - 2)
36318                     };
36319                   }
36320                 }
36321               }
36322             }
36323           }, {
36324             key: "em",
36325             value: function em(src, maskedSrc) {
36326               var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
36327               var match = this.rules.inline.em.start.exec(src);
36328
36329               if (match && (!match[1] || match[1] && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
36330                 maskedSrc = maskedSrc.slice(-1 * src.length);
36331                 var endReg = match[0] === '*' ? this.rules.inline.em.endAst : this.rules.inline.em.endUnd;
36332                 endReg.lastIndex = 0;
36333                 var cap;
36334
36335                 while ((match = endReg.exec(maskedSrc)) != null) {
36336                   cap = this.rules.inline.em.middle.exec(maskedSrc.slice(0, match.index + 2));
36337
36338                   if (cap) {
36339                     return {
36340                       type: 'em',
36341                       raw: src.slice(0, cap[0].length),
36342                       text: src.slice(1, cap[0].length - 1)
36343                     };
36344                   }
36345                 }
36346               }
36347             }
36348           }, {
36349             key: "codespan",
36350             value: function codespan(src) {
36351               var cap = this.rules.inline.code.exec(src);
36352
36353               if (cap) {
36354                 var text = cap[2].replace(/\n/g, ' ');
36355                 var hasNonSpaceChars = /[^ ]/.test(text);
36356                 var hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
36357
36358                 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
36359                   text = text.substring(1, text.length - 1);
36360                 }
36361
36362                 text = _escape(text, true);
36363                 return {
36364                   type: 'codespan',
36365                   raw: cap[0],
36366                   text: text
36367                 };
36368               }
36369             }
36370           }, {
36371             key: "br",
36372             value: function br(src) {
36373               var cap = this.rules.inline.br.exec(src);
36374
36375               if (cap) {
36376                 return {
36377                   type: 'br',
36378                   raw: cap[0]
36379                 };
36380               }
36381             }
36382           }, {
36383             key: "del",
36384             value: function del(src) {
36385               var cap = this.rules.inline.del.exec(src);
36386
36387               if (cap) {
36388                 return {
36389                   type: 'del',
36390                   raw: cap[0],
36391                   text: cap[1]
36392                 };
36393               }
36394             }
36395           }, {
36396             key: "autolink",
36397             value: function autolink(src, mangle) {
36398               var cap = this.rules.inline.autolink.exec(src);
36399
36400               if (cap) {
36401                 var text, href;
36402
36403                 if (cap[2] === '@') {
36404                   text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
36405                   href = 'mailto:' + text;
36406                 } else {
36407                   text = _escape(cap[1]);
36408                   href = text;
36409                 }
36410
36411                 return {
36412                   type: 'link',
36413                   raw: cap[0],
36414                   text: text,
36415                   href: href,
36416                   tokens: [{
36417                     type: 'text',
36418                     raw: text,
36419                     text: text
36420                   }]
36421                 };
36422               }
36423             }
36424           }, {
36425             key: "url",
36426             value: function url(src, mangle) {
36427               var cap;
36428
36429               if (cap = this.rules.inline.url.exec(src)) {
36430                 var text, href;
36431
36432                 if (cap[2] === '@') {
36433                   text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
36434                   href = 'mailto:' + text;
36435                 } else {
36436                   // do extended autolink path validation
36437                   var prevCapZero;
36438
36439                   do {
36440                     prevCapZero = cap[0];
36441                     cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
36442                   } while (prevCapZero !== cap[0]);
36443
36444                   text = _escape(cap[0]);
36445
36446                   if (cap[1] === 'www.') {
36447                     href = 'http://' + text;
36448                   } else {
36449                     href = text;
36450                   }
36451                 }
36452
36453                 return {
36454                   type: 'link',
36455                   raw: cap[0],
36456                   text: text,
36457                   href: href,
36458                   tokens: [{
36459                     type: 'text',
36460                     raw: text,
36461                     text: text
36462                   }]
36463                 };
36464               }
36465             }
36466           }, {
36467             key: "inlineText",
36468             value: function inlineText(src, inRawBlock, smartypants) {
36469               var cap = this.rules.inline.text.exec(src);
36470
36471               if (cap) {
36472                 var text;
36473
36474                 if (inRawBlock) {
36475                   text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
36476                 } else {
36477                   text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
36478                 }
36479
36480                 return {
36481                   type: 'text',
36482                   raw: cap[0],
36483                   text: text
36484                 };
36485               }
36486             }
36487           }]);
36488
36489           return Tokenizer;
36490         }();
36491
36492         var noopTest$1 = helpers.noopTest,
36493             edit$1 = helpers.edit,
36494             merge$2 = helpers.merge;
36495         /**
36496          * Block-Level Grammar
36497          */
36498
36499         var block = {
36500           newline: /^\n+/,
36501           code: /^( {4}[^\n]+\n*)+/,
36502           fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
36503           hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
36504           heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
36505           blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
36506           list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
36507           html: '^ {0,3}(?:' // optional indentation
36508           + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
36509           + '|comment[^\\n]*(\\n+|$)' // (2)
36510           + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
36511           + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
36512           + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
36513           + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
36514           + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
36515           + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
36516           + ')',
36517           def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
36518           nptable: noopTest$1,
36519           table: noopTest$1,
36520           lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
36521           // regex template, placeholders will be replaced according to different paragraph
36522           // interruption rules of commonmark and the original markdown spec:
36523           _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
36524           text: /^[^\n]+/
36525         };
36526         block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
36527         block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
36528         block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex();
36529         block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
36530         block.item = /^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/;
36531         block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex();
36532         block.listItemStart = edit$1(/^( *)(bull)/).replace('bull', block.bullet).getRegex();
36533         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();
36534         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';
36535         block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
36536         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();
36537         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
36538         .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
36539         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
36540         .getRegex();
36541         block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex();
36542         /**
36543          * Normal Block Grammar
36544          */
36545
36546         block.normal = merge$2({}, block);
36547         /**
36548          * GFM Block Grammar
36549          */
36550
36551         block.gfm = merge$2({}, block.normal, {
36552           nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
36553           + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
36554           + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
36555           // Cells
36556           table: '^ *\\|(.+)\\n' // Header
36557           + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
36558           + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
36559
36560         });
36561         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
36562         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36563         .getRegex();
36564         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
36565         .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
36566         .getRegex();
36567         /**
36568          * Pedantic grammar (original John Gruber's loose markdown specification)
36569          */
36570
36571         block.pedantic = merge$2({}, block.normal, {
36572           html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
36573           + '|<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(),
36574           def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
36575           heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
36576           fences: noopTest$1,
36577           // fences not supported
36578           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()
36579         });
36580         /**
36581          * Inline-Level Grammar
36582          */
36583
36584         var inline = {
36585           escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
36586           autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
36587           url: noopTest$1,
36588           tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
36589           + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
36590           + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
36591           + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
36592           + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
36593           // CDATA section
36594           link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
36595           reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
36596           nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
36597           reflinkSearch: 'reflink|nolink(?!\\()',
36598           strong: {
36599             start: /^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,
36600             // (1) returns if starts w/ punctuation
36601             middle: /^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,
36602             endAst: /[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36603             // last char can't be punct, or final * must also be followed by punct (or endline)
36604             endUnd: /[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36605
36606           },
36607           em: {
36608             start: /^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,
36609             // (1) returns if starts w/ punctuation
36610             middle: /^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,
36611             endAst: /[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,
36612             // last char can't be punct, or final * must also be followed by punct (or endline)
36613             endUnd: /[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/ // last char can't be a space, and final _ must preceed punct or \s (or endline)
36614
36615           },
36616           code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
36617           br: /^( {2,}|\\)\n(?!\s*$)/,
36618           del: noopTest$1,
36619           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,
36620           punctuation: /^([\s*punctuation])/
36621         }; // list of punctuation marks from common mark spec
36622         // without * and _ to workaround cases with double emphasis
36623
36624         inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
36625         inline.punctuation = edit$1(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
36626
36627         inline._blockSkip = '\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>';
36628         inline._overlapSkip = '__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*';
36629         inline._comment = edit$1(block._comment).replace('(?:-->|$)', '-->').getRegex();
36630         inline.em.start = edit$1(inline.em.start).replace(/punctuation/g, inline._punctuation).getRegex();
36631         inline.em.middle = edit$1(inline.em.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36632         inline.em.endAst = edit$1(inline.em.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36633         inline.em.endUnd = edit$1(inline.em.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36634         inline.strong.start = edit$1(inline.strong.start).replace(/punctuation/g, inline._punctuation).getRegex();
36635         inline.strong.middle = edit$1(inline.strong.middle).replace(/punctuation/g, inline._punctuation).replace(/overlapSkip/g, inline._overlapSkip).getRegex();
36636         inline.strong.endAst = edit$1(inline.strong.endAst, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36637         inline.strong.endUnd = edit$1(inline.strong.endUnd, 'g').replace(/punctuation/g, inline._punctuation).getRegex();
36638         inline.blockSkip = edit$1(inline._blockSkip, 'g').getRegex();
36639         inline.overlapSkip = edit$1(inline._overlapSkip, 'g').getRegex();
36640         inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
36641         inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
36642         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])?)+(?![-_])/;
36643         inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex();
36644         inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
36645         inline.tag = edit$1(inline.tag).replace('comment', inline._comment).replace('attribute', inline._attribute).getRegex();
36646         inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
36647         inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
36648         inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
36649         inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex();
36650         inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex();
36651         inline.reflinkSearch = edit$1(inline.reflinkSearch, 'g').replace('reflink', inline.reflink).replace('nolink', inline.nolink).getRegex();
36652         /**
36653          * Normal Inline Grammar
36654          */
36655
36656         inline.normal = merge$2({}, inline);
36657         /**
36658          * Pedantic Inline Grammar
36659          */
36660
36661         inline.pedantic = merge$2({}, inline.normal, {
36662           strong: {
36663             start: /^__|\*\*/,
36664             middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
36665             endAst: /\*\*(?!\*)/g,
36666             endUnd: /__(?!_)/g
36667           },
36668           em: {
36669             start: /^_|\*/,
36670             middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
36671             endAst: /\*(?!\*)/g,
36672             endUnd: /_(?!_)/g
36673           },
36674           link: edit$1(/^!?\[(label)\]\((.*?)\)/).replace('label', inline._label).getRegex(),
36675           reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline._label).getRegex()
36676         });
36677         /**
36678          * GFM Inline Grammar
36679          */
36680
36681         inline.gfm = merge$2({}, inline.normal, {
36682           escape: edit$1(inline.escape).replace('])', '~|])').getRegex(),
36683           _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
36684           url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
36685           _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
36686           del: /^~+(?=\S)([\s\S]*?\S)~+/,
36687           text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
36688         });
36689         inline.gfm.url = edit$1(inline.gfm.url, 'i').replace('email', inline.gfm._extended_email).getRegex();
36690         /**
36691          * GFM + Line Breaks Inline Grammar
36692          */
36693
36694         inline.breaks = merge$2({}, inline.gfm, {
36695           br: edit$1(inline.br).replace('{2,}', '*').getRegex(),
36696           text: edit$1(inline.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
36697         });
36698         var rules = {
36699           block: block,
36700           inline: inline
36701         };
36702
36703         var defaults$2 = defaults.defaults;
36704         var block$1 = rules.block,
36705             inline$1 = rules.inline;
36706         var repeatString$1 = helpers.repeatString;
36707         /**
36708          * smartypants text replacement
36709          */
36710
36711         function smartypants(text) {
36712           return text // em-dashes
36713           .replace(/---/g, "\u2014") // en-dashes
36714           .replace(/--/g, "\u2013") // opening singles
36715           .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
36716           .replace(/'/g, "\u2019") // opening doubles
36717           .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
36718           .replace(/"/g, "\u201D") // ellipses
36719           .replace(/\.{3}/g, "\u2026");
36720         }
36721         /**
36722          * mangle email addresses
36723          */
36724
36725
36726         function mangle(text) {
36727           var out = '',
36728               i,
36729               ch;
36730           var l = text.length;
36731
36732           for (i = 0; i < l; i++) {
36733             ch = text.charCodeAt(i);
36734
36735             if (Math.random() > 0.5) {
36736               ch = 'x' + ch.toString(16);
36737             }
36738
36739             out += '&#' + ch + ';';
36740           }
36741
36742           return out;
36743         }
36744         /**
36745          * Block Lexer
36746          */
36747
36748
36749         var Lexer_1 = /*#__PURE__*/function () {
36750           function Lexer(options) {
36751             _classCallCheck(this, Lexer);
36752
36753             this.tokens = [];
36754             this.tokens.links = Object.create(null);
36755             this.options = options || defaults$2;
36756             this.options.tokenizer = this.options.tokenizer || new Tokenizer_1();
36757             this.tokenizer = this.options.tokenizer;
36758             this.tokenizer.options = this.options;
36759             var rules = {
36760               block: block$1.normal,
36761               inline: inline$1.normal
36762             };
36763
36764             if (this.options.pedantic) {
36765               rules.block = block$1.pedantic;
36766               rules.inline = inline$1.pedantic;
36767             } else if (this.options.gfm) {
36768               rules.block = block$1.gfm;
36769
36770               if (this.options.breaks) {
36771                 rules.inline = inline$1.breaks;
36772               } else {
36773                 rules.inline = inline$1.gfm;
36774               }
36775             }
36776
36777             this.tokenizer.rules = rules;
36778           }
36779           /**
36780            * Expose Rules
36781            */
36782
36783
36784           _createClass(Lexer, [{
36785             key: "lex",
36786
36787             /**
36788              * Preprocessing
36789              */
36790             value: function lex(src) {
36791               src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, '    ');
36792               this.blockTokens(src, this.tokens, true);
36793               this.inline(this.tokens);
36794               return this.tokens;
36795             }
36796             /**
36797              * Lexing
36798              */
36799
36800           }, {
36801             key: "blockTokens",
36802             value: function blockTokens(src) {
36803               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
36804               var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
36805               src = src.replace(/^ +$/gm, '');
36806               var token, i, l, lastToken;
36807
36808               while (src) {
36809                 // newline
36810                 if (token = this.tokenizer.space(src)) {
36811                   src = src.substring(token.raw.length);
36812
36813                   if (token.type) {
36814                     tokens.push(token);
36815                   }
36816
36817                   continue;
36818                 } // code
36819
36820
36821                 if (token = this.tokenizer.code(src, tokens)) {
36822                   src = src.substring(token.raw.length);
36823
36824                   if (token.type) {
36825                     tokens.push(token);
36826                   } else {
36827                     lastToken = tokens[tokens.length - 1];
36828                     lastToken.raw += '\n' + token.raw;
36829                     lastToken.text += '\n' + token.text;
36830                   }
36831
36832                   continue;
36833                 } // fences
36834
36835
36836                 if (token = this.tokenizer.fences(src)) {
36837                   src = src.substring(token.raw.length);
36838                   tokens.push(token);
36839                   continue;
36840                 } // heading
36841
36842
36843                 if (token = this.tokenizer.heading(src)) {
36844                   src = src.substring(token.raw.length);
36845                   tokens.push(token);
36846                   continue;
36847                 } // table no leading pipe (gfm)
36848
36849
36850                 if (token = this.tokenizer.nptable(src)) {
36851                   src = src.substring(token.raw.length);
36852                   tokens.push(token);
36853                   continue;
36854                 } // hr
36855
36856
36857                 if (token = this.tokenizer.hr(src)) {
36858                   src = src.substring(token.raw.length);
36859                   tokens.push(token);
36860                   continue;
36861                 } // blockquote
36862
36863
36864                 if (token = this.tokenizer.blockquote(src)) {
36865                   src = src.substring(token.raw.length);
36866                   token.tokens = this.blockTokens(token.text, [], top);
36867                   tokens.push(token);
36868                   continue;
36869                 } // list
36870
36871
36872                 if (token = this.tokenizer.list(src)) {
36873                   src = src.substring(token.raw.length);
36874                   l = token.items.length;
36875
36876                   for (i = 0; i < l; i++) {
36877                     token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
36878                   }
36879
36880                   tokens.push(token);
36881                   continue;
36882                 } // html
36883
36884
36885                 if (token = this.tokenizer.html(src)) {
36886                   src = src.substring(token.raw.length);
36887                   tokens.push(token);
36888                   continue;
36889                 } // def
36890
36891
36892                 if (top && (token = this.tokenizer.def(src))) {
36893                   src = src.substring(token.raw.length);
36894
36895                   if (!this.tokens.links[token.tag]) {
36896                     this.tokens.links[token.tag] = {
36897                       href: token.href,
36898                       title: token.title
36899                     };
36900                   }
36901
36902                   continue;
36903                 } // table (gfm)
36904
36905
36906                 if (token = this.tokenizer.table(src)) {
36907                   src = src.substring(token.raw.length);
36908                   tokens.push(token);
36909                   continue;
36910                 } // lheading
36911
36912
36913                 if (token = this.tokenizer.lheading(src)) {
36914                   src = src.substring(token.raw.length);
36915                   tokens.push(token);
36916                   continue;
36917                 } // top-level paragraph
36918
36919
36920                 if (top && (token = this.tokenizer.paragraph(src))) {
36921                   src = src.substring(token.raw.length);
36922                   tokens.push(token);
36923                   continue;
36924                 } // text
36925
36926
36927                 if (token = this.tokenizer.text(src, tokens)) {
36928                   src = src.substring(token.raw.length);
36929
36930                   if (token.type) {
36931                     tokens.push(token);
36932                   } else {
36933                     lastToken = tokens[tokens.length - 1];
36934                     lastToken.raw += '\n' + token.raw;
36935                     lastToken.text += '\n' + token.text;
36936                   }
36937
36938                   continue;
36939                 }
36940
36941                 if (src) {
36942                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
36943
36944                   if (this.options.silent) {
36945                     console.error(errMsg);
36946                     break;
36947                   } else {
36948                     throw new Error(errMsg);
36949                   }
36950                 }
36951               }
36952
36953               return tokens;
36954             }
36955           }, {
36956             key: "inline",
36957             value: function inline(tokens) {
36958               var i, j, k, l2, row, token;
36959               var l = tokens.length;
36960
36961               for (i = 0; i < l; i++) {
36962                 token = tokens[i];
36963
36964                 switch (token.type) {
36965                   case 'paragraph':
36966                   case 'text':
36967                   case 'heading':
36968                     {
36969                       token.tokens = [];
36970                       this.inlineTokens(token.text, token.tokens);
36971                       break;
36972                     }
36973
36974                   case 'table':
36975                     {
36976                       token.tokens = {
36977                         header: [],
36978                         cells: []
36979                       }; // header
36980
36981                       l2 = token.header.length;
36982
36983                       for (j = 0; j < l2; j++) {
36984                         token.tokens.header[j] = [];
36985                         this.inlineTokens(token.header[j], token.tokens.header[j]);
36986                       } // cells
36987
36988
36989                       l2 = token.cells.length;
36990
36991                       for (j = 0; j < l2; j++) {
36992                         row = token.cells[j];
36993                         token.tokens.cells[j] = [];
36994
36995                         for (k = 0; k < row.length; k++) {
36996                           token.tokens.cells[j][k] = [];
36997                           this.inlineTokens(row[k], token.tokens.cells[j][k]);
36998                         }
36999                       }
37000
37001                       break;
37002                     }
37003
37004                   case 'blockquote':
37005                     {
37006                       this.inline(token.tokens);
37007                       break;
37008                     }
37009
37010                   case 'list':
37011                     {
37012                       l2 = token.items.length;
37013
37014                       for (j = 0; j < l2; j++) {
37015                         this.inline(token.items[j].tokens);
37016                       }
37017
37018                       break;
37019                     }
37020                 }
37021               }
37022
37023               return tokens;
37024             }
37025             /**
37026              * Lexing/Compiling
37027              */
37028
37029           }, {
37030             key: "inlineTokens",
37031             value: function inlineTokens(src) {
37032               var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
37033               var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
37034               var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
37035               var prevChar = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : '';
37036               var token; // String with links masked to avoid interference with em and strong
37037
37038               var maskedSrc = src;
37039               var match; // Mask out reflinks
37040
37041               if (this.tokens.links) {
37042                 var links = Object.keys(this.tokens.links);
37043
37044                 if (links.length > 0) {
37045                   while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
37046                     if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
37047                       maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
37048                     }
37049                   }
37050                 }
37051               } // Mask out other blocks
37052
37053
37054               while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
37055                 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString$1('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
37056               }
37057
37058               while (src) {
37059                 // escape
37060                 if (token = this.tokenizer.escape(src)) {
37061                   src = src.substring(token.raw.length);
37062                   tokens.push(token);
37063                   continue;
37064                 } // tag
37065
37066
37067                 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
37068                   src = src.substring(token.raw.length);
37069                   inLink = token.inLink;
37070                   inRawBlock = token.inRawBlock;
37071                   tokens.push(token);
37072                   continue;
37073                 } // link
37074
37075
37076                 if (token = this.tokenizer.link(src)) {
37077                   src = src.substring(token.raw.length);
37078
37079                   if (token.type === 'link') {
37080                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
37081                   }
37082
37083                   tokens.push(token);
37084                   continue;
37085                 } // reflink, nolink
37086
37087
37088                 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
37089                   src = src.substring(token.raw.length);
37090
37091                   if (token.type === 'link') {
37092                     token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
37093                   }
37094
37095                   tokens.push(token);
37096                   continue;
37097                 } // strong
37098
37099
37100                 if (token = this.tokenizer.strong(src, maskedSrc, prevChar)) {
37101                   src = src.substring(token.raw.length);
37102                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37103                   tokens.push(token);
37104                   continue;
37105                 } // em
37106
37107
37108                 if (token = this.tokenizer.em(src, maskedSrc, prevChar)) {
37109                   src = src.substring(token.raw.length);
37110                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37111                   tokens.push(token);
37112                   continue;
37113                 } // code
37114
37115
37116                 if (token = this.tokenizer.codespan(src)) {
37117                   src = src.substring(token.raw.length);
37118                   tokens.push(token);
37119                   continue;
37120                 } // br
37121
37122
37123                 if (token = this.tokenizer.br(src)) {
37124                   src = src.substring(token.raw.length);
37125                   tokens.push(token);
37126                   continue;
37127                 } // del (gfm)
37128
37129
37130                 if (token = this.tokenizer.del(src)) {
37131                   src = src.substring(token.raw.length);
37132                   token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
37133                   tokens.push(token);
37134                   continue;
37135                 } // autolink
37136
37137
37138                 if (token = this.tokenizer.autolink(src, mangle)) {
37139                   src = src.substring(token.raw.length);
37140                   tokens.push(token);
37141                   continue;
37142                 } // url (gfm)
37143
37144
37145                 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
37146                   src = src.substring(token.raw.length);
37147                   tokens.push(token);
37148                   continue;
37149                 } // text
37150
37151
37152                 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
37153                   src = src.substring(token.raw.length);
37154                   prevChar = token.raw.slice(-1);
37155                   tokens.push(token);
37156                   continue;
37157                 }
37158
37159                 if (src) {
37160                   var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
37161
37162                   if (this.options.silent) {
37163                     console.error(errMsg);
37164                     break;
37165                   } else {
37166                     throw new Error(errMsg);
37167                   }
37168                 }
37169               }
37170
37171               return tokens;
37172             }
37173           }], [{
37174             key: "lex",
37175
37176             /**
37177              * Static Lex Method
37178              */
37179             value: function lex(src, options) {
37180               var lexer = new Lexer(options);
37181               return lexer.lex(src);
37182             }
37183             /**
37184              * Static Lex Inline Method
37185              */
37186
37187           }, {
37188             key: "lexInline",
37189             value: function lexInline(src, options) {
37190               var lexer = new Lexer(options);
37191               return lexer.inlineTokens(src);
37192             }
37193           }, {
37194             key: "rules",
37195             get: function get() {
37196               return {
37197                 block: block$1,
37198                 inline: inline$1
37199               };
37200             }
37201           }]);
37202
37203           return Lexer;
37204         }();
37205
37206         var defaults$3 = defaults.defaults;
37207         var cleanUrl$1 = helpers.cleanUrl,
37208             escape$2 = helpers.escape;
37209         /**
37210          * Renderer
37211          */
37212
37213         var Renderer_1 = /*#__PURE__*/function () {
37214           function Renderer(options) {
37215             _classCallCheck(this, Renderer);
37216
37217             this.options = options || defaults$3;
37218           }
37219
37220           _createClass(Renderer, [{
37221             key: "code",
37222             value: function code(_code, infostring, escaped) {
37223               var lang = (infostring || '').match(/\S*/)[0];
37224
37225               if (this.options.highlight) {
37226                 var out = this.options.highlight(_code, lang);
37227
37228                 if (out != null && out !== _code) {
37229                   escaped = true;
37230                   _code = out;
37231                 }
37232               }
37233
37234               if (!lang) {
37235                 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37236               }
37237
37238               return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
37239             }
37240           }, {
37241             key: "blockquote",
37242             value: function blockquote(quote) {
37243               return '<blockquote>\n' + quote + '</blockquote>\n';
37244             }
37245           }, {
37246             key: "html",
37247             value: function html(_html) {
37248               return _html;
37249             }
37250           }, {
37251             key: "heading",
37252             value: function heading(text, level, raw, slugger) {
37253               if (this.options.headerIds) {
37254                 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
37255               } // ignore IDs
37256
37257
37258               return '<h' + level + '>' + text + '</h' + level + '>\n';
37259             }
37260           }, {
37261             key: "hr",
37262             value: function hr() {
37263               return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
37264             }
37265           }, {
37266             key: "list",
37267             value: function list(body, ordered, start) {
37268               var type = ordered ? 'ol' : 'ul',
37269                   startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
37270               return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
37271             }
37272           }, {
37273             key: "listitem",
37274             value: function listitem(text) {
37275               return '<li>' + text + '</li>\n';
37276             }
37277           }, {
37278             key: "checkbox",
37279             value: function checkbox(checked) {
37280               return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
37281             }
37282           }, {
37283             key: "paragraph",
37284             value: function paragraph(text) {
37285               return '<p>' + text + '</p>\n';
37286             }
37287           }, {
37288             key: "table",
37289             value: function table(header, body) {
37290               if (body) body = '<tbody>' + body + '</tbody>';
37291               return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
37292             }
37293           }, {
37294             key: "tablerow",
37295             value: function tablerow(content) {
37296               return '<tr>\n' + content + '</tr>\n';
37297             }
37298           }, {
37299             key: "tablecell",
37300             value: function tablecell(content, flags) {
37301               var type = flags.header ? 'th' : 'td';
37302               var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
37303               return tag + content + '</' + type + '>\n';
37304             } // span level renderer
37305
37306           }, {
37307             key: "strong",
37308             value: function strong(text) {
37309               return '<strong>' + text + '</strong>';
37310             }
37311           }, {
37312             key: "em",
37313             value: function em(text) {
37314               return '<em>' + text + '</em>';
37315             }
37316           }, {
37317             key: "codespan",
37318             value: function codespan(text) {
37319               return '<code>' + text + '</code>';
37320             }
37321           }, {
37322             key: "br",
37323             value: function br() {
37324               return this.options.xhtml ? '<br/>' : '<br>';
37325             }
37326           }, {
37327             key: "del",
37328             value: function del(text) {
37329               return '<del>' + text + '</del>';
37330             }
37331           }, {
37332             key: "link",
37333             value: function link(href, title, text) {
37334               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37335
37336               if (href === null) {
37337                 return text;
37338               }
37339
37340               var out = '<a href="' + escape$2(href) + '"';
37341
37342               if (title) {
37343                 out += ' title="' + title + '"';
37344               }
37345
37346               out += '>' + text + '</a>';
37347               return out;
37348             }
37349           }, {
37350             key: "image",
37351             value: function image(href, title, text) {
37352               href = cleanUrl$1(this.options.sanitize, this.options.baseUrl, href);
37353
37354               if (href === null) {
37355                 return text;
37356               }
37357
37358               var out = '<img src="' + href + '" alt="' + text + '"';
37359
37360               if (title) {
37361                 out += ' title="' + title + '"';
37362               }
37363
37364               out += this.options.xhtml ? '/>' : '>';
37365               return out;
37366             }
37367           }, {
37368             key: "text",
37369             value: function text(_text) {
37370               return _text;
37371             }
37372           }]);
37373
37374           return Renderer;
37375         }();
37376
37377         /**
37378          * TextRenderer
37379          * returns only the textual part of the token
37380          */
37381         var TextRenderer_1 = /*#__PURE__*/function () {
37382           function TextRenderer() {
37383             _classCallCheck(this, TextRenderer);
37384           }
37385
37386           _createClass(TextRenderer, [{
37387             key: "strong",
37388             // no need for block level renderers
37389             value: function strong(text) {
37390               return text;
37391             }
37392           }, {
37393             key: "em",
37394             value: function em(text) {
37395               return text;
37396             }
37397           }, {
37398             key: "codespan",
37399             value: function codespan(text) {
37400               return text;
37401             }
37402           }, {
37403             key: "del",
37404             value: function del(text) {
37405               return text;
37406             }
37407           }, {
37408             key: "html",
37409             value: function html(text) {
37410               return text;
37411             }
37412           }, {
37413             key: "text",
37414             value: function text(_text) {
37415               return _text;
37416             }
37417           }, {
37418             key: "link",
37419             value: function link(href, title, text) {
37420               return '' + text;
37421             }
37422           }, {
37423             key: "image",
37424             value: function image(href, title, text) {
37425               return '' + text;
37426             }
37427           }, {
37428             key: "br",
37429             value: function br() {
37430               return '';
37431             }
37432           }]);
37433
37434           return TextRenderer;
37435         }();
37436
37437         /**
37438          * Slugger generates header id
37439          */
37440         var Slugger_1 = /*#__PURE__*/function () {
37441           function Slugger() {
37442             _classCallCheck(this, Slugger);
37443
37444             this.seen = {};
37445           }
37446
37447           _createClass(Slugger, [{
37448             key: "serialize",
37449             value: function serialize(value) {
37450               return value.toLowerCase().trim() // remove html tags
37451               .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
37452               .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
37453             }
37454             /**
37455              * Finds the next safe (unique) slug to use
37456              */
37457
37458           }, {
37459             key: "getNextSafeSlug",
37460             value: function getNextSafeSlug(originalSlug, isDryRun) {
37461               var slug = originalSlug;
37462               var occurenceAccumulator = 0;
37463
37464               if (this.seen.hasOwnProperty(slug)) {
37465                 occurenceAccumulator = this.seen[originalSlug];
37466
37467                 do {
37468                   occurenceAccumulator++;
37469                   slug = originalSlug + '-' + occurenceAccumulator;
37470                 } while (this.seen.hasOwnProperty(slug));
37471               }
37472
37473               if (!isDryRun) {
37474                 this.seen[originalSlug] = occurenceAccumulator;
37475                 this.seen[slug] = 0;
37476               }
37477
37478               return slug;
37479             }
37480             /**
37481              * Convert string to unique id
37482              * @param {object} options
37483              * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
37484              */
37485
37486           }, {
37487             key: "slug",
37488             value: function slug(value) {
37489               var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
37490               var slug = this.serialize(value);
37491               return this.getNextSafeSlug(slug, options.dryrun);
37492             }
37493           }]);
37494
37495           return Slugger;
37496         }();
37497
37498         var defaults$4 = defaults.defaults;
37499         var unescape$2 = helpers.unescape;
37500         /**
37501          * Parsing & Compiling
37502          */
37503
37504         var Parser_1 = /*#__PURE__*/function () {
37505           function Parser(options) {
37506             _classCallCheck(this, Parser);
37507
37508             this.options = options || defaults$4;
37509             this.options.renderer = this.options.renderer || new Renderer_1();
37510             this.renderer = this.options.renderer;
37511             this.renderer.options = this.options;
37512             this.textRenderer = new TextRenderer_1();
37513             this.slugger = new Slugger_1();
37514           }
37515           /**
37516            * Static Parse Method
37517            */
37518
37519
37520           _createClass(Parser, [{
37521             key: "parse",
37522
37523             /**
37524              * Parse Loop
37525              */
37526             value: function parse(tokens) {
37527               var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
37528               var out = '',
37529                   i,
37530                   j,
37531                   k,
37532                   l2,
37533                   l3,
37534                   row,
37535                   cell,
37536                   header,
37537                   body,
37538                   token,
37539                   ordered,
37540                   start,
37541                   loose,
37542                   itemBody,
37543                   item,
37544                   checked,
37545                   task,
37546                   checkbox;
37547               var l = tokens.length;
37548
37549               for (i = 0; i < l; i++) {
37550                 token = tokens[i];
37551
37552                 switch (token.type) {
37553                   case 'space':
37554                     {
37555                       continue;
37556                     }
37557
37558                   case 'hr':
37559                     {
37560                       out += this.renderer.hr();
37561                       continue;
37562                     }
37563
37564                   case 'heading':
37565                     {
37566                       out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$2(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
37567                       continue;
37568                     }
37569
37570                   case 'code':
37571                     {
37572                       out += this.renderer.code(token.text, token.lang, token.escaped);
37573                       continue;
37574                     }
37575
37576                   case 'table':
37577                     {
37578                       header = ''; // header
37579
37580                       cell = '';
37581                       l2 = token.header.length;
37582
37583                       for (j = 0; j < l2; j++) {
37584                         cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
37585                           header: true,
37586                           align: token.align[j]
37587                         });
37588                       }
37589
37590                       header += this.renderer.tablerow(cell);
37591                       body = '';
37592                       l2 = token.cells.length;
37593
37594                       for (j = 0; j < l2; j++) {
37595                         row = token.tokens.cells[j];
37596                         cell = '';
37597                         l3 = row.length;
37598
37599                         for (k = 0; k < l3; k++) {
37600                           cell += this.renderer.tablecell(this.parseInline(row[k]), {
37601                             header: false,
37602                             align: token.align[k]
37603                           });
37604                         }
37605
37606                         body += this.renderer.tablerow(cell);
37607                       }
37608
37609                       out += this.renderer.table(header, body);
37610                       continue;
37611                     }
37612
37613                   case 'blockquote':
37614                     {
37615                       body = this.parse(token.tokens);
37616                       out += this.renderer.blockquote(body);
37617                       continue;
37618                     }
37619
37620                   case 'list':
37621                     {
37622                       ordered = token.ordered;
37623                       start = token.start;
37624                       loose = token.loose;
37625                       l2 = token.items.length;
37626                       body = '';
37627
37628                       for (j = 0; j < l2; j++) {
37629                         item = token.items[j];
37630                         checked = item.checked;
37631                         task = item.task;
37632                         itemBody = '';
37633
37634                         if (item.task) {
37635                           checkbox = this.renderer.checkbox(checked);
37636
37637                           if (loose) {
37638                             if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
37639                               item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
37640
37641                               if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
37642                                 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
37643                               }
37644                             } else {
37645                               item.tokens.unshift({
37646                                 type: 'text',
37647                                 text: checkbox
37648                               });
37649                             }
37650                           } else {
37651                             itemBody += checkbox;
37652                           }
37653                         }
37654
37655                         itemBody += this.parse(item.tokens, loose);
37656                         body += this.renderer.listitem(itemBody, task, checked);
37657                       }
37658
37659                       out += this.renderer.list(body, ordered, start);
37660                       continue;
37661                     }
37662
37663                   case 'html':
37664                     {
37665                       // TODO parse inline content if parameter markdown=1
37666                       out += this.renderer.html(token.text);
37667                       continue;
37668                     }
37669
37670                   case 'paragraph':
37671                     {
37672                       out += this.renderer.paragraph(this.parseInline(token.tokens));
37673                       continue;
37674                     }
37675
37676                   case 'text':
37677                     {
37678                       body = token.tokens ? this.parseInline(token.tokens) : token.text;
37679
37680                       while (i + 1 < l && tokens[i + 1].type === 'text') {
37681                         token = tokens[++i];
37682                         body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
37683                       }
37684
37685                       out += top ? this.renderer.paragraph(body) : body;
37686                       continue;
37687                     }
37688
37689                   default:
37690                     {
37691                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37692
37693                       if (this.options.silent) {
37694                         console.error(errMsg);
37695                         return;
37696                       } else {
37697                         throw new Error(errMsg);
37698                       }
37699                     }
37700                 }
37701               }
37702
37703               return out;
37704             }
37705             /**
37706              * Parse Inline Tokens
37707              */
37708
37709           }, {
37710             key: "parseInline",
37711             value: function parseInline(tokens, renderer) {
37712               renderer = renderer || this.renderer;
37713               var out = '',
37714                   i,
37715                   token;
37716               var l = tokens.length;
37717
37718               for (i = 0; i < l; i++) {
37719                 token = tokens[i];
37720
37721                 switch (token.type) {
37722                   case 'escape':
37723                     {
37724                       out += renderer.text(token.text);
37725                       break;
37726                     }
37727
37728                   case 'html':
37729                     {
37730                       out += renderer.html(token.text);
37731                       break;
37732                     }
37733
37734                   case 'link':
37735                     {
37736                       out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
37737                       break;
37738                     }
37739
37740                   case 'image':
37741                     {
37742                       out += renderer.image(token.href, token.title, token.text);
37743                       break;
37744                     }
37745
37746                   case 'strong':
37747                     {
37748                       out += renderer.strong(this.parseInline(token.tokens, renderer));
37749                       break;
37750                     }
37751
37752                   case 'em':
37753                     {
37754                       out += renderer.em(this.parseInline(token.tokens, renderer));
37755                       break;
37756                     }
37757
37758                   case 'codespan':
37759                     {
37760                       out += renderer.codespan(token.text);
37761                       break;
37762                     }
37763
37764                   case 'br':
37765                     {
37766                       out += renderer.br();
37767                       break;
37768                     }
37769
37770                   case 'del':
37771                     {
37772                       out += renderer.del(this.parseInline(token.tokens, renderer));
37773                       break;
37774                     }
37775
37776                   case 'text':
37777                     {
37778                       out += renderer.text(token.text);
37779                       break;
37780                     }
37781
37782                   default:
37783                     {
37784                       var errMsg = 'Token with "' + token.type + '" type was not found.';
37785
37786                       if (this.options.silent) {
37787                         console.error(errMsg);
37788                         return;
37789                       } else {
37790                         throw new Error(errMsg);
37791                       }
37792                     }
37793                 }
37794               }
37795
37796               return out;
37797             }
37798           }], [{
37799             key: "parse",
37800             value: function parse(tokens, options) {
37801               var parser = new Parser(options);
37802               return parser.parse(tokens);
37803             }
37804             /**
37805              * Static Parse Inline Method
37806              */
37807
37808           }, {
37809             key: "parseInline",
37810             value: function parseInline(tokens, options) {
37811               var parser = new Parser(options);
37812               return parser.parseInline(tokens);
37813             }
37814           }]);
37815
37816           return Parser;
37817         }();
37818
37819         var merge$3 = helpers.merge,
37820             checkSanitizeDeprecation$1 = helpers.checkSanitizeDeprecation,
37821             escape$3 = helpers.escape;
37822         var getDefaults = defaults.getDefaults,
37823             changeDefaults = defaults.changeDefaults,
37824             defaults$5 = defaults.defaults;
37825         /**
37826          * Marked
37827          */
37828
37829         function marked(src, opt, callback) {
37830           // throw error in case of non string input
37831           if (typeof src === 'undefined' || src === null) {
37832             throw new Error('marked(): input parameter is undefined or null');
37833           }
37834
37835           if (typeof src !== 'string') {
37836             throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
37837           }
37838
37839           if (typeof opt === 'function') {
37840             callback = opt;
37841             opt = null;
37842           }
37843
37844           opt = merge$3({}, marked.defaults, opt || {});
37845           checkSanitizeDeprecation$1(opt);
37846
37847           if (callback) {
37848             var highlight = opt.highlight;
37849             var tokens;
37850
37851             try {
37852               tokens = Lexer_1.lex(src, opt);
37853             } catch (e) {
37854               return callback(e);
37855             }
37856
37857             var done = function done(err) {
37858               var out;
37859
37860               if (!err) {
37861                 try {
37862                   out = Parser_1.parse(tokens, opt);
37863                 } catch (e) {
37864                   err = e;
37865                 }
37866               }
37867
37868               opt.highlight = highlight;
37869               return err ? callback(err) : callback(null, out);
37870             };
37871
37872             if (!highlight || highlight.length < 3) {
37873               return done();
37874             }
37875
37876             delete opt.highlight;
37877             if (!tokens.length) return done();
37878             var pending = 0;
37879             marked.walkTokens(tokens, function (token) {
37880               if (token.type === 'code') {
37881                 pending++;
37882                 setTimeout(function () {
37883                   highlight(token.text, token.lang, function (err, code) {
37884                     if (err) {
37885                       return done(err);
37886                     }
37887
37888                     if (code != null && code !== token.text) {
37889                       token.text = code;
37890                       token.escaped = true;
37891                     }
37892
37893                     pending--;
37894
37895                     if (pending === 0) {
37896                       done();
37897                     }
37898                   });
37899                 }, 0);
37900               }
37901             });
37902
37903             if (pending === 0) {
37904               done();
37905             }
37906
37907             return;
37908           }
37909
37910           try {
37911             var _tokens = Lexer_1.lex(src, opt);
37912
37913             if (opt.walkTokens) {
37914               marked.walkTokens(_tokens, opt.walkTokens);
37915             }
37916
37917             return Parser_1.parse(_tokens, opt);
37918           } catch (e) {
37919             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
37920
37921             if (opt.silent) {
37922               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
37923             }
37924
37925             throw e;
37926           }
37927         }
37928         /**
37929          * Options
37930          */
37931
37932
37933         marked.options = marked.setOptions = function (opt) {
37934           merge$3(marked.defaults, opt);
37935           changeDefaults(marked.defaults);
37936           return marked;
37937         };
37938
37939         marked.getDefaults = getDefaults;
37940         marked.defaults = defaults$5;
37941         /**
37942          * Use Extension
37943          */
37944
37945         marked.use = function (extension) {
37946           var opts = merge$3({}, extension);
37947
37948           if (extension.renderer) {
37949             (function () {
37950               var renderer = marked.defaults.renderer || new Renderer_1();
37951
37952               var _loop = function _loop(prop) {
37953                 var prevRenderer = renderer[prop];
37954
37955                 renderer[prop] = function () {
37956                   for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
37957                     args[_key] = arguments[_key];
37958                   }
37959
37960                   var ret = extension.renderer[prop].apply(renderer, args);
37961
37962                   if (ret === false) {
37963                     ret = prevRenderer.apply(renderer, args);
37964                   }
37965
37966                   return ret;
37967                 };
37968               };
37969
37970               for (var prop in extension.renderer) {
37971                 _loop(prop);
37972               }
37973
37974               opts.renderer = renderer;
37975             })();
37976           }
37977
37978           if (extension.tokenizer) {
37979             (function () {
37980               var tokenizer = marked.defaults.tokenizer || new Tokenizer_1();
37981
37982               var _loop2 = function _loop2(prop) {
37983                 var prevTokenizer = tokenizer[prop];
37984
37985                 tokenizer[prop] = function () {
37986                   for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
37987                     args[_key2] = arguments[_key2];
37988                   }
37989
37990                   var ret = extension.tokenizer[prop].apply(tokenizer, args);
37991
37992                   if (ret === false) {
37993                     ret = prevTokenizer.apply(tokenizer, args);
37994                   }
37995
37996                   return ret;
37997                 };
37998               };
37999
38000               for (var prop in extension.tokenizer) {
38001                 _loop2(prop);
38002               }
38003
38004               opts.tokenizer = tokenizer;
38005             })();
38006           }
38007
38008           if (extension.walkTokens) {
38009             var walkTokens = marked.defaults.walkTokens;
38010
38011             opts.walkTokens = function (token) {
38012               extension.walkTokens(token);
38013
38014               if (walkTokens) {
38015                 walkTokens(token);
38016               }
38017             };
38018           }
38019
38020           marked.setOptions(opts);
38021         };
38022         /**
38023          * Run callback for every token
38024          */
38025
38026
38027         marked.walkTokens = function (tokens, callback) {
38028           var _iterator = _createForOfIteratorHelper(tokens),
38029               _step;
38030
38031           try {
38032             for (_iterator.s(); !(_step = _iterator.n()).done;) {
38033               var token = _step.value;
38034               callback(token);
38035
38036               switch (token.type) {
38037                 case 'table':
38038                   {
38039                     var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
38040                         _step2;
38041
38042                     try {
38043                       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
38044                         var cell = _step2.value;
38045                         marked.walkTokens(cell, callback);
38046                       }
38047                     } catch (err) {
38048                       _iterator2.e(err);
38049                     } finally {
38050                       _iterator2.f();
38051                     }
38052
38053                     var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
38054                         _step3;
38055
38056                     try {
38057                       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
38058                         var row = _step3.value;
38059
38060                         var _iterator4 = _createForOfIteratorHelper(row),
38061                             _step4;
38062
38063                         try {
38064                           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
38065                             var _cell = _step4.value;
38066                             marked.walkTokens(_cell, callback);
38067                           }
38068                         } catch (err) {
38069                           _iterator4.e(err);
38070                         } finally {
38071                           _iterator4.f();
38072                         }
38073                       }
38074                     } catch (err) {
38075                       _iterator3.e(err);
38076                     } finally {
38077                       _iterator3.f();
38078                     }
38079
38080                     break;
38081                   }
38082
38083                 case 'list':
38084                   {
38085                     marked.walkTokens(token.items, callback);
38086                     break;
38087                   }
38088
38089                 default:
38090                   {
38091                     if (token.tokens) {
38092                       marked.walkTokens(token.tokens, callback);
38093                     }
38094                   }
38095               }
38096             }
38097           } catch (err) {
38098             _iterator.e(err);
38099           } finally {
38100             _iterator.f();
38101           }
38102         };
38103         /**
38104          * Parse Inline
38105          */
38106
38107
38108         marked.parseInline = function (src, opt) {
38109           // throw error in case of non string input
38110           if (typeof src === 'undefined' || src === null) {
38111             throw new Error('marked.parseInline(): input parameter is undefined or null');
38112           }
38113
38114           if (typeof src !== 'string') {
38115             throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
38116           }
38117
38118           opt = merge$3({}, marked.defaults, opt || {});
38119           checkSanitizeDeprecation$1(opt);
38120
38121           try {
38122             var tokens = Lexer_1.lexInline(src, opt);
38123
38124             if (opt.walkTokens) {
38125               marked.walkTokens(tokens, opt.walkTokens);
38126             }
38127
38128             return Parser_1.parseInline(tokens, opt);
38129           } catch (e) {
38130             e.message += '\nPlease report this to https://github.com/markedjs/marked.';
38131
38132             if (opt.silent) {
38133               return '<p>An error occurred:</p><pre>' + escape$3(e.message + '', true) + '</pre>';
38134             }
38135
38136             throw e;
38137           }
38138         };
38139         /**
38140          * Expose
38141          */
38142
38143
38144         marked.Parser = Parser_1;
38145         marked.parser = Parser_1.parse;
38146         marked.Renderer = Renderer_1;
38147         marked.TextRenderer = TextRenderer_1;
38148         marked.Lexer = Lexer_1;
38149         marked.lexer = Lexer_1.lex;
38150         marked.Tokenizer = Tokenizer_1;
38151         marked.Slugger = Slugger_1;
38152         marked.parse = marked;
38153         var marked_1 = marked;
38154
38155         var tiler$2 = utilTiler();
38156         var dispatch$3 = dispatch('loaded');
38157         var _tileZoom$2 = 14;
38158         var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
38159         var _osmoseData = {
38160           icons: {},
38161           items: []
38162         }; // This gets reassigned if reset
38163
38164         var _cache$2;
38165
38166         function abortRequest$2(controller) {
38167           if (controller) {
38168             controller.abort();
38169           }
38170         }
38171
38172         function abortUnwantedRequests$2(cache, tiles) {
38173           Object.keys(cache.inflightTile).forEach(function (k) {
38174             var wanted = tiles.find(function (tile) {
38175               return k === tile.id;
38176             });
38177
38178             if (!wanted) {
38179               abortRequest$2(cache.inflightTile[k]);
38180               delete cache.inflightTile[k];
38181             }
38182           });
38183         }
38184
38185         function encodeIssueRtree$2(d) {
38186           return {
38187             minX: d.loc[0],
38188             minY: d.loc[1],
38189             maxX: d.loc[0],
38190             maxY: d.loc[1],
38191             data: d
38192           };
38193         } // Replace or remove QAItem from rtree
38194
38195
38196         function updateRtree$2(item, replace) {
38197           _cache$2.rtree.remove(item, function (a, b) {
38198             return a.data.id === b.data.id;
38199           });
38200
38201           if (replace) {
38202             _cache$2.rtree.insert(item);
38203           }
38204         } // Issues shouldn't obscure each other
38205
38206
38207         function preventCoincident$1(loc) {
38208           var coincident = false;
38209
38210           do {
38211             // first time, move marker up. after that, move marker right.
38212             var delta = coincident ? [0.00001, 0] : [0, 0.00001];
38213             loc = geoVecAdd(loc, delta);
38214             var bbox = geoExtent(loc).bbox();
38215             coincident = _cache$2.rtree.search(bbox).length;
38216           } while (coincident);
38217
38218           return loc;
38219         }
38220
38221         var serviceOsmose = {
38222           title: 'osmose',
38223           init: function init() {
38224             _mainFileFetcher.get('qa_data').then(function (d) {
38225               _osmoseData = d.osmose;
38226               _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
38227                 return s.split('-')[0];
38228               }).reduce(function (unique, item) {
38229                 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
38230               }, []);
38231             });
38232
38233             if (!_cache$2) {
38234               this.reset();
38235             }
38236
38237             this.event = utilRebind(this, dispatch$3, 'on');
38238           },
38239           reset: function reset() {
38240             var _strings = {};
38241             var _colors = {};
38242
38243             if (_cache$2) {
38244               Object.values(_cache$2.inflightTile).forEach(abortRequest$2); // Strings and colors are static and should not be re-populated
38245
38246               _strings = _cache$2.strings;
38247               _colors = _cache$2.colors;
38248             }
38249
38250             _cache$2 = {
38251               data: {},
38252               loadedTile: {},
38253               inflightTile: {},
38254               inflightPost: {},
38255               closed: {},
38256               rtree: new RBush(),
38257               strings: _strings,
38258               colors: _colors
38259             };
38260           },
38261           loadIssues: function loadIssues(projection) {
38262             var _this = this;
38263
38264             var params = {
38265               // Tiles return a maximum # of issues
38266               // So we want to filter our request for only types iD supports
38267               item: _osmoseData.items
38268             }; // determine the needed tiles to cover the view
38269
38270             var tiles = tiler$2.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
38271
38272             abortUnwantedRequests$2(_cache$2, tiles); // issue new requests..
38273
38274             tiles.forEach(function (tile) {
38275               if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
38276
38277               var _tile$xyz = _slicedToArray(tile.xyz, 3),
38278                   x = _tile$xyz[0],
38279                   y = _tile$xyz[1],
38280                   z = _tile$xyz[2];
38281
38282               var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
38283               var controller = new AbortController();
38284               _cache$2.inflightTile[tile.id] = controller;
38285               d3_json(url, {
38286                 signal: controller.signal
38287               }).then(function (data) {
38288                 delete _cache$2.inflightTile[tile.id];
38289                 _cache$2.loadedTile[tile.id] = true;
38290
38291                 if (data.features) {
38292                   data.features.forEach(function (issue) {
38293                     var _issue$properties = issue.properties,
38294                         item = _issue$properties.item,
38295                         cl = _issue$properties["class"],
38296                         id = _issue$properties.uuid;
38297                     /* Osmose issues are uniquely identified by a unique
38298                       `item` and `class` combination (both integer values) */
38299
38300                     var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
38301
38302                     if (itemType in _osmoseData.icons) {
38303                       var loc = issue.geometry.coordinates; // lon, lat
38304
38305                       loc = preventCoincident$1(loc);
38306                       var d = new QAItem(loc, _this, itemType, id, {
38307                         item: item
38308                       }); // Setting elems here prevents UI detail requests
38309
38310                       if (item === 8300 || item === 8360) {
38311                         d.elems = [];
38312                       }
38313
38314                       _cache$2.data[d.id] = d;
38315
38316                       _cache$2.rtree.insert(encodeIssueRtree$2(d));
38317                     }
38318                   });
38319                 }
38320
38321                 dispatch$3.call('loaded');
38322               })["catch"](function () {
38323                 delete _cache$2.inflightTile[tile.id];
38324                 _cache$2.loadedTile[tile.id] = true;
38325               });
38326             });
38327           },
38328           loadIssueDetail: function loadIssueDetail(issue) {
38329             var _this2 = this;
38330
38331             // Issue details only need to be fetched once
38332             if (issue.elems !== undefined) {
38333               return Promise.resolve(issue);
38334             }
38335
38336             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
38337
38338             var cacheDetails = function cacheDetails(data) {
38339               // Associated elements used for highlighting
38340               // Assign directly for immediate use in the callback
38341               issue.elems = data.elems.map(function (e) {
38342                 return e.type.substring(0, 1) + e.id;
38343               }); // Some issues have instance specific detail in a subtitle
38344
38345               issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
38346
38347               _this2.replaceItem(issue);
38348             };
38349
38350             return d3_json(url).then(cacheDetails).then(function () {
38351               return issue;
38352             });
38353           },
38354           loadStrings: function loadStrings() {
38355             var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
38356             var items = Object.keys(_osmoseData.icons);
38357
38358             if (locale in _cache$2.strings && Object.keys(_cache$2.strings[locale]).length === items.length) {
38359               return Promise.resolve(_cache$2.strings[locale]);
38360             } // May be partially populated already if some requests were successful
38361
38362
38363             if (!(locale in _cache$2.strings)) {
38364               _cache$2.strings[locale] = {};
38365             } // Only need to cache strings for supported issue types
38366             // Using multiple individual item + class requests to reduce fetched data size
38367
38368
38369             var allRequests = items.map(function (itemType) {
38370               // No need to request data we already have
38371               if (itemType in _cache$2.strings[locale]) return null;
38372
38373               var cacheData = function cacheData(data) {
38374                 // Bunch of nested single value arrays of objects
38375                 var _data$categories = _slicedToArray(data.categories, 1),
38376                     _data$categories$ = _data$categories[0],
38377                     cat = _data$categories$ === void 0 ? {
38378                   items: []
38379                 } : _data$categories$;
38380
38381                 var _cat$items = _slicedToArray(cat.items, 1),
38382                     _cat$items$ = _cat$items[0],
38383                     item = _cat$items$ === void 0 ? {
38384                   "class": []
38385                 } : _cat$items$;
38386
38387                 var _item$class = _slicedToArray(item["class"], 1),
38388                     _item$class$ = _item$class[0],
38389                     cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
38390
38391
38392                 if (!cl) {
38393                   /* eslint-disable no-console */
38394                   console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
38395                   /* eslint-enable no-console */
38396
38397                   return;
38398                 } // Cache served item colors to automatically style issue markers later
38399
38400
38401                 var itemInt = item.item,
38402                     color = item.color;
38403
38404                 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
38405                   _cache$2.colors[itemInt] = color;
38406                 } // Value of root key will be null if no string exists
38407                 // If string exists, value is an object with key 'auto' for string
38408
38409
38410                 var title = cl.title,
38411                     detail = cl.detail,
38412                     fix = cl.fix,
38413                     trap = cl.trap; // Osmose titles shouldn't contain markdown
38414
38415                 var issueStrings = {};
38416                 if (title) issueStrings.title = title.auto;
38417                 if (detail) issueStrings.detail = marked_1(detail.auto);
38418                 if (trap) issueStrings.trap = marked_1(trap.auto);
38419                 if (fix) issueStrings.fix = marked_1(fix.auto);
38420                 _cache$2.strings[locale][itemType] = issueStrings;
38421               };
38422
38423               var _itemType$split = itemType.split('-'),
38424                   _itemType$split2 = _slicedToArray(_itemType$split, 2),
38425                   item = _itemType$split2[0],
38426                   cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
38427
38428
38429               var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
38430               return d3_json(url).then(cacheData);
38431             }).filter(Boolean);
38432             return Promise.all(allRequests).then(function () {
38433               return _cache$2.strings[locale];
38434             });
38435           },
38436           getStrings: function getStrings(itemType) {
38437             var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
38438             // No need to fallback to English, Osmose API handles this for us
38439             return locale in _cache$2.strings ? _cache$2.strings[locale][itemType] : {};
38440           },
38441           getColor: function getColor(itemType) {
38442             return itemType in _cache$2.colors ? _cache$2.colors[itemType] : '#FFFFFF';
38443           },
38444           postUpdate: function postUpdate(issue, callback) {
38445             var _this3 = this;
38446
38447             if (_cache$2.inflightPost[issue.id]) {
38448               return callback({
38449                 message: 'Issue update already inflight',
38450                 status: -2
38451               }, issue);
38452             } // UI sets the status to either 'done' or 'false'
38453
38454
38455             var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
38456             var controller = new AbortController();
38457
38458             var after = function after() {
38459               delete _cache$2.inflightPost[issue.id];
38460
38461               _this3.removeItem(issue);
38462
38463               if (issue.newStatus === 'done') {
38464                 // Keep track of the number of issues closed per `item` to tag the changeset
38465                 if (!(issue.item in _cache$2.closed)) {
38466                   _cache$2.closed[issue.item] = 0;
38467                 }
38468
38469                 _cache$2.closed[issue.item] += 1;
38470               }
38471
38472               if (callback) callback(null, issue);
38473             };
38474
38475             _cache$2.inflightPost[issue.id] = controller;
38476             fetch(url, {
38477               signal: controller.signal
38478             }).then(after)["catch"](function (err) {
38479               delete _cache$2.inflightPost[issue.id];
38480               if (callback) callback(err.message);
38481             });
38482           },
38483           // Get all cached QAItems covering the viewport
38484           getItems: function getItems(projection) {
38485             var viewport = projection.clipExtent();
38486             var min = [viewport[0][0], viewport[1][1]];
38487             var max = [viewport[1][0], viewport[0][1]];
38488             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38489             return _cache$2.rtree.search(bbox).map(function (d) {
38490               return d.data;
38491             });
38492           },
38493           // Get a QAItem from cache
38494           // NOTE: Don't change method name until UI v3 is merged
38495           getError: function getError(id) {
38496             return _cache$2.data[id];
38497           },
38498           // get the name of the icon to display for this item
38499           getIcon: function getIcon(itemType) {
38500             return _osmoseData.icons[itemType];
38501           },
38502           // Replace a single QAItem in the cache
38503           replaceItem: function replaceItem(item) {
38504             if (!(item instanceof QAItem) || !item.id) return;
38505             _cache$2.data[item.id] = item;
38506             updateRtree$2(encodeIssueRtree$2(item), true); // true = replace
38507
38508             return item;
38509           },
38510           // Remove a single QAItem from the cache
38511           removeItem: function removeItem(item) {
38512             if (!(item instanceof QAItem) || !item.id) return;
38513             delete _cache$2.data[item.id];
38514             updateRtree$2(encodeIssueRtree$2(item), false); // false = remove
38515           },
38516           // Used to populate `closed:osmose:*` changeset tags
38517           getClosedCounts: function getClosedCounts() {
38518             return _cache$2.closed;
38519           },
38520           itemURL: function itemURL(item) {
38521             return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
38522           }
38523         };
38524
38525         var apibase = 'https://a.mapillary.com/v3/';
38526         var viewercss = 'mapillary-js/mapillary.min.css';
38527         var viewerjs = 'mapillary-js/mapillary.min.js';
38528         var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
38529         var mapFeatureConfig = {
38530           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(',')
38531         };
38532         var maxResults = 1000;
38533         var tileZoom = 14;
38534         var tiler$3 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
38535         var dispatch$4 = dispatch('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'nodeChanged');
38536         var _mlyFallback = false;
38537
38538         var _mlyCache;
38539
38540         var _mlyClicks;
38541
38542         var _mlyActiveImage;
38543
38544         var _mlySelectedImageKey;
38545
38546         var _mlyViewer;
38547
38548         var _mlyViewerFilter = ['all'];
38549
38550         var _loadViewerPromise;
38551
38552         var _mlyHighlightedDetection;
38553
38554         var _mlyShowFeatureDetections = false;
38555         var _mlyShowSignDetections = false;
38556
38557         function abortRequest$3(controller) {
38558           controller.abort();
38559         }
38560
38561         function loadTiles(which, url, projection) {
38562           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
38563           var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
38564
38565           var cache = _mlyCache[which];
38566           Object.keys(cache.inflight).forEach(function (k) {
38567             var wanted = tiles.find(function (tile) {
38568               return k.indexOf(tile.id + ',') === 0;
38569             });
38570
38571             if (!wanted) {
38572               abortRequest$3(cache.inflight[k]);
38573               delete cache.inflight[k];
38574             }
38575           });
38576           tiles.forEach(function (tile) {
38577             loadNextTilePage(which, currZoom, url, tile);
38578           });
38579         }
38580
38581         function loadNextTilePage(which, currZoom, url, tile) {
38582           var cache = _mlyCache[which];
38583           var rect = tile.extent.rectangle();
38584           var maxPages = maxPageAtZoom(currZoom);
38585           var nextPage = cache.nextPage[tile.id] || 0;
38586           var nextURL = cache.nextURL[tile.id] || url + utilQsString({
38587             per_page: maxResults,
38588             page: nextPage,
38589             client_id: clientId,
38590             bbox: [rect[0], rect[1], rect[2], rect[3]].join(',')
38591           });
38592           if (nextPage > maxPages) return;
38593           var id = tile.id + ',' + String(nextPage);
38594           if (cache.loaded[id] || cache.inflight[id]) return;
38595           var controller = new AbortController();
38596           cache.inflight[id] = controller;
38597           var options = {
38598             method: 'GET',
38599             signal: controller.signal,
38600             headers: {
38601               'Content-Type': 'application/json'
38602             }
38603           };
38604           fetch(nextURL, options).then(function (response) {
38605             if (!response.ok) {
38606               throw new Error(response.status + ' ' + response.statusText);
38607             }
38608
38609             var linkHeader = response.headers.get('Link');
38610
38611             if (linkHeader) {
38612               var pagination = parsePagination(linkHeader);
38613
38614               if (pagination.next) {
38615                 cache.nextURL[tile.id] = pagination.next;
38616               }
38617             }
38618
38619             return response.json();
38620           }).then(function (data) {
38621             cache.loaded[id] = true;
38622             delete cache.inflight[id];
38623
38624             if (!data || !data.features || !data.features.length) {
38625               throw new Error('No Data');
38626             }
38627
38628             var features = data.features.map(function (feature) {
38629               var loc = feature.geometry.coordinates;
38630               var d; // An image (shown as a green dot on the map) is a single street photo with extra
38631               // information such as location, camera angle (CA), camera model, and so on.
38632               // Each image feature is a GeoJSON Point
38633
38634               if (which === 'images') {
38635                 d = {
38636                   loc: loc,
38637                   key: feature.properties.key,
38638                   ca: feature.properties.ca,
38639                   captured_at: feature.properties.captured_at,
38640                   captured_by: feature.properties.username,
38641                   pano: feature.properties.pano
38642                 };
38643                 cache.forImageKey[d.key] = d; // cache imageKey -> image
38644                 // Mapillary organizes images as sequences. A sequence of images are continuously captured
38645                 // by a user at a give time. Sequences are shown on the map as green lines.
38646                 // Each sequence feature is a GeoJSON LineString
38647               } else if (which === 'sequences') {
38648                 var sequenceKey = feature.properties.key;
38649                 cache.lineString[sequenceKey] = feature; // cache sequenceKey -> lineString
38650
38651                 feature.properties.coordinateProperties.image_keys.forEach(function (imageKey) {
38652                   cache.forImageKey[imageKey] = sequenceKey; // cache imageKey -> sequenceKey
38653                 });
38654                 return false; // because no `d` data worth loading into an rbush
38655                 // A map feature is a real world object that can be shown on a map. It could be any object
38656                 // recognized from images, manually added in images, or added on the map.
38657                 // Each map feature is a GeoJSON Point (located where the feature is)
38658               } else if (which === 'map_features' || which === 'points') {
38659                 d = {
38660                   loc: loc,
38661                   key: feature.properties.key,
38662                   value: feature.properties.value,
38663                   detections: feature.properties.detections,
38664                   direction: feature.properties.direction,
38665                   accuracy: feature.properties.accuracy,
38666                   first_seen_at: feature.properties.first_seen_at,
38667                   last_seen_at: feature.properties.last_seen_at
38668                 };
38669               }
38670
38671               return {
38672                 minX: loc[0],
38673                 minY: loc[1],
38674                 maxX: loc[0],
38675                 maxY: loc[1],
38676                 data: d
38677               };
38678             }).filter(Boolean);
38679
38680             if (cache.rtree && features) {
38681               cache.rtree.load(features);
38682             }
38683
38684             if (data.features.length === maxResults) {
38685               // more pages to load
38686               cache.nextPage[tile.id] = nextPage + 1;
38687               loadNextTilePage(which, currZoom, url, tile);
38688             } else {
38689               cache.nextPage[tile.id] = Infinity; // no more pages to load
38690             }
38691
38692             if (which === 'images' || which === 'sequences') {
38693               dispatch$4.call('loadedImages');
38694             } else if (which === 'map_features') {
38695               dispatch$4.call('loadedSigns');
38696             } else if (which === 'points') {
38697               dispatch$4.call('loadedMapFeatures');
38698             }
38699           })["catch"](function () {
38700             cache.loaded[id] = true;
38701             delete cache.inflight[id];
38702           });
38703         }
38704
38705         function loadData(which, url) {
38706           var cache = _mlyCache[which];
38707           var options = {
38708             method: 'GET',
38709             headers: {
38710               'Content-Type': 'application/json'
38711             }
38712           };
38713           var nextUrl = url + '&client_id=' + clientId;
38714           return fetch(nextUrl, options).then(function (response) {
38715             if (!response.ok) {
38716               throw new Error(response.status + ' ' + response.statusText);
38717             }
38718
38719             return response.json();
38720           }).then(function (data) {
38721             if (!data || !data.features || !data.features.length) {
38722               throw new Error('No Data');
38723             }
38724
38725             data.features.forEach(function (feature) {
38726               var d;
38727
38728               if (which === 'image_detections') {
38729                 d = {
38730                   key: feature.properties.key,
38731                   image_key: feature.properties.image_key,
38732                   value: feature.properties.value,
38733                   shape: feature.properties.shape
38734                 };
38735
38736                 if (!cache.forImageKey[d.image_key]) {
38737                   cache.forImageKey[d.image_key] = [];
38738                 }
38739
38740                 cache.forImageKey[d.image_key].push(d);
38741               }
38742             });
38743           });
38744         }
38745
38746         function maxPageAtZoom(z) {
38747           if (z < 15) return 2;
38748           if (z === 15) return 5;
38749           if (z === 16) return 10;
38750           if (z === 17) return 20;
38751           if (z === 18) return 40;
38752           if (z > 18) return 80;
38753         } // extract links to pages of API results
38754
38755
38756         function parsePagination(links) {
38757           return links.split(',').map(function (rel) {
38758             var elements = rel.split(';');
38759
38760             if (elements.length === 2) {
38761               return [/<(.+)>/.exec(elements[0])[1], /rel="(.+)"/.exec(elements[1])[1]];
38762             } else {
38763               return ['', ''];
38764             }
38765           }).reduce(function (pagination, val) {
38766             pagination[val[1]] = val[0];
38767             return pagination;
38768           }, {});
38769         } // partition viewport into higher zoom tiles
38770
38771
38772         function partitionViewport(projection) {
38773           var z = geoScaleToZoom(projection.scale());
38774           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
38775
38776           var tiler = utilTiler().zoomExtent([z2, z2]);
38777           return tiler.getTiles(projection).map(function (tile) {
38778             return tile.extent;
38779           });
38780         } // no more than `limit` results per partition.
38781
38782
38783         function searchLimited(limit, projection, rtree) {
38784           limit = limit || 5;
38785           return partitionViewport(projection).reduce(function (result, extent) {
38786             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
38787               return d.data;
38788             });
38789             return found.length ? result.concat(found) : result;
38790           }, []);
38791         }
38792
38793         var serviceMapillary = {
38794           init: function init() {
38795             if (!_mlyCache) {
38796               this.reset();
38797             }
38798
38799             this.event = utilRebind(this, dispatch$4, 'on');
38800           },
38801           reset: function reset() {
38802             if (_mlyCache) {
38803               Object.values(_mlyCache.images.inflight).forEach(abortRequest$3);
38804               Object.values(_mlyCache.image_detections.inflight).forEach(abortRequest$3);
38805               Object.values(_mlyCache.map_features.inflight).forEach(abortRequest$3);
38806               Object.values(_mlyCache.points.inflight).forEach(abortRequest$3);
38807               Object.values(_mlyCache.sequences.inflight).forEach(abortRequest$3);
38808             }
38809
38810             _mlyCache = {
38811               images: {
38812                 inflight: {},
38813                 loaded: {},
38814                 nextPage: {},
38815                 nextURL: {},
38816                 rtree: new RBush(),
38817                 forImageKey: {}
38818               },
38819               image_detections: {
38820                 inflight: {},
38821                 loaded: {},
38822                 nextPage: {},
38823                 nextURL: {},
38824                 forImageKey: {}
38825               },
38826               map_features: {
38827                 inflight: {},
38828                 loaded: {},
38829                 nextPage: {},
38830                 nextURL: {},
38831                 rtree: new RBush()
38832               },
38833               points: {
38834                 inflight: {},
38835                 loaded: {},
38836                 nextPage: {},
38837                 nextURL: {},
38838                 rtree: new RBush()
38839               },
38840               sequences: {
38841                 inflight: {},
38842                 loaded: {},
38843                 nextPage: {},
38844                 nextURL: {},
38845                 rtree: new RBush(),
38846                 forImageKey: {},
38847                 lineString: {}
38848               }
38849             };
38850             _mlySelectedImageKey = null;
38851             _mlyActiveImage = null;
38852             _mlyClicks = [];
38853           },
38854           images: function images(projection) {
38855             var limit = 5;
38856             return searchLimited(limit, projection, _mlyCache.images.rtree);
38857           },
38858           signs: function signs(projection) {
38859             var limit = 5;
38860             return searchLimited(limit, projection, _mlyCache.map_features.rtree);
38861           },
38862           mapFeatures: function mapFeatures(projection) {
38863             var limit = 5;
38864             return searchLimited(limit, projection, _mlyCache.points.rtree);
38865           },
38866           cachedImage: function cachedImage(imageKey) {
38867             return _mlyCache.images.forImageKey[imageKey];
38868           },
38869           sequences: function sequences(projection) {
38870             var viewport = projection.clipExtent();
38871             var min = [viewport[0][0], viewport[1][1]];
38872             var max = [viewport[1][0], viewport[0][1]];
38873             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
38874             var sequenceKeys = {}; // all sequences for images in viewport
38875
38876             _mlyCache.images.rtree.search(bbox).forEach(function (d) {
38877               var sequenceKey = _mlyCache.sequences.forImageKey[d.data.key];
38878
38879               if (sequenceKey) {
38880                 sequenceKeys[sequenceKey] = true;
38881               }
38882             }); // Return lineStrings for the sequences
38883
38884
38885             return Object.keys(sequenceKeys).map(function (sequenceKey) {
38886               return _mlyCache.sequences.lineString[sequenceKey];
38887             });
38888           },
38889           signsSupported: function signsSupported() {
38890             return true;
38891           },
38892           loadImages: function loadImages(projection) {
38893             loadTiles('images', apibase + 'images?sort_by=key&', projection);
38894             loadTiles('sequences', apibase + 'sequences?sort_by=key&', projection);
38895           },
38896           loadSigns: function loadSigns(projection) {
38897             loadTiles('map_features', apibase + 'map_features?layers=trafficsigns&min_nbr_image_detections=2&sort_by=key&', projection);
38898           },
38899           loadMapFeatures: function loadMapFeatures(projection) {
38900             loadTiles('points', apibase + 'map_features?layers=points&min_nbr_image_detections=2&sort_by=key&values=' + mapFeatureConfig.values + '&', projection);
38901           },
38902           ensureViewerLoaded: function ensureViewerLoaded(context) {
38903             if (_loadViewerPromise) return _loadViewerPromise; // add mly-wrapper
38904
38905             var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
38906             wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
38907             var that = this;
38908             _loadViewerPromise = new Promise(function (resolve, reject) {
38909               var loadedCount = 0;
38910
38911               function loaded() {
38912                 loadedCount += 1; // wait until both files are loaded
38913
38914                 if (loadedCount === 2) resolve();
38915               }
38916
38917               var head = select('head'); // load mapillary-viewercss
38918
38919               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 () {
38920                 reject();
38921               }); // load mapillary-viewerjs
38922
38923               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 () {
38924                 reject();
38925               });
38926             })["catch"](function () {
38927               _loadViewerPromise = null;
38928             }).then(function () {
38929               that.initViewer(context);
38930             });
38931             return _loadViewerPromise;
38932           },
38933           loadSignResources: function loadSignResources(context) {
38934             context.ui().svgDefs.addSprites(['mapillary-sprite'], false
38935             /* don't override colors */
38936             );
38937             return this;
38938           },
38939           loadObjectResources: function loadObjectResources(context) {
38940             context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
38941             /* don't override colors */
38942             );
38943             return this;
38944           },
38945           resetTags: function resetTags() {
38946             if (_mlyViewer && !_mlyFallback) {
38947               _mlyViewer.getComponent('tag').removeAll(); // remove previous detections
38948
38949             }
38950           },
38951           showFeatureDetections: function showFeatureDetections(value) {
38952             _mlyShowFeatureDetections = value;
38953
38954             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38955               this.resetTags();
38956             }
38957           },
38958           showSignDetections: function showSignDetections(value) {
38959             _mlyShowSignDetections = value;
38960
38961             if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
38962               this.resetTags();
38963             }
38964           },
38965           filterViewer: function filterViewer(context) {
38966             var showsPano = context.photos().showsPanoramic();
38967             var showsFlat = context.photos().showsFlat();
38968             var fromDate = context.photos().fromDate();
38969             var toDate = context.photos().toDate();
38970             var usernames = context.photos().usernames();
38971             var filter = ['all'];
38972             if (!showsPano) filter.push(['==', 'pano', false]);
38973             if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
38974             if (usernames && usernames.length) filter.push(['==', 'username', usernames[0]]);
38975
38976             if (fromDate) {
38977               var fromTimestamp = new Date(fromDate).getTime();
38978               filter.push(['>=', 'capturedAt', fromTimestamp]);
38979             }
38980
38981             if (toDate) {
38982               var toTimestamp = new Date(toDate).getTime();
38983               filter.push(['>=', 'capturedAt', toTimestamp]);
38984             }
38985
38986             if (_mlyViewer) {
38987               _mlyViewer.setFilter(filter);
38988             }
38989
38990             _mlyViewerFilter = filter;
38991             return filter;
38992           },
38993           showViewer: function showViewer(context) {
38994             var wrap = context.container().select('.photoviewer').classed('hide', false);
38995             var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
38996
38997             if (isHidden && _mlyViewer) {
38998               wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
38999               wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
39000
39001               _mlyViewer.resize();
39002             }
39003
39004             return this;
39005           },
39006           hideViewer: function hideViewer(context) {
39007             _mlyActiveImage = null;
39008             _mlySelectedImageKey = null;
39009
39010             if (!_mlyFallback && _mlyViewer) {
39011               _mlyViewer.getComponent('sequence').stop();
39012             }
39013
39014             var viewer = context.container().select('.photoviewer');
39015             if (!viewer.empty()) viewer.datum(null);
39016             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
39017             this.updateUrlImage(null);
39018             dispatch$4.call('nodeChanged');
39019             return this.setStyles(context, null, true);
39020           },
39021           parsePagination: parsePagination,
39022           updateUrlImage: function updateUrlImage(imageKey) {
39023             if (!window.mocha) {
39024               var hash = utilStringQs(window.location.hash);
39025
39026               if (imageKey) {
39027                 hash.photo = 'mapillary/' + imageKey;
39028               } else {
39029                 delete hash.photo;
39030               }
39031
39032               window.location.replace('#' + utilQsString(hash, true));
39033             }
39034           },
39035           highlightDetection: function highlightDetection(detection) {
39036             if (detection) {
39037               _mlyHighlightedDetection = detection.detection_key;
39038             }
39039
39040             return this;
39041           },
39042           initViewer: function initViewer(context) {
39043             var that = this;
39044             if (!window.Mapillary) return;
39045             var opts = {
39046               baseImageSize: 320,
39047               component: {
39048                 cover: false,
39049                 keyboard: false,
39050                 tag: true
39051               }
39052             }; // Disable components requiring WebGL support
39053
39054             if (!Mapillary.isSupported() && Mapillary.isFallbackSupported()) {
39055               _mlyFallback = true;
39056               opts.component = {
39057                 cover: false,
39058                 direction: false,
39059                 imagePlane: false,
39060                 keyboard: false,
39061                 mouse: false,
39062                 sequence: false,
39063                 tag: false,
39064                 image: true,
39065                 // fallback
39066                 navigation: true // fallback
39067
39068               };
39069             }
39070
39071             _mlyViewer = new Mapillary.Viewer('ideditor-mly', clientId, null, opts);
39072
39073             _mlyViewer.on('nodechanged', nodeChanged);
39074
39075             _mlyViewer.on('bearingchanged', bearingChanged);
39076
39077             if (_mlyViewerFilter) {
39078               _mlyViewer.setFilter(_mlyViewerFilter);
39079             } // Register viewer resize handler
39080
39081
39082             context.ui().photoviewer.on('resize.mapillary', function () {
39083               if (_mlyViewer) _mlyViewer.resize();
39084             }); // nodeChanged: called after the viewer has changed images and is ready.
39085             //
39086             // There is some logic here to batch up clicks into a _mlyClicks array
39087             // because the user might click on a lot of markers quickly and nodechanged
39088             // may be called out of order asynchronously.
39089             //
39090             // Clicks are added to the array in `selectedImage` and removed here.
39091             //
39092
39093             function nodeChanged(node) {
39094               that.resetTags();
39095               var clicks = _mlyClicks;
39096               var index = clicks.indexOf(node.key);
39097               var selectedKey = _mlySelectedImageKey;
39098               that.setActiveImage(node);
39099
39100               if (index > -1) {
39101                 // `nodechanged` initiated from clicking on a marker..
39102                 clicks.splice(index, 1); // remove the click
39103                 // If `node.key` matches the current _mlySelectedImageKey, call `selectImage()`
39104                 // one more time to update the detections and attribution..
39105
39106                 if (node.key === selectedKey) {
39107                   that.selectImage(context, _mlySelectedImageKey, true);
39108                 }
39109               } else {
39110                 // `nodechanged` initiated from the Mapillary viewer controls..
39111                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
39112                 context.map().centerEase(loc);
39113                 that.selectImage(context, node.key, true);
39114               }
39115
39116               dispatch$4.call('nodeChanged');
39117             }
39118
39119             function bearingChanged(e) {
39120               dispatch$4.call('bearingChanged', undefined, e);
39121             }
39122           },
39123           // Pass in the image key string as `imageKey`.
39124           // This allows images to be selected from places that dont have access
39125           // to the full image datum (like the street signs layer or the js viewer)
39126           selectImage: function selectImage(context, imageKey, fromViewer) {
39127             _mlySelectedImageKey = imageKey;
39128             this.updateUrlImage(imageKey);
39129             var d = _mlyCache.images.forImageKey[imageKey];
39130             var viewer = context.container().select('.photoviewer');
39131             if (!viewer.empty()) viewer.datum(d);
39132             imageKey = d && d.key || imageKey;
39133
39134             if (!fromViewer && imageKey) {
39135               _mlyClicks.push(imageKey);
39136             }
39137
39138             this.setStyles(context, null, true);
39139
39140             if (_mlyShowFeatureDetections) {
39141               this.updateDetections(imageKey, apibase + 'image_detections?layers=points&values=' + mapFeatureConfig.values + '&image_keys=' + imageKey);
39142             }
39143
39144             if (_mlyShowSignDetections) {
39145               this.updateDetections(imageKey, apibase + 'image_detections?layers=trafficsigns&image_keys=' + imageKey);
39146             }
39147
39148             if (_mlyViewer && imageKey) {
39149               _mlyViewer.moveToKey(imageKey)["catch"](function (e) {
39150                 console.error('mly3', e);
39151               }); // eslint-disable-line no-console
39152
39153             }
39154
39155             return this;
39156           },
39157           getActiveImage: function getActiveImage() {
39158             return _mlyActiveImage;
39159           },
39160           getSelectedImageKey: function getSelectedImageKey() {
39161             return _mlySelectedImageKey;
39162           },
39163           getSequenceKeyForImageKey: function getSequenceKeyForImageKey(imageKey) {
39164             return _mlyCache.sequences.forImageKey[imageKey];
39165           },
39166           setActiveImage: function setActiveImage(node) {
39167             if (node) {
39168               _mlyActiveImage = {
39169                 ca: node.originalCA,
39170                 key: node.key,
39171                 loc: [node.originalLatLon.lon, node.originalLatLon.lat],
39172                 pano: node.pano
39173               };
39174             } else {
39175               _mlyActiveImage = null;
39176             }
39177           },
39178           // Updates the currently highlighted sequence and selected bubble.
39179           // Reset is only necessary when interacting with the viewport because
39180           // this implicitly changes the currently selected bubble/sequence
39181           setStyles: function setStyles(context, hovered, reset) {
39182             if (reset) {
39183               // reset all layers
39184               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false);
39185               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
39186             }
39187
39188             var hoveredImageKey = hovered && hovered.key;
39189             var hoveredSequenceKey = hoveredImageKey && this.getSequenceKeyForImageKey(hoveredImageKey);
39190             var hoveredLineString = hoveredSequenceKey && _mlyCache.sequences.lineString[hoveredSequenceKey];
39191             var hoveredImageKeys = hoveredLineString && hoveredLineString.properties.coordinateProperties.image_keys || [];
39192             var selectedImageKey = _mlySelectedImageKey;
39193             var selectedSequenceKey = selectedImageKey && this.getSequenceKeyForImageKey(selectedImageKey);
39194             var selectedLineString = selectedSequenceKey && _mlyCache.sequences.lineString[selectedSequenceKey];
39195             var selectedImageKeys = selectedLineString && selectedLineString.properties.coordinateProperties.image_keys || []; // highlight sibling viewfields on either the selected or the hovered sequences
39196
39197             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
39198             context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
39199               return highlightedImageKeys.indexOf(d.key) !== -1;
39200             }).classed('hovered', function (d) {
39201               return d.key === hoveredImageKey;
39202             });
39203             context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
39204               return d.properties.key === hoveredSequenceKey;
39205             }).classed('currentView', function (d) {
39206               return d.properties.key === selectedSequenceKey;
39207             }); // update viewfields if needed
39208
39209             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
39210
39211             function viewfieldPath() {
39212               var d = this.parentNode.__data__;
39213
39214               if (d.pano && d.key !== selectedImageKey) {
39215                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
39216               } else {
39217                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
39218               }
39219             }
39220
39221             return this;
39222           },
39223           updateDetections: function updateDetections(imageKey, url) {
39224             if (!_mlyViewer || _mlyFallback) return;
39225             if (!imageKey) return;
39226
39227             if (!_mlyCache.image_detections.forImageKey[imageKey]) {
39228               loadData('image_detections', url).then(function () {
39229                 showDetections(_mlyCache.image_detections.forImageKey[imageKey] || []);
39230               });
39231             } else {
39232               showDetections(_mlyCache.image_detections.forImageKey[imageKey]);
39233             }
39234
39235             function showDetections(detections) {
39236               detections.forEach(function (data) {
39237                 var tag = makeTag(data);
39238
39239                 if (tag) {
39240                   var tagComponent = _mlyViewer.getComponent('tag');
39241
39242                   tagComponent.add([tag]);
39243                 }
39244               });
39245             }
39246
39247             function makeTag(data) {
39248               var valueParts = data.value.split('--');
39249               if (!valueParts.length) return;
39250               var tag;
39251               var text;
39252               var color = 0xffffff;
39253
39254               if (_mlyHighlightedDetection === data.key) {
39255                 color = 0xffff00;
39256                 text = valueParts[1];
39257
39258                 if (text === 'flat' || text === 'discrete' || text === 'sign') {
39259                   text = valueParts[2];
39260                 }
39261
39262                 text = text.replace(/-/g, ' ');
39263                 text = text.charAt(0).toUpperCase() + text.slice(1);
39264                 _mlyHighlightedDetection = null;
39265               }
39266
39267               if (data.shape.type === 'Polygon') {
39268                 var polygonGeometry = new Mapillary.TagComponent.PolygonGeometry(data.shape.coordinates[0]);
39269                 tag = new Mapillary.TagComponent.OutlineTag(data.key, polygonGeometry, {
39270                   text: text,
39271                   textColor: color,
39272                   lineColor: color,
39273                   lineWidth: 2,
39274                   fillColor: color,
39275                   fillOpacity: 0.3
39276                 });
39277               } else if (data.shape.type === 'Point') {
39278                 var pointGeometry = new Mapillary.TagComponent.PointGeometry(data.shape.coordinates[0]);
39279                 tag = new Mapillary.TagComponent.SpotTag(data.key, pointGeometry, {
39280                   text: text,
39281                   color: color,
39282                   textColor: color
39283                 });
39284               }
39285
39286               return tag;
39287             }
39288           },
39289           cache: function cache() {
39290             return _mlyCache;
39291           }
39292         };
39293
39294         function validationIssue(attrs) {
39295           this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
39296
39297           this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
39298
39299           this.severity = attrs.severity; // required - 'warning' or 'error'
39300
39301           this.message = attrs.message; // required - function returning localized string
39302
39303           this.reference = attrs.reference; // optional - function(selection) to render reference information
39304
39305           this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
39306
39307           this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
39308
39309           this.data = attrs.data; // optional - object containing extra data for the fixes
39310
39311           this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
39312
39313           this.hash = attrs.hash; // optional - string to further differentiate the issue
39314
39315           this.id = generateID.apply(this); // generated - see below
39316
39317           this.autoFix = null; // generated - if autofix exists, will be set below
39318           // A unique, deterministic string hash.
39319           // Issues with identical id values are considered identical.
39320
39321           function generateID() {
39322             var parts = [this.type];
39323
39324             if (this.hash) {
39325               // subclasses can pass in their own differentiator
39326               parts.push(this.hash);
39327             }
39328
39329             if (this.subtype) {
39330               parts.push(this.subtype);
39331             } // include the entities this issue is for
39332             // (sort them so the id is deterministic)
39333
39334
39335             if (this.entityIds) {
39336               var entityKeys = this.entityIds.slice().sort();
39337               parts.push.apply(parts, entityKeys);
39338             }
39339
39340             return parts.join(':');
39341           }
39342
39343           this.extent = function (resolver) {
39344             if (this.loc) {
39345               return geoExtent(this.loc);
39346             }
39347
39348             if (this.entityIds && this.entityIds.length) {
39349               return this.entityIds.reduce(function (extent, entityId) {
39350                 return extent.extend(resolver.entity(entityId).extent(resolver));
39351               }, geoExtent());
39352             }
39353
39354             return null;
39355           };
39356
39357           this.fixes = function (context) {
39358             var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
39359             var issue = this;
39360
39361             if (issue.severity === 'warning') {
39362               // allow ignoring any issue that's not an error
39363               fixes.push(new validationIssueFix({
39364                 title: _t.html('issues.fix.ignore_issue.title'),
39365                 icon: 'iD-icon-close',
39366                 onClick: function onClick() {
39367                   context.validator().ignoreIssue(this.issue.id);
39368                 }
39369               }));
39370             }
39371
39372             fixes.forEach(function (fix) {
39373               // the id doesn't matter as long as it's unique to this issue/fix
39374               fix.id = fix.title; // add a reference to the issue for use in actions
39375
39376               fix.issue = issue;
39377
39378               if (fix.autoArgs) {
39379                 issue.autoFix = fix;
39380               }
39381             });
39382             return fixes;
39383           };
39384         }
39385         function validationIssueFix(attrs) {
39386           this.title = attrs.title; // Required
39387
39388           this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
39389
39390           this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
39391
39392           this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
39393
39394           this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
39395
39396           this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
39397
39398           this.issue = null; // Generated link - added by validationIssue
39399         }
39400
39401         var buildRuleChecks = function buildRuleChecks() {
39402           return {
39403             equals: function equals(_equals) {
39404               return function (tags) {
39405                 return Object.keys(_equals).every(function (k) {
39406                   return _equals[k] === tags[k];
39407                 });
39408               };
39409             },
39410             notEquals: function notEquals(_notEquals) {
39411               return function (tags) {
39412                 return Object.keys(_notEquals).some(function (k) {
39413                   return _notEquals[k] !== tags[k];
39414                 });
39415               };
39416             },
39417             absence: function absence(_absence) {
39418               return function (tags) {
39419                 return Object.keys(tags).indexOf(_absence) === -1;
39420               };
39421             },
39422             presence: function presence(_presence) {
39423               return function (tags) {
39424                 return Object.keys(tags).indexOf(_presence) > -1;
39425               };
39426             },
39427             greaterThan: function greaterThan(_greaterThan) {
39428               var key = Object.keys(_greaterThan)[0];
39429               var value = _greaterThan[key];
39430               return function (tags) {
39431                 return tags[key] > value;
39432               };
39433             },
39434             greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
39435               var key = Object.keys(_greaterThanEqual)[0];
39436               var value = _greaterThanEqual[key];
39437               return function (tags) {
39438                 return tags[key] >= value;
39439               };
39440             },
39441             lessThan: function lessThan(_lessThan) {
39442               var key = Object.keys(_lessThan)[0];
39443               var value = _lessThan[key];
39444               return function (tags) {
39445                 return tags[key] < value;
39446               };
39447             },
39448             lessThanEqual: function lessThanEqual(_lessThanEqual) {
39449               var key = Object.keys(_lessThanEqual)[0];
39450               var value = _lessThanEqual[key];
39451               return function (tags) {
39452                 return tags[key] <= value;
39453               };
39454             },
39455             positiveRegex: function positiveRegex(_positiveRegex) {
39456               var tagKey = Object.keys(_positiveRegex)[0];
39457
39458               var expression = _positiveRegex[tagKey].join('|');
39459
39460               var regex = new RegExp(expression);
39461               return function (tags) {
39462                 return regex.test(tags[tagKey]);
39463               };
39464             },
39465             negativeRegex: function negativeRegex(_negativeRegex) {
39466               var tagKey = Object.keys(_negativeRegex)[0];
39467
39468               var expression = _negativeRegex[tagKey].join('|');
39469
39470               var regex = new RegExp(expression);
39471               return function (tags) {
39472                 return !regex.test(tags[tagKey]);
39473               };
39474             }
39475           };
39476         };
39477
39478         var buildLineKeys = function buildLineKeys() {
39479           return {
39480             highway: {
39481               rest_area: true,
39482               services: true
39483             },
39484             railway: {
39485               roundhouse: true,
39486               station: true,
39487               traverser: true,
39488               turntable: true,
39489               wash: true
39490             }
39491           };
39492         };
39493
39494         var serviceMapRules = {
39495           init: function init() {
39496             this._ruleChecks = buildRuleChecks();
39497             this._validationRules = [];
39498             this._areaKeys = osmAreaKeys;
39499             this._lineKeys = buildLineKeys();
39500           },
39501           // list of rules only relevant to tag checks...
39502           filterRuleChecks: function filterRuleChecks(selector) {
39503             var _ruleChecks = this._ruleChecks;
39504             return Object.keys(selector).reduce(function (rules, key) {
39505               if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
39506                 rules.push(_ruleChecks[key](selector[key]));
39507               }
39508
39509               return rules;
39510             }, []);
39511           },
39512           // builds tagMap from mapcss-parse selector object...
39513           buildTagMap: function buildTagMap(selector) {
39514             var getRegexValues = function getRegexValues(regexes) {
39515               return regexes.map(function (regex) {
39516                 return regex.replace(/\$|\^/g, '');
39517               });
39518             };
39519
39520             var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
39521               var values;
39522               var isRegex = /regex/gi.test(key);
39523               var isEqual = /equals/gi.test(key);
39524
39525               if (isRegex || isEqual) {
39526                 Object.keys(selector[key]).forEach(function (selectorKey) {
39527                   values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
39528
39529                   if (expectedTags.hasOwnProperty(selectorKey)) {
39530                     values = values.concat(expectedTags[selectorKey]);
39531                   }
39532
39533                   expectedTags[selectorKey] = values;
39534                 });
39535               } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
39536                 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
39537                 values = [selector[key][tagKey]];
39538
39539                 if (expectedTags.hasOwnProperty(tagKey)) {
39540                   values = values.concat(expectedTags[tagKey]);
39541                 }
39542
39543                 expectedTags[tagKey] = values;
39544               }
39545
39546               return expectedTags;
39547             }, {});
39548             return tagMap;
39549           },
39550           // inspired by osmWay#isArea()
39551           inferGeometry: function inferGeometry(tagMap) {
39552             var _lineKeys = this._lineKeys;
39553             var _areaKeys = this._areaKeys;
39554
39555             var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
39556               return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
39557             };
39558
39559             var keyValueImpliesLine = function keyValueImpliesLine(key) {
39560               return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
39561             };
39562
39563             if (tagMap.hasOwnProperty('area')) {
39564               if (tagMap.area.indexOf('yes') > -1) {
39565                 return 'area';
39566               }
39567
39568               if (tagMap.area.indexOf('no') > -1) {
39569                 return 'line';
39570               }
39571             }
39572
39573             for (var key in tagMap) {
39574               if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
39575                 return 'area';
39576               }
39577
39578               if (key in _lineKeys && keyValueImpliesLine(key)) {
39579                 return 'area';
39580               }
39581             }
39582
39583             return 'line';
39584           },
39585           // adds from mapcss-parse selector check...
39586           addRule: function addRule(selector) {
39587             var rule = {
39588               // checks relevant to mapcss-selector
39589               checks: this.filterRuleChecks(selector),
39590               // true if all conditions for a tag error are true..
39591               matches: function matches(entity) {
39592                 return this.checks.every(function (check) {
39593                   return check(entity.tags);
39594                 });
39595               },
39596               // borrowed from Way#isArea()
39597               inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
39598               geometryMatches: function geometryMatches(entity, graph) {
39599                 if (entity.type === 'node' || entity.type === 'relation') {
39600                   return selector.geometry === entity.type;
39601                 } else if (entity.type === 'way') {
39602                   return this.inferredGeometry === entity.geometry(graph);
39603                 }
39604               },
39605               // when geometries match and tag matches are present, return a warning...
39606               findIssues: function findIssues(entity, graph, issues) {
39607                 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
39608                   var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
39609                   var _message = selector[severity];
39610                   issues.push(new validationIssue({
39611                     type: 'maprules',
39612                     severity: severity,
39613                     message: function message() {
39614                       return _message;
39615                     },
39616                     entityIds: [entity.id]
39617                   }));
39618                 }
39619               }
39620             };
39621
39622             this._validationRules.push(rule);
39623           },
39624           clearRules: function clearRules() {
39625             this._validationRules = [];
39626           },
39627           // returns validationRules...
39628           validationRules: function validationRules() {
39629             return this._validationRules;
39630           },
39631           // returns ruleChecks
39632           ruleChecks: function ruleChecks() {
39633             return this._ruleChecks;
39634           }
39635         };
39636
39637         var apibase$1 = 'https://nominatim.openstreetmap.org/';
39638         var _inflight = {};
39639
39640         var _nominatimCache;
39641
39642         var serviceNominatim = {
39643           init: function init() {
39644             _inflight = {};
39645             _nominatimCache = new RBush();
39646           },
39647           reset: function reset() {
39648             Object.values(_inflight).forEach(function (controller) {
39649               controller.abort();
39650             });
39651             _inflight = {};
39652             _nominatimCache = new RBush();
39653           },
39654           countryCode: function countryCode(location, callback) {
39655             this.reverse(location, function (err, result) {
39656               if (err) {
39657                 return callback(err);
39658               } else if (result.address) {
39659                 return callback(null, result.address.country_code);
39660               } else {
39661                 return callback('Unable to geocode', null);
39662               }
39663             });
39664           },
39665           reverse: function reverse(loc, callback) {
39666             var cached = _nominatimCache.search({
39667               minX: loc[0],
39668               minY: loc[1],
39669               maxX: loc[0],
39670               maxY: loc[1]
39671             });
39672
39673             if (cached.length > 0) {
39674               if (callback) callback(null, cached[0].data);
39675               return;
39676             }
39677
39678             var params = {
39679               zoom: 13,
39680               format: 'json',
39681               addressdetails: 1,
39682               lat: loc[1],
39683               lon: loc[0]
39684             };
39685             var url = apibase$1 + 'reverse?' + utilQsString(params);
39686             if (_inflight[url]) return;
39687             var controller = new AbortController();
39688             _inflight[url] = controller;
39689             d3_json(url, {
39690               signal: controller.signal
39691             }).then(function (result) {
39692               delete _inflight[url];
39693
39694               if (result && result.error) {
39695                 throw new Error(result.error);
39696               }
39697
39698               var extent = geoExtent(loc).padByMeters(200);
39699
39700               _nominatimCache.insert(Object.assign(extent.bbox(), {
39701                 data: result
39702               }));
39703
39704               if (callback) callback(null, result);
39705             })["catch"](function (err) {
39706               delete _inflight[url];
39707               if (err.name === 'AbortError') return;
39708               if (callback) callback(err.message);
39709             });
39710           },
39711           search: function search(val, callback) {
39712             var searchVal = encodeURIComponent(val);
39713             var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
39714             if (_inflight[url]) return;
39715             var controller = new AbortController();
39716             _inflight[url] = controller;
39717             d3_json(url, {
39718               signal: controller.signal
39719             }).then(function (result) {
39720               delete _inflight[url];
39721
39722               if (result && result.error) {
39723                 throw new Error(result.error);
39724               }
39725
39726               if (callback) callback(null, result);
39727             })["catch"](function (err) {
39728               delete _inflight[url];
39729               if (err.name === 'AbortError') return;
39730               if (callback) callback(err.message);
39731             });
39732           }
39733         };
39734
39735         var apibase$2 = 'https://openstreetcam.org';
39736         var maxResults$1 = 1000;
39737         var tileZoom$1 = 14;
39738         var tiler$4 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
39739         var dispatch$5 = dispatch('loadedImages');
39740         var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
39741
39742         var _oscCache;
39743
39744         var _oscSelectedImage;
39745
39746         var _loadViewerPromise$1;
39747
39748         function abortRequest$4(controller) {
39749           controller.abort();
39750         }
39751
39752         function maxPageAtZoom$1(z) {
39753           if (z < 15) return 2;
39754           if (z === 15) return 5;
39755           if (z === 16) return 10;
39756           if (z === 17) return 20;
39757           if (z === 18) return 40;
39758           if (z > 18) return 80;
39759         }
39760
39761         function loadTiles$1(which, url, projection) {
39762           var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
39763           var tiles = tiler$4.getTiles(projection); // abort inflight requests that are no longer needed
39764
39765           var cache = _oscCache[which];
39766           Object.keys(cache.inflight).forEach(function (k) {
39767             var wanted = tiles.find(function (tile) {
39768               return k.indexOf(tile.id + ',') === 0;
39769             });
39770
39771             if (!wanted) {
39772               abortRequest$4(cache.inflight[k]);
39773               delete cache.inflight[k];
39774             }
39775           });
39776           tiles.forEach(function (tile) {
39777             loadNextTilePage$1(which, currZoom, url, tile);
39778           });
39779         }
39780
39781         function loadNextTilePage$1(which, currZoom, url, tile) {
39782           var cache = _oscCache[which];
39783           var bbox = tile.extent.bbox();
39784           var maxPages = maxPageAtZoom$1(currZoom);
39785           var nextPage = cache.nextPage[tile.id] || 1;
39786           var params = utilQsString({
39787             ipp: maxResults$1,
39788             page: nextPage,
39789             // client_id: clientId,
39790             bbTopLeft: [bbox.maxY, bbox.minX].join(','),
39791             bbBottomRight: [bbox.minY, bbox.maxX].join(',')
39792           }, true);
39793           if (nextPage > maxPages) return;
39794           var id = tile.id + ',' + String(nextPage);
39795           if (cache.loaded[id] || cache.inflight[id]) return;
39796           var controller = new AbortController();
39797           cache.inflight[id] = controller;
39798           var options = {
39799             method: 'POST',
39800             signal: controller.signal,
39801             body: params,
39802             headers: {
39803               'Content-Type': 'application/x-www-form-urlencoded'
39804             }
39805           };
39806           d3_json(url, options).then(function (data) {
39807             cache.loaded[id] = true;
39808             delete cache.inflight[id];
39809
39810             if (!data || !data.currentPageItems || !data.currentPageItems.length) {
39811               throw new Error('No Data');
39812             }
39813
39814             var features = data.currentPageItems.map(function (item) {
39815               var loc = [+item.lng, +item.lat];
39816               var d;
39817
39818               if (which === 'images') {
39819                 d = {
39820                   loc: loc,
39821                   key: item.id,
39822                   ca: +item.heading,
39823                   captured_at: item.shot_date || item.date_added,
39824                   captured_by: item.username,
39825                   imagePath: item.lth_name,
39826                   sequence_id: item.sequence_id,
39827                   sequence_index: +item.sequence_index
39828                 }; // cache sequence info
39829
39830                 var seq = _oscCache.sequences[d.sequence_id];
39831
39832                 if (!seq) {
39833                   seq = {
39834                     rotation: 0,
39835                     images: []
39836                   };
39837                   _oscCache.sequences[d.sequence_id] = seq;
39838                 }
39839
39840                 seq.images[d.sequence_index] = d;
39841                 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
39842               }
39843
39844               return {
39845                 minX: loc[0],
39846                 minY: loc[1],
39847                 maxX: loc[0],
39848                 maxY: loc[1],
39849                 data: d
39850               };
39851             });
39852             cache.rtree.load(features);
39853
39854             if (data.currentPageItems.length === maxResults$1) {
39855               // more pages to load
39856               cache.nextPage[tile.id] = nextPage + 1;
39857               loadNextTilePage$1(which, currZoom, url, tile);
39858             } else {
39859               cache.nextPage[tile.id] = Infinity; // no more pages to load
39860             }
39861
39862             if (which === 'images') {
39863               dispatch$5.call('loadedImages');
39864             }
39865           })["catch"](function () {
39866             cache.loaded[id] = true;
39867             delete cache.inflight[id];
39868           });
39869         } // partition viewport into higher zoom tiles
39870
39871
39872         function partitionViewport$1(projection) {
39873           var z = geoScaleToZoom(projection.scale());
39874           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
39875
39876           var tiler = utilTiler().zoomExtent([z2, z2]);
39877           return tiler.getTiles(projection).map(function (tile) {
39878             return tile.extent;
39879           });
39880         } // no more than `limit` results per partition.
39881
39882
39883         function searchLimited$1(limit, projection, rtree) {
39884           limit = limit || 5;
39885           return partitionViewport$1(projection).reduce(function (result, extent) {
39886             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
39887               return d.data;
39888             });
39889             return found.length ? result.concat(found) : result;
39890           }, []);
39891         }
39892
39893         var serviceOpenstreetcam = {
39894           init: function init() {
39895             if (!_oscCache) {
39896               this.reset();
39897             }
39898
39899             this.event = utilRebind(this, dispatch$5, 'on');
39900           },
39901           reset: function reset() {
39902             if (_oscCache) {
39903               Object.values(_oscCache.images.inflight).forEach(abortRequest$4);
39904             }
39905
39906             _oscCache = {
39907               images: {
39908                 inflight: {},
39909                 loaded: {},
39910                 nextPage: {},
39911                 rtree: new RBush(),
39912                 forImageKey: {}
39913               },
39914               sequences: {}
39915             };
39916             _oscSelectedImage = null;
39917           },
39918           images: function images(projection) {
39919             var limit = 5;
39920             return searchLimited$1(limit, projection, _oscCache.images.rtree);
39921           },
39922           sequences: function sequences(projection) {
39923             var viewport = projection.clipExtent();
39924             var min = [viewport[0][0], viewport[1][1]];
39925             var max = [viewport[1][0], viewport[0][1]];
39926             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
39927             var sequenceKeys = {}; // all sequences for images in viewport
39928
39929             _oscCache.images.rtree.search(bbox).forEach(function (d) {
39930               sequenceKeys[d.data.sequence_id] = true;
39931             }); // make linestrings from those sequences
39932
39933
39934             var lineStrings = [];
39935             Object.keys(sequenceKeys).forEach(function (sequenceKey) {
39936               var seq = _oscCache.sequences[sequenceKey];
39937               var images = seq && seq.images;
39938
39939               if (images) {
39940                 lineStrings.push({
39941                   type: 'LineString',
39942                   coordinates: images.map(function (d) {
39943                     return d.loc;
39944                   }).filter(Boolean),
39945                   properties: {
39946                     captured_at: images[0] ? images[0].captured_at : null,
39947                     captured_by: images[0] ? images[0].captured_by : null,
39948                     key: sequenceKey
39949                   }
39950                 });
39951               }
39952             });
39953             return lineStrings;
39954           },
39955           cachedImage: function cachedImage(imageKey) {
39956             return _oscCache.images.forImageKey[imageKey];
39957           },
39958           loadImages: function loadImages(projection) {
39959             var url = apibase$2 + '/1.0/list/nearby-photos/';
39960             loadTiles$1('images', url, projection);
39961           },
39962           ensureViewerLoaded: function ensureViewerLoaded(context) {
39963             if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
39964
39965             var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
39966             var that = this;
39967             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
39968             wrapEnter.append('div').attr('class', 'photo-attribution fillD');
39969             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
39970             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
39971             controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
39972             controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
39973             controlsEnter.append('button').on('click.forward', step(1)).html('►');
39974             wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
39975
39976             context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
39977               imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
39978             });
39979
39980             function zoomPan(d3_event) {
39981               var t = d3_event.transform;
39982               context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
39983             }
39984
39985             function rotate(deg) {
39986               return function () {
39987                 if (!_oscSelectedImage) return;
39988                 var sequenceKey = _oscSelectedImage.sequence_id;
39989                 var sequence = _oscCache.sequences[sequenceKey];
39990                 if (!sequence) return;
39991                 var r = sequence.rotation || 0;
39992                 r += deg;
39993                 if (r > 180) r -= 360;
39994                 if (r < -180) r += 360;
39995                 sequence.rotation = r;
39996                 var wrap = context.container().select('.photoviewer .osc-wrapper');
39997                 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
39998                 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
39999               };
40000             }
40001
40002             function step(stepBy) {
40003               return function () {
40004                 if (!_oscSelectedImage) return;
40005                 var sequenceKey = _oscSelectedImage.sequence_id;
40006                 var sequence = _oscCache.sequences[sequenceKey];
40007                 if (!sequence) return;
40008                 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
40009                 var nextImage = sequence.images[nextIndex];
40010                 if (!nextImage) return;
40011                 context.map().centerEase(nextImage.loc);
40012                 that.selectImage(context, nextImage.key);
40013               };
40014             } // don't need any async loading so resolve immediately
40015
40016
40017             _loadViewerPromise$1 = Promise.resolve();
40018             return _loadViewerPromise$1;
40019           },
40020           showViewer: function showViewer(context) {
40021             var viewer = context.container().select('.photoviewer').classed('hide', false);
40022             var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
40023
40024             if (isHidden) {
40025               viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
40026               viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
40027             }
40028
40029             return this;
40030           },
40031           hideViewer: function hideViewer(context) {
40032             _oscSelectedImage = null;
40033             this.updateUrlImage(null);
40034             var viewer = context.container().select('.photoviewer');
40035             if (!viewer.empty()) viewer.datum(null);
40036             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
40037             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
40038             return this.setStyles(context, null, true);
40039           },
40040           selectImage: function selectImage(context, imageKey) {
40041             var d = this.cachedImage(imageKey);
40042             _oscSelectedImage = d;
40043             this.updateUrlImage(imageKey);
40044             var viewer = context.container().select('.photoviewer');
40045             if (!viewer.empty()) viewer.datum(d);
40046             this.setStyles(context, null, true);
40047             context.container().selectAll('.icon-sign').classed('currentView', false);
40048             if (!d) return this;
40049             var wrap = context.container().select('.photoviewer .osc-wrapper');
40050             var imageWrap = wrap.selectAll('.osc-image-wrap');
40051             var attribution = wrap.selectAll('.photo-attribution').html('');
40052             wrap.transition().duration(100).call(imgZoom.transform, identity$2);
40053             imageWrap.selectAll('.osc-image').remove();
40054
40055             if (d) {
40056               var sequence = _oscCache.sequences[d.sequence_id];
40057               var r = sequence && sequence.rotation || 0;
40058               imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$2 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
40059
40060               if (d.captured_by) {
40061                 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
40062                 attribution.append('span').html('|');
40063               }
40064
40065               if (d.captured_at) {
40066                 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
40067                 attribution.append('span').html('|');
40068               }
40069
40070               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');
40071             }
40072
40073             return this;
40074
40075             function localeDateString(s) {
40076               if (!s) return null;
40077               var options = {
40078                 day: 'numeric',
40079                 month: 'short',
40080                 year: 'numeric'
40081               };
40082               var d = new Date(s);
40083               if (isNaN(d.getTime())) return null;
40084               return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
40085             }
40086           },
40087           getSelectedImage: function getSelectedImage() {
40088             return _oscSelectedImage;
40089           },
40090           getSequenceKeyForImage: function getSequenceKeyForImage(d) {
40091             return d && d.sequence_id;
40092           },
40093           // Updates the currently highlighted sequence and selected bubble.
40094           // Reset is only necessary when interacting with the viewport because
40095           // this implicitly changes the currently selected bubble/sequence
40096           setStyles: function setStyles(context, hovered, reset) {
40097             if (reset) {
40098               // reset all layers
40099               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
40100               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
40101             }
40102
40103             var hoveredImageKey = hovered && hovered.key;
40104             var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
40105             var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
40106             var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
40107               return d.key;
40108             }) || [];
40109             var viewer = context.container().select('.photoviewer');
40110             var selected = viewer.empty() ? undefined : viewer.datum();
40111             var selectedImageKey = selected && selected.key;
40112             var selectedSequenceKey = this.getSequenceKeyForImage(selected);
40113             var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
40114             var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
40115               return d.key;
40116             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
40117
40118             var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
40119             context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
40120               return highlightedImageKeys.indexOf(d.key) !== -1;
40121             }).classed('hovered', function (d) {
40122               return d.key === hoveredImageKey;
40123             }).classed('currentView', function (d) {
40124               return d.key === selectedImageKey;
40125             });
40126             context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
40127               return d.properties.key === hoveredSequenceKey;
40128             }).classed('currentView', function (d) {
40129               return d.properties.key === selectedSequenceKey;
40130             }); // update viewfields if needed
40131
40132             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
40133
40134             function viewfieldPath() {
40135               var d = this.parentNode.__data__;
40136
40137               if (d.pano && d.key !== selectedImageKey) {
40138                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
40139               } else {
40140                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
40141               }
40142             }
40143
40144             return this;
40145           },
40146           updateUrlImage: function updateUrlImage(imageKey) {
40147             if (!window.mocha) {
40148               var hash = utilStringQs(window.location.hash);
40149
40150               if (imageKey) {
40151                 hash.photo = 'openstreetcam/' + imageKey;
40152               } else {
40153                 delete hash.photo;
40154               }
40155
40156               window.location.replace('#' + utilQsString(hash, true));
40157             }
40158           },
40159           cache: function cache() {
40160             return _oscCache;
40161           }
40162         };
40163
40164         var FORCED$f = fails(function () {
40165           return new Date(NaN).toJSON() !== null
40166             || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
40167         });
40168
40169         // `Date.prototype.toJSON` method
40170         // https://tc39.github.io/ecma262/#sec-date.prototype.tojson
40171         _export({ target: 'Date', proto: true, forced: FORCED$f }, {
40172           // eslint-disable-next-line no-unused-vars
40173           toJSON: function toJSON(key) {
40174             var O = toObject(this);
40175             var pv = toPrimitive(O);
40176             return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
40177           }
40178         });
40179
40180         // `URL.prototype.toJSON` method
40181         // https://url.spec.whatwg.org/#dom-url-tojson
40182         _export({ target: 'URL', proto: true, enumerable: true }, {
40183           toJSON: function toJSON() {
40184             return URL.prototype.toString.call(this);
40185           }
40186         });
40187
40188         /**
40189          * Checks if `value` is the
40190          * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
40191          * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
40192          *
40193          * @static
40194          * @memberOf _
40195          * @since 0.1.0
40196          * @category Lang
40197          * @param {*} value The value to check.
40198          * @returns {boolean} Returns `true` if `value` is an object, else `false`.
40199          * @example
40200          *
40201          * _.isObject({});
40202          * // => true
40203          *
40204          * _.isObject([1, 2, 3]);
40205          * // => true
40206          *
40207          * _.isObject(_.noop);
40208          * // => true
40209          *
40210          * _.isObject(null);
40211          * // => false
40212          */
40213         function isObject$1(value) {
40214           var type = _typeof(value);
40215
40216           return value != null && (type == 'object' || type == 'function');
40217         }
40218
40219         /** Detect free variable `global` from Node.js. */
40220         var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
40221
40222         /** Detect free variable `self`. */
40223
40224         var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
40225         /** Used as a reference to the global object. */
40226
40227         var root$1 = freeGlobal || freeSelf || Function('return this')();
40228
40229         /**
40230          * Gets the timestamp of the number of milliseconds that have elapsed since
40231          * the Unix epoch (1 January 1970 00:00:00 UTC).
40232          *
40233          * @static
40234          * @memberOf _
40235          * @since 2.4.0
40236          * @category Date
40237          * @returns {number} Returns the timestamp.
40238          * @example
40239          *
40240          * _.defer(function(stamp) {
40241          *   console.log(_.now() - stamp);
40242          * }, _.now());
40243          * // => Logs the number of milliseconds it took for the deferred invocation.
40244          */
40245
40246         var now$1 = function now() {
40247           return root$1.Date.now();
40248         };
40249
40250         /** Built-in value references. */
40251
40252         var _Symbol = root$1.Symbol;
40253
40254         /** Used for built-in method references. */
40255
40256         var objectProto = Object.prototype;
40257         /** Used to check objects for own properties. */
40258
40259         var hasOwnProperty$1 = objectProto.hasOwnProperty;
40260         /**
40261          * Used to resolve the
40262          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40263          * of values.
40264          */
40265
40266         var nativeObjectToString = objectProto.toString;
40267         /** Built-in value references. */
40268
40269         var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
40270         /**
40271          * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
40272          *
40273          * @private
40274          * @param {*} value The value to query.
40275          * @returns {string} Returns the raw `toStringTag`.
40276          */
40277
40278         function getRawTag(value) {
40279           var isOwn = hasOwnProperty$1.call(value, symToStringTag),
40280               tag = value[symToStringTag];
40281
40282           try {
40283             value[symToStringTag] = undefined;
40284             var unmasked = true;
40285           } catch (e) {}
40286
40287           var result = nativeObjectToString.call(value);
40288
40289           if (unmasked) {
40290             if (isOwn) {
40291               value[symToStringTag] = tag;
40292             } else {
40293               delete value[symToStringTag];
40294             }
40295           }
40296
40297           return result;
40298         }
40299
40300         /** Used for built-in method references. */
40301         var objectProto$1 = Object.prototype;
40302         /**
40303          * Used to resolve the
40304          * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
40305          * of values.
40306          */
40307
40308         var nativeObjectToString$1 = objectProto$1.toString;
40309         /**
40310          * Converts `value` to a string using `Object.prototype.toString`.
40311          *
40312          * @private
40313          * @param {*} value The value to convert.
40314          * @returns {string} Returns the converted string.
40315          */
40316
40317         function objectToString$1(value) {
40318           return nativeObjectToString$1.call(value);
40319         }
40320
40321         /** `Object#toString` result references. */
40322
40323         var nullTag = '[object Null]',
40324             undefinedTag = '[object Undefined]';
40325         /** Built-in value references. */
40326
40327         var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
40328         /**
40329          * The base implementation of `getTag` without fallbacks for buggy environments.
40330          *
40331          * @private
40332          * @param {*} value The value to query.
40333          * @returns {string} Returns the `toStringTag`.
40334          */
40335
40336         function baseGetTag(value) {
40337           if (value == null) {
40338             return value === undefined ? undefinedTag : nullTag;
40339           }
40340
40341           return symToStringTag$1 && symToStringTag$1 in Object(value) ? getRawTag(value) : objectToString$1(value);
40342         }
40343
40344         /**
40345          * Checks if `value` is object-like. A value is object-like if it's not `null`
40346          * and has a `typeof` result of "object".
40347          *
40348          * @static
40349          * @memberOf _
40350          * @since 4.0.0
40351          * @category Lang
40352          * @param {*} value The value to check.
40353          * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
40354          * @example
40355          *
40356          * _.isObjectLike({});
40357          * // => true
40358          *
40359          * _.isObjectLike([1, 2, 3]);
40360          * // => true
40361          *
40362          * _.isObjectLike(_.noop);
40363          * // => false
40364          *
40365          * _.isObjectLike(null);
40366          * // => false
40367          */
40368         function isObjectLike(value) {
40369           return value != null && _typeof(value) == 'object';
40370         }
40371
40372         /** `Object#toString` result references. */
40373
40374         var symbolTag = '[object Symbol]';
40375         /**
40376          * Checks if `value` is classified as a `Symbol` primitive or object.
40377          *
40378          * @static
40379          * @memberOf _
40380          * @since 4.0.0
40381          * @category Lang
40382          * @param {*} value The value to check.
40383          * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
40384          * @example
40385          *
40386          * _.isSymbol(Symbol.iterator);
40387          * // => true
40388          *
40389          * _.isSymbol('abc');
40390          * // => false
40391          */
40392
40393         function isSymbol$1(value) {
40394           return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
40395         }
40396
40397         /** Used as references for various `Number` constants. */
40398
40399         var NAN = 0 / 0;
40400         /** Used to match leading and trailing whitespace. */
40401
40402         var reTrim = /^\s+|\s+$/g;
40403         /** Used to detect bad signed hexadecimal string values. */
40404
40405         var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
40406         /** Used to detect binary string values. */
40407
40408         var reIsBinary = /^0b[01]+$/i;
40409         /** Used to detect octal string values. */
40410
40411         var reIsOctal = /^0o[0-7]+$/i;
40412         /** Built-in method references without a dependency on `root`. */
40413
40414         var freeParseInt = parseInt;
40415         /**
40416          * Converts `value` to a number.
40417          *
40418          * @static
40419          * @memberOf _
40420          * @since 4.0.0
40421          * @category Lang
40422          * @param {*} value The value to process.
40423          * @returns {number} Returns the number.
40424          * @example
40425          *
40426          * _.toNumber(3.2);
40427          * // => 3.2
40428          *
40429          * _.toNumber(Number.MIN_VALUE);
40430          * // => 5e-324
40431          *
40432          * _.toNumber(Infinity);
40433          * // => Infinity
40434          *
40435          * _.toNumber('3.2');
40436          * // => 3.2
40437          */
40438
40439         function toNumber$1(value) {
40440           if (typeof value == 'number') {
40441             return value;
40442           }
40443
40444           if (isSymbol$1(value)) {
40445             return NAN;
40446           }
40447
40448           if (isObject$1(value)) {
40449             var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
40450             value = isObject$1(other) ? other + '' : other;
40451           }
40452
40453           if (typeof value != 'string') {
40454             return value === 0 ? value : +value;
40455           }
40456
40457           value = value.replace(reTrim, '');
40458           var isBinary = reIsBinary.test(value);
40459           return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
40460         }
40461
40462         /** Error message constants. */
40463
40464         var FUNC_ERROR_TEXT = 'Expected a function';
40465         /* Built-in method references for those with the same name as other `lodash` methods. */
40466
40467         var nativeMax = Math.max,
40468             nativeMin = Math.min;
40469         /**
40470          * Creates a debounced function that delays invoking `func` until after `wait`
40471          * milliseconds have elapsed since the last time the debounced function was
40472          * invoked. The debounced function comes with a `cancel` method to cancel
40473          * delayed `func` invocations and a `flush` method to immediately invoke them.
40474          * Provide `options` to indicate whether `func` should be invoked on the
40475          * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
40476          * with the last arguments provided to the debounced function. Subsequent
40477          * calls to the debounced function return the result of the last `func`
40478          * invocation.
40479          *
40480          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40481          * invoked on the trailing edge of the timeout only if the debounced function
40482          * is invoked more than once during the `wait` timeout.
40483          *
40484          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40485          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40486          *
40487          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40488          * for details over the differences between `_.debounce` and `_.throttle`.
40489          *
40490          * @static
40491          * @memberOf _
40492          * @since 0.1.0
40493          * @category Function
40494          * @param {Function} func The function to debounce.
40495          * @param {number} [wait=0] The number of milliseconds to delay.
40496          * @param {Object} [options={}] The options object.
40497          * @param {boolean} [options.leading=false]
40498          *  Specify invoking on the leading edge of the timeout.
40499          * @param {number} [options.maxWait]
40500          *  The maximum time `func` is allowed to be delayed before it's invoked.
40501          * @param {boolean} [options.trailing=true]
40502          *  Specify invoking on the trailing edge of the timeout.
40503          * @returns {Function} Returns the new debounced function.
40504          * @example
40505          *
40506          * // Avoid costly calculations while the window size is in flux.
40507          * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
40508          *
40509          * // Invoke `sendMail` when clicked, debouncing subsequent calls.
40510          * jQuery(element).on('click', _.debounce(sendMail, 300, {
40511          *   'leading': true,
40512          *   'trailing': false
40513          * }));
40514          *
40515          * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
40516          * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
40517          * var source = new EventSource('/stream');
40518          * jQuery(source).on('message', debounced);
40519          *
40520          * // Cancel the trailing debounced invocation.
40521          * jQuery(window).on('popstate', debounced.cancel);
40522          */
40523
40524         function debounce(func, wait, options) {
40525           var lastArgs,
40526               lastThis,
40527               maxWait,
40528               result,
40529               timerId,
40530               lastCallTime,
40531               lastInvokeTime = 0,
40532               leading = false,
40533               maxing = false,
40534               trailing = true;
40535
40536           if (typeof func != 'function') {
40537             throw new TypeError(FUNC_ERROR_TEXT);
40538           }
40539
40540           wait = toNumber$1(wait) || 0;
40541
40542           if (isObject$1(options)) {
40543             leading = !!options.leading;
40544             maxing = 'maxWait' in options;
40545             maxWait = maxing ? nativeMax(toNumber$1(options.maxWait) || 0, wait) : maxWait;
40546             trailing = 'trailing' in options ? !!options.trailing : trailing;
40547           }
40548
40549           function invokeFunc(time) {
40550             var args = lastArgs,
40551                 thisArg = lastThis;
40552             lastArgs = lastThis = undefined;
40553             lastInvokeTime = time;
40554             result = func.apply(thisArg, args);
40555             return result;
40556           }
40557
40558           function leadingEdge(time) {
40559             // Reset any `maxWait` timer.
40560             lastInvokeTime = time; // Start the timer for the trailing edge.
40561
40562             timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
40563
40564             return leading ? invokeFunc(time) : result;
40565           }
40566
40567           function remainingWait(time) {
40568             var timeSinceLastCall = time - lastCallTime,
40569                 timeSinceLastInvoke = time - lastInvokeTime,
40570                 timeWaiting = wait - timeSinceLastCall;
40571             return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
40572           }
40573
40574           function shouldInvoke(time) {
40575             var timeSinceLastCall = time - lastCallTime,
40576                 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
40577             // trailing edge, the system time has gone backwards and we're treating
40578             // it as the trailing edge, or we've hit the `maxWait` limit.
40579
40580             return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
40581           }
40582
40583           function timerExpired() {
40584             var time = now$1();
40585
40586             if (shouldInvoke(time)) {
40587               return trailingEdge(time);
40588             } // Restart the timer.
40589
40590
40591             timerId = setTimeout(timerExpired, remainingWait(time));
40592           }
40593
40594           function trailingEdge(time) {
40595             timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
40596             // debounced at least once.
40597
40598             if (trailing && lastArgs) {
40599               return invokeFunc(time);
40600             }
40601
40602             lastArgs = lastThis = undefined;
40603             return result;
40604           }
40605
40606           function cancel() {
40607             if (timerId !== undefined) {
40608               clearTimeout(timerId);
40609             }
40610
40611             lastInvokeTime = 0;
40612             lastArgs = lastCallTime = lastThis = timerId = undefined;
40613           }
40614
40615           function flush() {
40616             return timerId === undefined ? result : trailingEdge(now$1());
40617           }
40618
40619           function debounced() {
40620             var time = now$1(),
40621                 isInvoking = shouldInvoke(time);
40622             lastArgs = arguments;
40623             lastThis = this;
40624             lastCallTime = time;
40625
40626             if (isInvoking) {
40627               if (timerId === undefined) {
40628                 return leadingEdge(lastCallTime);
40629               }
40630
40631               if (maxing) {
40632                 // Handle invocations in a tight loop.
40633                 clearTimeout(timerId);
40634                 timerId = setTimeout(timerExpired, wait);
40635                 return invokeFunc(lastCallTime);
40636               }
40637             }
40638
40639             if (timerId === undefined) {
40640               timerId = setTimeout(timerExpired, wait);
40641             }
40642
40643             return result;
40644           }
40645
40646           debounced.cancel = cancel;
40647           debounced.flush = flush;
40648           return debounced;
40649         }
40650
40651         /** Error message constants. */
40652
40653         var FUNC_ERROR_TEXT$1 = 'Expected a function';
40654         /**
40655          * Creates a throttled function that only invokes `func` at most once per
40656          * every `wait` milliseconds. The throttled function comes with a `cancel`
40657          * method to cancel delayed `func` invocations and a `flush` method to
40658          * immediately invoke them. Provide `options` to indicate whether `func`
40659          * should be invoked on the leading and/or trailing edge of the `wait`
40660          * timeout. The `func` is invoked with the last arguments provided to the
40661          * throttled function. Subsequent calls to the throttled function return the
40662          * result of the last `func` invocation.
40663          *
40664          * **Note:** If `leading` and `trailing` options are `true`, `func` is
40665          * invoked on the trailing edge of the timeout only if the throttled function
40666          * is invoked more than once during the `wait` timeout.
40667          *
40668          * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
40669          * until to the next tick, similar to `setTimeout` with a timeout of `0`.
40670          *
40671          * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
40672          * for details over the differences between `_.throttle` and `_.debounce`.
40673          *
40674          * @static
40675          * @memberOf _
40676          * @since 0.1.0
40677          * @category Function
40678          * @param {Function} func The function to throttle.
40679          * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
40680          * @param {Object} [options={}] The options object.
40681          * @param {boolean} [options.leading=true]
40682          *  Specify invoking on the leading edge of the timeout.
40683          * @param {boolean} [options.trailing=true]
40684          *  Specify invoking on the trailing edge of the timeout.
40685          * @returns {Function} Returns the new throttled function.
40686          * @example
40687          *
40688          * // Avoid excessively updating the position while scrolling.
40689          * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
40690          *
40691          * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
40692          * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
40693          * jQuery(element).on('click', throttled);
40694          *
40695          * // Cancel the trailing throttled invocation.
40696          * jQuery(window).on('popstate', throttled.cancel);
40697          */
40698
40699         function throttle(func, wait, options) {
40700           var leading = true,
40701               trailing = true;
40702
40703           if (typeof func != 'function') {
40704             throw new TypeError(FUNC_ERROR_TEXT$1);
40705           }
40706
40707           if (isObject$1(options)) {
40708             leading = 'leading' in options ? !!options.leading : leading;
40709             trailing = 'trailing' in options ? !!options.trailing : trailing;
40710           }
40711
40712           return debounce(func, wait, {
40713             'leading': leading,
40714             'maxWait': wait,
40715             'trailing': trailing
40716           });
40717         }
40718
40719         var hashes = createCommonjsModule(function (module, exports) {
40720           /**
40721            * jshashes - https://github.com/h2non/jshashes
40722            * Released under the "New BSD" license
40723            *
40724            * Algorithms specification:
40725            *
40726            * MD5 - http://www.ietf.org/rfc/rfc1321.txt
40727            * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
40728            * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40729            * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40730            * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
40731            * HMAC - http://www.ietf.org/rfc/rfc2104.txt
40732            */
40733           (function () {
40734             var Hashes;
40735
40736             function utf8Encode(str) {
40737               var x,
40738                   y,
40739                   output = '',
40740                   i = -1,
40741                   l;
40742
40743               if (str && str.length) {
40744                 l = str.length;
40745
40746                 while ((i += 1) < l) {
40747                   /* Decode utf-16 surrogate pairs */
40748                   x = str.charCodeAt(i);
40749                   y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
40750
40751                   if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
40752                     x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
40753                     i += 1;
40754                   }
40755                   /* Encode output as utf-8 */
40756
40757
40758                   if (x <= 0x7F) {
40759                     output += String.fromCharCode(x);
40760                   } else if (x <= 0x7FF) {
40761                     output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
40762                   } else if (x <= 0xFFFF) {
40763                     output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40764                   } else if (x <= 0x1FFFFF) {
40765                     output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
40766                   }
40767                 }
40768               }
40769
40770               return output;
40771             }
40772
40773             function utf8Decode(str) {
40774               var i,
40775                   ac,
40776                   c1,
40777                   c2,
40778                   c3,
40779                   arr = [],
40780                   l;
40781               i = ac = c1 = c2 = c3 = 0;
40782
40783               if (str && str.length) {
40784                 l = str.length;
40785                 str += '';
40786
40787                 while (i < l) {
40788                   c1 = str.charCodeAt(i);
40789                   ac += 1;
40790
40791                   if (c1 < 128) {
40792                     arr[ac] = String.fromCharCode(c1);
40793                     i += 1;
40794                   } else if (c1 > 191 && c1 < 224) {
40795                     c2 = str.charCodeAt(i + 1);
40796                     arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
40797                     i += 2;
40798                   } else {
40799                     c2 = str.charCodeAt(i + 1);
40800                     c3 = str.charCodeAt(i + 2);
40801                     arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
40802                     i += 3;
40803                   }
40804                 }
40805               }
40806
40807               return arr.join('');
40808             }
40809             /**
40810              * Add integers, wrapping at 2^32. This uses 16-bit operations internally
40811              * to work around bugs in some JS interpreters.
40812              */
40813
40814
40815             function safe_add(x, y) {
40816               var lsw = (x & 0xFFFF) + (y & 0xFFFF),
40817                   msw = (x >> 16) + (y >> 16) + (lsw >> 16);
40818               return msw << 16 | lsw & 0xFFFF;
40819             }
40820             /**
40821              * Bitwise rotate a 32-bit number to the left.
40822              */
40823
40824
40825             function bit_rol(num, cnt) {
40826               return num << cnt | num >>> 32 - cnt;
40827             }
40828             /**
40829              * Convert a raw string to a hex string
40830              */
40831
40832
40833             function rstr2hex(input, hexcase) {
40834               var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
40835                   output = '',
40836                   x,
40837                   i = 0,
40838                   l = input.length;
40839
40840               for (; i < l; i += 1) {
40841                 x = input.charCodeAt(i);
40842                 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
40843               }
40844
40845               return output;
40846             }
40847             /**
40848              * Convert an array of big-endian words to a string
40849              */
40850
40851
40852             function binb2rstr(input) {
40853               var i,
40854                   l = input.length * 32,
40855                   output = '';
40856
40857               for (i = 0; i < l; i += 8) {
40858                 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
40859               }
40860
40861               return output;
40862             }
40863             /**
40864              * Convert an array of little-endian words to a string
40865              */
40866
40867
40868             function binl2rstr(input) {
40869               var i,
40870                   l = input.length * 32,
40871                   output = '';
40872
40873               for (i = 0; i < l; i += 8) {
40874                 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
40875               }
40876
40877               return output;
40878             }
40879             /**
40880              * Convert a raw string to an array of little-endian words
40881              * Characters >255 have their high-byte silently ignored.
40882              */
40883
40884
40885             function rstr2binl(input) {
40886               var i,
40887                   l = input.length * 8,
40888                   output = Array(input.length >> 2),
40889                   lo = output.length;
40890
40891               for (i = 0; i < lo; i += 1) {
40892                 output[i] = 0;
40893               }
40894
40895               for (i = 0; i < l; i += 8) {
40896                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
40897               }
40898
40899               return output;
40900             }
40901             /**
40902              * Convert a raw string to an array of big-endian words
40903              * Characters >255 have their high-byte silently ignored.
40904              */
40905
40906
40907             function rstr2binb(input) {
40908               var i,
40909                   l = input.length * 8,
40910                   output = Array(input.length >> 2),
40911                   lo = output.length;
40912
40913               for (i = 0; i < lo; i += 1) {
40914                 output[i] = 0;
40915               }
40916
40917               for (i = 0; i < l; i += 8) {
40918                 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
40919               }
40920
40921               return output;
40922             }
40923             /**
40924              * Convert a raw string to an arbitrary string encoding
40925              */
40926
40927
40928             function rstr2any(input, encoding) {
40929               var divisor = encoding.length,
40930                   remainders = Array(),
40931                   i,
40932                   q,
40933                   x,
40934                   ld,
40935                   quotient,
40936                   dividend,
40937                   output,
40938                   full_length;
40939               /* Convert to an array of 16-bit big-endian values, forming the dividend */
40940
40941               dividend = Array(Math.ceil(input.length / 2));
40942               ld = dividend.length;
40943
40944               for (i = 0; i < ld; i += 1) {
40945                 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
40946               }
40947               /**
40948                * Repeatedly perform a long division. The binary array forms the dividend,
40949                * the length of the encoding is the divisor. Once computed, the quotient
40950                * forms the dividend for the next step. We stop when the dividend is zerHashes.
40951                * All remainders are stored for later use.
40952                */
40953
40954
40955               while (dividend.length > 0) {
40956                 quotient = Array();
40957                 x = 0;
40958
40959                 for (i = 0; i < dividend.length; i += 1) {
40960                   x = (x << 16) + dividend[i];
40961                   q = Math.floor(x / divisor);
40962                   x -= q * divisor;
40963
40964                   if (quotient.length > 0 || q > 0) {
40965                     quotient[quotient.length] = q;
40966                   }
40967                 }
40968
40969                 remainders[remainders.length] = x;
40970                 dividend = quotient;
40971               }
40972               /* Convert the remainders to the output string */
40973
40974
40975               output = '';
40976
40977               for (i = remainders.length - 1; i >= 0; i--) {
40978                 output += encoding.charAt(remainders[i]);
40979               }
40980               /* Append leading zero equivalents */
40981
40982
40983               full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
40984
40985               for (i = output.length; i < full_length; i += 1) {
40986                 output = encoding[0] + output;
40987               }
40988
40989               return output;
40990             }
40991             /**
40992              * Convert a raw string to a base-64 string
40993              */
40994
40995
40996             function rstr2b64(input, b64pad) {
40997               var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
40998                   output = '',
40999                   len = input.length,
41000                   i,
41001                   j,
41002                   triplet;
41003               b64pad = b64pad || '=';
41004
41005               for (i = 0; i < len; i += 3) {
41006                 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
41007
41008                 for (j = 0; j < 4; j += 1) {
41009                   if (i * 8 + j * 6 > input.length * 8) {
41010                     output += b64pad;
41011                   } else {
41012                     output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
41013                   }
41014                 }
41015               }
41016
41017               return output;
41018             }
41019
41020             Hashes = {
41021               /**
41022                * @property {String} version
41023                * @readonly
41024                */
41025               VERSION: '1.0.6',
41026
41027               /**
41028                * @member Hashes
41029                * @class Base64
41030                * @constructor
41031                */
41032               Base64: function Base64() {
41033                 // private properties
41034                 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
41035                     pad = '=',
41036                     // URL encoding support @todo
41037                 utf8 = true; // by default enable UTF-8 support encoding
41038                 // public method for encoding
41039
41040                 this.encode = function (input) {
41041                   var i,
41042                       j,
41043                       triplet,
41044                       output = '',
41045                       len = input.length;
41046                   pad = pad || '=';
41047                   input = utf8 ? utf8Encode(input) : input;
41048
41049                   for (i = 0; i < len; i += 3) {
41050                     triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
41051
41052                     for (j = 0; j < 4; j += 1) {
41053                       if (i * 8 + j * 6 > len * 8) {
41054                         output += pad;
41055                       } else {
41056                         output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
41057                       }
41058                     }
41059                   }
41060
41061                   return output;
41062                 }; // public method for decoding
41063
41064
41065                 this.decode = function (input) {
41066                   // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
41067                   var i,
41068                       o1,
41069                       o2,
41070                       o3,
41071                       h1,
41072                       h2,
41073                       h3,
41074                       h4,
41075                       bits,
41076                       ac,
41077                       dec = '',
41078                       arr = [];
41079
41080                   if (!input) {
41081                     return input;
41082                   }
41083
41084                   i = ac = 0;
41085                   input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
41086                   //input += '';
41087
41088                   do {
41089                     // unpack four hexets into three octets using index points in b64
41090                     h1 = tab.indexOf(input.charAt(i += 1));
41091                     h2 = tab.indexOf(input.charAt(i += 1));
41092                     h3 = tab.indexOf(input.charAt(i += 1));
41093                     h4 = tab.indexOf(input.charAt(i += 1));
41094                     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
41095                     o1 = bits >> 16 & 0xff;
41096                     o2 = bits >> 8 & 0xff;
41097                     o3 = bits & 0xff;
41098                     ac += 1;
41099
41100                     if (h3 === 64) {
41101                       arr[ac] = String.fromCharCode(o1);
41102                     } else if (h4 === 64) {
41103                       arr[ac] = String.fromCharCode(o1, o2);
41104                     } else {
41105                       arr[ac] = String.fromCharCode(o1, o2, o3);
41106                     }
41107                   } while (i < input.length);
41108
41109                   dec = arr.join('');
41110                   dec = utf8 ? utf8Decode(dec) : dec;
41111                   return dec;
41112                 }; // set custom pad string
41113
41114
41115                 this.setPad = function (str) {
41116                   pad = str || pad;
41117                   return this;
41118                 }; // set custom tab string characters
41119
41120
41121                 this.setTab = function (str) {
41122                   tab = str || tab;
41123                   return this;
41124                 };
41125
41126                 this.setUTF8 = function (bool) {
41127                   if (typeof bool === 'boolean') {
41128                     utf8 = bool;
41129                   }
41130
41131                   return this;
41132                 };
41133               },
41134
41135               /**
41136                * CRC-32 calculation
41137                * @member Hashes
41138                * @method CRC32
41139                * @static
41140                * @param {String} str Input String
41141                * @return {String}
41142                */
41143               CRC32: function CRC32(str) {
41144                 var crc = 0,
41145                     x = 0,
41146                     y = 0,
41147                     table,
41148                     i,
41149                     iTop;
41150                 str = utf8Encode(str);
41151                 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('');
41152                 crc = crc ^ -1;
41153
41154                 for (i = 0, iTop = str.length; i < iTop; i += 1) {
41155                   y = (crc ^ str.charCodeAt(i)) & 0xFF;
41156                   x = '0x' + table.substr(y * 9, 8);
41157                   crc = crc >>> 8 ^ x;
41158                 } // always return a positive number (that's what >>> 0 does)
41159
41160
41161                 return (crc ^ -1) >>> 0;
41162               },
41163
41164               /**
41165                * @member Hashes
41166                * @class MD5
41167                * @constructor
41168                * @param {Object} [config]
41169                *
41170                * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
41171                * Digest Algorithm, as defined in RFC 1321.
41172                * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
41173                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41174                * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
41175                */
41176               MD5: function MD5(options) {
41177                 /**
41178                  * Private config properties. You may need to tweak these to be compatible with
41179                  * the server-side, but the defaults work in most cases.
41180                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41181                  */
41182                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41183                     // hexadecimal output case format. false - lowercase; true - uppercase
41184                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41185                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41186                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41187                 // privileged (public) methods
41188
41189                 this.hex = function (s) {
41190                   return rstr2hex(rstr(s), hexcase);
41191                 };
41192
41193                 this.b64 = function (s) {
41194                   return rstr2b64(rstr(s), b64pad);
41195                 };
41196
41197                 this.any = function (s, e) {
41198                   return rstr2any(rstr(s), e);
41199                 };
41200
41201                 this.raw = function (s) {
41202                   return rstr(s);
41203                 };
41204
41205                 this.hex_hmac = function (k, d) {
41206                   return rstr2hex(rstr_hmac(k, d), hexcase);
41207                 };
41208
41209                 this.b64_hmac = function (k, d) {
41210                   return rstr2b64(rstr_hmac(k, d), b64pad);
41211                 };
41212
41213                 this.any_hmac = function (k, d, e) {
41214                   return rstr2any(rstr_hmac(k, d), e);
41215                 };
41216                 /**
41217                  * Perform a simple self-test to see if the VM is working
41218                  * @return {String} Hexadecimal hash sample
41219                  */
41220
41221
41222                 this.vm_test = function () {
41223                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41224                 };
41225                 /**
41226                  * Enable/disable uppercase hexadecimal returned string
41227                  * @param {Boolean}
41228                  * @return {Object} this
41229                  */
41230
41231
41232                 this.setUpperCase = function (a) {
41233                   if (typeof a === 'boolean') {
41234                     hexcase = a;
41235                   }
41236
41237                   return this;
41238                 };
41239                 /**
41240                  * Defines a base64 pad string
41241                  * @param {String} Pad
41242                  * @return {Object} this
41243                  */
41244
41245
41246                 this.setPad = function (a) {
41247                   b64pad = a || b64pad;
41248                   return this;
41249                 };
41250                 /**
41251                  * Defines a base64 pad string
41252                  * @param {Boolean}
41253                  * @return {Object} [this]
41254                  */
41255
41256
41257                 this.setUTF8 = function (a) {
41258                   if (typeof a === 'boolean') {
41259                     utf8 = a;
41260                   }
41261
41262                   return this;
41263                 }; // private methods
41264
41265                 /**
41266                  * Calculate the MD5 of a raw string
41267                  */
41268
41269
41270                 function rstr(s) {
41271                   s = utf8 ? utf8Encode(s) : s;
41272                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
41273                 }
41274                 /**
41275                  * Calculate the HMAC-MD5, of a key and some data (raw strings)
41276                  */
41277
41278
41279                 function rstr_hmac(key, data) {
41280                   var bkey, ipad, opad, hash, i;
41281                   key = utf8 ? utf8Encode(key) : key;
41282                   data = utf8 ? utf8Encode(data) : data;
41283                   bkey = rstr2binl(key);
41284
41285                   if (bkey.length > 16) {
41286                     bkey = binl(bkey, key.length * 8);
41287                   }
41288
41289                   ipad = Array(16), opad = Array(16);
41290
41291                   for (i = 0; i < 16; i += 1) {
41292                     ipad[i] = bkey[i] ^ 0x36363636;
41293                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41294                   }
41295
41296                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
41297                   return binl2rstr(binl(opad.concat(hash), 512 + 128));
41298                 }
41299                 /**
41300                  * Calculate the MD5 of an array of little-endian words, and a bit length.
41301                  */
41302
41303
41304                 function binl(x, len) {
41305                   var i,
41306                       olda,
41307                       oldb,
41308                       oldc,
41309                       oldd,
41310                       a = 1732584193,
41311                       b = -271733879,
41312                       c = -1732584194,
41313                       d = 271733878;
41314                   /* append padding */
41315
41316                   x[len >> 5] |= 0x80 << len % 32;
41317                   x[(len + 64 >>> 9 << 4) + 14] = len;
41318
41319                   for (i = 0; i < x.length; i += 16) {
41320                     olda = a;
41321                     oldb = b;
41322                     oldc = c;
41323                     oldd = d;
41324                     a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
41325                     d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
41326                     c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
41327                     b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
41328                     a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
41329                     d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
41330                     c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
41331                     b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
41332                     a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
41333                     d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
41334                     c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
41335                     b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
41336                     a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
41337                     d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
41338                     c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
41339                     b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
41340                     a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
41341                     d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
41342                     c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
41343                     b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
41344                     a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
41345                     d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
41346                     c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
41347                     b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
41348                     a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
41349                     d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
41350                     c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
41351                     b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
41352                     a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
41353                     d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
41354                     c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
41355                     b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
41356                     a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
41357                     d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
41358                     c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
41359                     b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
41360                     a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
41361                     d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
41362                     c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
41363                     b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
41364                     a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
41365                     d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
41366                     c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
41367                     b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
41368                     a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
41369                     d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
41370                     c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
41371                     b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
41372                     a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
41373                     d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
41374                     c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
41375                     b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
41376                     a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
41377                     d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
41378                     c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
41379                     b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
41380                     a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
41381                     d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
41382                     c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
41383                     b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
41384                     a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
41385                     d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
41386                     c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
41387                     b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
41388                     a = safe_add(a, olda);
41389                     b = safe_add(b, oldb);
41390                     c = safe_add(c, oldc);
41391                     d = safe_add(d, oldd);
41392                   }
41393
41394                   return Array(a, b, c, d);
41395                 }
41396                 /**
41397                  * These functions implement the four basic operations the algorithm uses.
41398                  */
41399
41400
41401                 function md5_cmn(q, a, b, x, s, t) {
41402                   return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
41403                 }
41404
41405                 function md5_ff(a, b, c, d, x, s, t) {
41406                   return md5_cmn(b & c | ~b & d, a, b, x, s, t);
41407                 }
41408
41409                 function md5_gg(a, b, c, d, x, s, t) {
41410                   return md5_cmn(b & d | c & ~d, a, b, x, s, t);
41411                 }
41412
41413                 function md5_hh(a, b, c, d, x, s, t) {
41414                   return md5_cmn(b ^ c ^ d, a, b, x, s, t);
41415                 }
41416
41417                 function md5_ii(a, b, c, d, x, s, t) {
41418                   return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
41419                 }
41420               },
41421
41422               /**
41423                * @member Hashes
41424                * @class Hashes.SHA1
41425                * @param {Object} [config]
41426                * @constructor
41427                *
41428                * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
41429                * Version 2.2 Copyright Paul Johnston 2000 - 2009.
41430                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41431                * See http://pajhome.org.uk/crypt/md5 for details.
41432                */
41433               SHA1: function SHA1(options) {
41434                 /**
41435                  * Private config properties. You may need to tweak these to be compatible with
41436                  * the server-side, but the defaults work in most cases.
41437                  * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
41438                  */
41439                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41440                     // hexadecimal output case format. false - lowercase; true - uppercase
41441                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41442                     // base-64 pad character. Defaults to '=' for strict RFC compliance
41443                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
41444                 // public methods
41445
41446                 this.hex = function (s) {
41447                   return rstr2hex(rstr(s), hexcase);
41448                 };
41449
41450                 this.b64 = function (s) {
41451                   return rstr2b64(rstr(s), b64pad);
41452                 };
41453
41454                 this.any = function (s, e) {
41455                   return rstr2any(rstr(s), e);
41456                 };
41457
41458                 this.raw = function (s) {
41459                   return rstr(s);
41460                 };
41461
41462                 this.hex_hmac = function (k, d) {
41463                   return rstr2hex(rstr_hmac(k, d));
41464                 };
41465
41466                 this.b64_hmac = function (k, d) {
41467                   return rstr2b64(rstr_hmac(k, d), b64pad);
41468                 };
41469
41470                 this.any_hmac = function (k, d, e) {
41471                   return rstr2any(rstr_hmac(k, d), e);
41472                 };
41473                 /**
41474                  * Perform a simple self-test to see if the VM is working
41475                  * @return {String} Hexadecimal hash sample
41476                  * @public
41477                  */
41478
41479
41480                 this.vm_test = function () {
41481                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41482                 };
41483                 /**
41484                  * @description Enable/disable uppercase hexadecimal returned string
41485                  * @param {boolean}
41486                  * @return {Object} this
41487                  * @public
41488                  */
41489
41490
41491                 this.setUpperCase = function (a) {
41492                   if (typeof a === 'boolean') {
41493                     hexcase = a;
41494                   }
41495
41496                   return this;
41497                 };
41498                 /**
41499                  * @description Defines a base64 pad string
41500                  * @param {string} Pad
41501                  * @return {Object} this
41502                  * @public
41503                  */
41504
41505
41506                 this.setPad = function (a) {
41507                   b64pad = a || b64pad;
41508                   return this;
41509                 };
41510                 /**
41511                  * @description Defines a base64 pad string
41512                  * @param {boolean}
41513                  * @return {Object} this
41514                  * @public
41515                  */
41516
41517
41518                 this.setUTF8 = function (a) {
41519                   if (typeof a === 'boolean') {
41520                     utf8 = a;
41521                   }
41522
41523                   return this;
41524                 }; // private methods
41525
41526                 /**
41527                  * Calculate the SHA-512 of a raw string
41528                  */
41529
41530
41531                 function rstr(s) {
41532                   s = utf8 ? utf8Encode(s) : s;
41533                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41534                 }
41535                 /**
41536                  * Calculate the HMAC-SHA1 of a key and some data (raw strings)
41537                  */
41538
41539
41540                 function rstr_hmac(key, data) {
41541                   var bkey, ipad, opad, i, hash;
41542                   key = utf8 ? utf8Encode(key) : key;
41543                   data = utf8 ? utf8Encode(data) : data;
41544                   bkey = rstr2binb(key);
41545
41546                   if (bkey.length > 16) {
41547                     bkey = binb(bkey, key.length * 8);
41548                   }
41549
41550                   ipad = Array(16), opad = Array(16);
41551
41552                   for (i = 0; i < 16; i += 1) {
41553                     ipad[i] = bkey[i] ^ 0x36363636;
41554                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41555                   }
41556
41557                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41558                   return binb2rstr(binb(opad.concat(hash), 512 + 160));
41559                 }
41560                 /**
41561                  * Calculate the SHA-1 of an array of big-endian words, and a bit length
41562                  */
41563
41564
41565                 function binb(x, len) {
41566                   var i,
41567                       j,
41568                       t,
41569                       olda,
41570                       oldb,
41571                       oldc,
41572                       oldd,
41573                       olde,
41574                       w = Array(80),
41575                       a = 1732584193,
41576                       b = -271733879,
41577                       c = -1732584194,
41578                       d = 271733878,
41579                       e = -1009589776;
41580                   /* append padding */
41581
41582                   x[len >> 5] |= 0x80 << 24 - len % 32;
41583                   x[(len + 64 >> 9 << 4) + 15] = len;
41584
41585                   for (i = 0; i < x.length; i += 16) {
41586                     olda = a;
41587                     oldb = b;
41588                     oldc = c;
41589                     oldd = d;
41590                     olde = e;
41591
41592                     for (j = 0; j < 80; j += 1) {
41593                       if (j < 16) {
41594                         w[j] = x[i + j];
41595                       } else {
41596                         w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
41597                       }
41598
41599                       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)));
41600                       e = d;
41601                       d = c;
41602                       c = bit_rol(b, 30);
41603                       b = a;
41604                       a = t;
41605                     }
41606
41607                     a = safe_add(a, olda);
41608                     b = safe_add(b, oldb);
41609                     c = safe_add(c, oldc);
41610                     d = safe_add(d, oldd);
41611                     e = safe_add(e, olde);
41612                   }
41613
41614                   return Array(a, b, c, d, e);
41615                 }
41616                 /**
41617                  * Perform the appropriate triplet combination function for the current
41618                  * iteration
41619                  */
41620
41621
41622                 function sha1_ft(t, b, c, d) {
41623                   if (t < 20) {
41624                     return b & c | ~b & d;
41625                   }
41626
41627                   if (t < 40) {
41628                     return b ^ c ^ d;
41629                   }
41630
41631                   if (t < 60) {
41632                     return b & c | b & d | c & d;
41633                   }
41634
41635                   return b ^ c ^ d;
41636                 }
41637                 /**
41638                  * Determine the appropriate additive constant for the current iteration
41639                  */
41640
41641
41642                 function sha1_kt(t) {
41643                   return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
41644                 }
41645               },
41646
41647               /**
41648                * @class Hashes.SHA256
41649                * @param {config}
41650                *
41651                * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
41652                * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
41653                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41654                * See http://pajhome.org.uk/crypt/md5 for details.
41655                * Also http://anmar.eu.org/projects/jssha2/
41656                */
41657               SHA256: function SHA256(options) {
41658                 /**
41659                  * Private properties configuration variables. You may need to tweak these to be compatible with
41660                  * the server-side, but the defaults work in most cases.
41661                  * @see this.setUpperCase() method
41662                  * @see this.setPad() method
41663                  */
41664                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41665                     // hexadecimal output case format. false - lowercase; true - uppercase  */
41666                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41667
41668                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41669                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41670
41671                 /* enable/disable utf8 encoding */
41672                 sha256_K;
41673                 /* privileged (public) methods */
41674
41675                 this.hex = function (s) {
41676                   return rstr2hex(rstr(s, utf8));
41677                 };
41678
41679                 this.b64 = function (s) {
41680                   return rstr2b64(rstr(s, utf8), b64pad);
41681                 };
41682
41683                 this.any = function (s, e) {
41684                   return rstr2any(rstr(s, utf8), e);
41685                 };
41686
41687                 this.raw = function (s) {
41688                   return rstr(s, utf8);
41689                 };
41690
41691                 this.hex_hmac = function (k, d) {
41692                   return rstr2hex(rstr_hmac(k, d));
41693                 };
41694
41695                 this.b64_hmac = function (k, d) {
41696                   return rstr2b64(rstr_hmac(k, d), b64pad);
41697                 };
41698
41699                 this.any_hmac = function (k, d, e) {
41700                   return rstr2any(rstr_hmac(k, d), e);
41701                 };
41702                 /**
41703                  * Perform a simple self-test to see if the VM is working
41704                  * @return {String} Hexadecimal hash sample
41705                  * @public
41706                  */
41707
41708
41709                 this.vm_test = function () {
41710                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41711                 };
41712                 /**
41713                  * Enable/disable uppercase hexadecimal returned string
41714                  * @param {boolean}
41715                  * @return {Object} this
41716                  * @public
41717                  */
41718
41719
41720                 this.setUpperCase = function (a) {
41721                   if (typeof a === 'boolean') {
41722                     hexcase = a;
41723                   }
41724
41725                   return this;
41726                 };
41727                 /**
41728                  * @description Defines a base64 pad string
41729                  * @param {string} Pad
41730                  * @return {Object} this
41731                  * @public
41732                  */
41733
41734
41735                 this.setPad = function (a) {
41736                   b64pad = a || b64pad;
41737                   return this;
41738                 };
41739                 /**
41740                  * Defines a base64 pad string
41741                  * @param {boolean}
41742                  * @return {Object} this
41743                  * @public
41744                  */
41745
41746
41747                 this.setUTF8 = function (a) {
41748                   if (typeof a === 'boolean') {
41749                     utf8 = a;
41750                   }
41751
41752                   return this;
41753                 }; // private methods
41754
41755                 /**
41756                  * Calculate the SHA-512 of a raw string
41757                  */
41758
41759
41760                 function rstr(s, utf8) {
41761                   s = utf8 ? utf8Encode(s) : s;
41762                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41763                 }
41764                 /**
41765                  * Calculate the HMAC-sha256 of a key and some data (raw strings)
41766                  */
41767
41768
41769                 function rstr_hmac(key, data) {
41770                   key = utf8 ? utf8Encode(key) : key;
41771                   data = utf8 ? utf8Encode(data) : data;
41772                   var hash,
41773                       i = 0,
41774                       bkey = rstr2binb(key),
41775                       ipad = Array(16),
41776                       opad = Array(16);
41777
41778                   if (bkey.length > 16) {
41779                     bkey = binb(bkey, key.length * 8);
41780                   }
41781
41782                   for (; i < 16; i += 1) {
41783                     ipad[i] = bkey[i] ^ 0x36363636;
41784                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
41785                   }
41786
41787                   hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
41788                   return binb2rstr(binb(opad.concat(hash), 512 + 256));
41789                 }
41790                 /*
41791                  * Main sha256 function, with its support functions
41792                  */
41793
41794
41795                 function sha256_S(X, n) {
41796                   return X >>> n | X << 32 - n;
41797                 }
41798
41799                 function sha256_R(X, n) {
41800                   return X >>> n;
41801                 }
41802
41803                 function sha256_Ch(x, y, z) {
41804                   return x & y ^ ~x & z;
41805                 }
41806
41807                 function sha256_Maj(x, y, z) {
41808                   return x & y ^ x & z ^ y & z;
41809                 }
41810
41811                 function sha256_Sigma0256(x) {
41812                   return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
41813                 }
41814
41815                 function sha256_Sigma1256(x) {
41816                   return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
41817                 }
41818
41819                 function sha256_Gamma0256(x) {
41820                   return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
41821                 }
41822
41823                 function sha256_Gamma1256(x) {
41824                   return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
41825                 }
41826
41827                 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];
41828
41829                 function binb(m, l) {
41830                   var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
41831                   var W = new Array(64);
41832                   var a, b, c, d, e, f, g, h;
41833                   var i, j, T1, T2;
41834                   /* append padding */
41835
41836                   m[l >> 5] |= 0x80 << 24 - l % 32;
41837                   m[(l + 64 >> 9 << 4) + 15] = l;
41838
41839                   for (i = 0; i < m.length; i += 16) {
41840                     a = HASH[0];
41841                     b = HASH[1];
41842                     c = HASH[2];
41843                     d = HASH[3];
41844                     e = HASH[4];
41845                     f = HASH[5];
41846                     g = HASH[6];
41847                     h = HASH[7];
41848
41849                     for (j = 0; j < 64; j += 1) {
41850                       if (j < 16) {
41851                         W[j] = m[j + i];
41852                       } else {
41853                         W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
41854                       }
41855
41856                       T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
41857                       T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
41858                       h = g;
41859                       g = f;
41860                       f = e;
41861                       e = safe_add(d, T1);
41862                       d = c;
41863                       c = b;
41864                       b = a;
41865                       a = safe_add(T1, T2);
41866                     }
41867
41868                     HASH[0] = safe_add(a, HASH[0]);
41869                     HASH[1] = safe_add(b, HASH[1]);
41870                     HASH[2] = safe_add(c, HASH[2]);
41871                     HASH[3] = safe_add(d, HASH[3]);
41872                     HASH[4] = safe_add(e, HASH[4]);
41873                     HASH[5] = safe_add(f, HASH[5]);
41874                     HASH[6] = safe_add(g, HASH[6]);
41875                     HASH[7] = safe_add(h, HASH[7]);
41876                   }
41877
41878                   return HASH;
41879                 }
41880               },
41881
41882               /**
41883                * @class Hashes.SHA512
41884                * @param {config}
41885                *
41886                * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
41887                * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
41888                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41889                * See http://pajhome.org.uk/crypt/md5 for details.
41890                */
41891               SHA512: function SHA512(options) {
41892                 /**
41893                  * Private properties configuration variables. You may need to tweak these to be compatible with
41894                  * the server-side, but the defaults work in most cases.
41895                  * @see this.setUpperCase() method
41896                  * @see this.setPad() method
41897                  */
41898                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
41899
41900                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
41901                 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
41902
41903                 /* base-64 pad character. Default '=' for strict RFC compliance   */
41904                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
41905
41906                 /* enable/disable utf8 encoding */
41907                 sha512_k;
41908                 /* privileged (public) methods */
41909
41910                 this.hex = function (s) {
41911                   return rstr2hex(rstr(s));
41912                 };
41913
41914                 this.b64 = function (s) {
41915                   return rstr2b64(rstr(s), b64pad);
41916                 };
41917
41918                 this.any = function (s, e) {
41919                   return rstr2any(rstr(s), e);
41920                 };
41921
41922                 this.raw = function (s) {
41923                   return rstr(s);
41924                 };
41925
41926                 this.hex_hmac = function (k, d) {
41927                   return rstr2hex(rstr_hmac(k, d));
41928                 };
41929
41930                 this.b64_hmac = function (k, d) {
41931                   return rstr2b64(rstr_hmac(k, d), b64pad);
41932                 };
41933
41934                 this.any_hmac = function (k, d, e) {
41935                   return rstr2any(rstr_hmac(k, d), e);
41936                 };
41937                 /**
41938                  * Perform a simple self-test to see if the VM is working
41939                  * @return {String} Hexadecimal hash sample
41940                  * @public
41941                  */
41942
41943
41944                 this.vm_test = function () {
41945                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
41946                 };
41947                 /**
41948                  * @description Enable/disable uppercase hexadecimal returned string
41949                  * @param {boolean}
41950                  * @return {Object} this
41951                  * @public
41952                  */
41953
41954
41955                 this.setUpperCase = function (a) {
41956                   if (typeof a === 'boolean') {
41957                     hexcase = a;
41958                   }
41959
41960                   return this;
41961                 };
41962                 /**
41963                  * @description Defines a base64 pad string
41964                  * @param {string} Pad
41965                  * @return {Object} this
41966                  * @public
41967                  */
41968
41969
41970                 this.setPad = function (a) {
41971                   b64pad = a || b64pad;
41972                   return this;
41973                 };
41974                 /**
41975                  * @description Defines a base64 pad string
41976                  * @param {boolean}
41977                  * @return {Object} this
41978                  * @public
41979                  */
41980
41981
41982                 this.setUTF8 = function (a) {
41983                   if (typeof a === 'boolean') {
41984                     utf8 = a;
41985                   }
41986
41987                   return this;
41988                 };
41989                 /* private methods */
41990
41991                 /**
41992                  * Calculate the SHA-512 of a raw string
41993                  */
41994
41995
41996                 function rstr(s) {
41997                   s = utf8 ? utf8Encode(s) : s;
41998                   return binb2rstr(binb(rstr2binb(s), s.length * 8));
41999                 }
42000                 /*
42001                  * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
42002                  */
42003
42004
42005                 function rstr_hmac(key, data) {
42006                   key = utf8 ? utf8Encode(key) : key;
42007                   data = utf8 ? utf8Encode(data) : data;
42008                   var hash,
42009                       i = 0,
42010                       bkey = rstr2binb(key),
42011                       ipad = Array(32),
42012                       opad = Array(32);
42013
42014                   if (bkey.length > 32) {
42015                     bkey = binb(bkey, key.length * 8);
42016                   }
42017
42018                   for (; i < 32; i += 1) {
42019                     ipad[i] = bkey[i] ^ 0x36363636;
42020                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
42021                   }
42022
42023                   hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
42024                   return binb2rstr(binb(opad.concat(hash), 1024 + 512));
42025                 }
42026                 /**
42027                  * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
42028                  */
42029
42030
42031                 function binb(x, len) {
42032                   var j,
42033                       i,
42034                       l,
42035                       W = new Array(80),
42036                       hash = new Array(16),
42037                       //Initial hash values
42038                   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)],
42039                       T1 = new int64(0, 0),
42040                       T2 = new int64(0, 0),
42041                       a = new int64(0, 0),
42042                       b = new int64(0, 0),
42043                       c = new int64(0, 0),
42044                       d = new int64(0, 0),
42045                       e = new int64(0, 0),
42046                       f = new int64(0, 0),
42047                       g = new int64(0, 0),
42048                       h = new int64(0, 0),
42049                       //Temporary variables not specified by the document
42050                   s0 = new int64(0, 0),
42051                       s1 = new int64(0, 0),
42052                       Ch = new int64(0, 0),
42053                       Maj = new int64(0, 0),
42054                       r1 = new int64(0, 0),
42055                       r2 = new int64(0, 0),
42056                       r3 = new int64(0, 0);
42057
42058                   if (sha512_k === undefined) {
42059                     //SHA512 constants
42060                     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)];
42061                   }
42062
42063                   for (i = 0; i < 80; i += 1) {
42064                     W[i] = new int64(0, 0);
42065                   } // append padding to the source string. The format is described in the FIPS.
42066
42067
42068                   x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
42069                   x[(len + 128 >> 10 << 5) + 31] = len;
42070                   l = x.length;
42071
42072                   for (i = 0; i < l; i += 32) {
42073                     //32 dwords is the block size
42074                     int64copy(a, H[0]);
42075                     int64copy(b, H[1]);
42076                     int64copy(c, H[2]);
42077                     int64copy(d, H[3]);
42078                     int64copy(e, H[4]);
42079                     int64copy(f, H[5]);
42080                     int64copy(g, H[6]);
42081                     int64copy(h, H[7]);
42082
42083                     for (j = 0; j < 16; j += 1) {
42084                       W[j].h = x[i + 2 * j];
42085                       W[j].l = x[i + 2 * j + 1];
42086                     }
42087
42088                     for (j = 16; j < 80; j += 1) {
42089                       //sigma1
42090                       int64rrot(r1, W[j - 2], 19);
42091                       int64revrrot(r2, W[j - 2], 29);
42092                       int64shr(r3, W[j - 2], 6);
42093                       s1.l = r1.l ^ r2.l ^ r3.l;
42094                       s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
42095
42096                       int64rrot(r1, W[j - 15], 1);
42097                       int64rrot(r2, W[j - 15], 8);
42098                       int64shr(r3, W[j - 15], 7);
42099                       s0.l = r1.l ^ r2.l ^ r3.l;
42100                       s0.h = r1.h ^ r2.h ^ r3.h;
42101                       int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
42102                     }
42103
42104                     for (j = 0; j < 80; j += 1) {
42105                       //Ch
42106                       Ch.l = e.l & f.l ^ ~e.l & g.l;
42107                       Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
42108
42109                       int64rrot(r1, e, 14);
42110                       int64rrot(r2, e, 18);
42111                       int64revrrot(r3, e, 9);
42112                       s1.l = r1.l ^ r2.l ^ r3.l;
42113                       s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
42114
42115                       int64rrot(r1, a, 28);
42116                       int64revrrot(r2, a, 2);
42117                       int64revrrot(r3, a, 7);
42118                       s0.l = r1.l ^ r2.l ^ r3.l;
42119                       s0.h = r1.h ^ r2.h ^ r3.h; //Maj
42120
42121                       Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
42122                       Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
42123                       int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
42124                       int64add(T2, s0, Maj);
42125                       int64copy(h, g);
42126                       int64copy(g, f);
42127                       int64copy(f, e);
42128                       int64add(e, d, T1);
42129                       int64copy(d, c);
42130                       int64copy(c, b);
42131                       int64copy(b, a);
42132                       int64add(a, T1, T2);
42133                     }
42134
42135                     int64add(H[0], H[0], a);
42136                     int64add(H[1], H[1], b);
42137                     int64add(H[2], H[2], c);
42138                     int64add(H[3], H[3], d);
42139                     int64add(H[4], H[4], e);
42140                     int64add(H[5], H[5], f);
42141                     int64add(H[6], H[6], g);
42142                     int64add(H[7], H[7], h);
42143                   } //represent the hash as an array of 32-bit dwords
42144
42145
42146                   for (i = 0; i < 8; i += 1) {
42147                     hash[2 * i] = H[i].h;
42148                     hash[2 * i + 1] = H[i].l;
42149                   }
42150
42151                   return hash;
42152                 } //A constructor for 64-bit numbers
42153
42154
42155                 function int64(h, l) {
42156                   this.h = h;
42157                   this.l = l; //this.toString = int64toString;
42158                 } //Copies src into dst, assuming both are 64-bit numbers
42159
42160
42161                 function int64copy(dst, src) {
42162                   dst.h = src.h;
42163                   dst.l = src.l;
42164                 } //Right-rotates a 64-bit number by shift
42165                 //Won't handle cases of shift>=32
42166                 //The function revrrot() is for that
42167
42168
42169                 function int64rrot(dst, x, shift) {
42170                   dst.l = x.l >>> shift | x.h << 32 - shift;
42171                   dst.h = x.h >>> shift | x.l << 32 - shift;
42172                 } //Reverses the dwords of the source and then rotates right by shift.
42173                 //This is equivalent to rotation by 32+shift
42174
42175
42176                 function int64revrrot(dst, x, shift) {
42177                   dst.l = x.h >>> shift | x.l << 32 - shift;
42178                   dst.h = x.l >>> shift | x.h << 32 - shift;
42179                 } //Bitwise-shifts right a 64-bit number by shift
42180                 //Won't handle shift>=32, but it's never needed in SHA512
42181
42182
42183                 function int64shr(dst, x, shift) {
42184                   dst.l = x.l >>> shift | x.h << 32 - shift;
42185                   dst.h = x.h >>> shift;
42186                 } //Adds two 64-bit numbers
42187                 //Like the original implementation, does not rely on 32-bit operations
42188
42189
42190                 function int64add(dst, x, y) {
42191                   var w0 = (x.l & 0xffff) + (y.l & 0xffff);
42192                   var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
42193                   var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
42194                   var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
42195                   dst.l = w0 & 0xffff | w1 << 16;
42196                   dst.h = w2 & 0xffff | w3 << 16;
42197                 } //Same, except with 4 addends. Works faster than adding them one by one.
42198
42199
42200                 function int64add4(dst, a, b, c, d) {
42201                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
42202                   var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
42203                   var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
42204                   var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
42205                   dst.l = w0 & 0xffff | w1 << 16;
42206                   dst.h = w2 & 0xffff | w3 << 16;
42207                 } //Same, except with 5 addends
42208
42209
42210                 function int64add5(dst, a, b, c, d, e) {
42211                   var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
42212                       w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
42213                       w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
42214                       w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
42215                   dst.l = w0 & 0xffff | w1 << 16;
42216                   dst.h = w2 & 0xffff | w3 << 16;
42217                 }
42218               },
42219
42220               /**
42221                * @class Hashes.RMD160
42222                * @constructor
42223                * @param {Object} [config]
42224                *
42225                * A JavaScript implementation of the RIPEMD-160 Algorithm
42226                * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
42227                * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
42228                * See http://pajhome.org.uk/crypt/md5 for details.
42229                * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
42230                */
42231               RMD160: function RMD160(options) {
42232                 /**
42233                  * Private properties configuration variables. You may need to tweak these to be compatible with
42234                  * the server-side, but the defaults work in most cases.
42235                  * @see this.setUpperCase() method
42236                  * @see this.setPad() method
42237                  */
42238                 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
42239
42240                 /* hexadecimal output case format. false - lowercase; true - uppercase  */
42241                 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
42242
42243                 /* base-64 pad character. Default '=' for strict RFC compliance   */
42244                 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
42245
42246                 /* enable/disable utf8 encoding */
42247                 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],
42248                     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],
42249                     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],
42250                     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];
42251                 /* privileged (public) methods */
42252
42253                 this.hex = function (s) {
42254                   return rstr2hex(rstr(s));
42255                 };
42256
42257                 this.b64 = function (s) {
42258                   return rstr2b64(rstr(s), b64pad);
42259                 };
42260
42261                 this.any = function (s, e) {
42262                   return rstr2any(rstr(s), e);
42263                 };
42264
42265                 this.raw = function (s) {
42266                   return rstr(s);
42267                 };
42268
42269                 this.hex_hmac = function (k, d) {
42270                   return rstr2hex(rstr_hmac(k, d));
42271                 };
42272
42273                 this.b64_hmac = function (k, d) {
42274                   return rstr2b64(rstr_hmac(k, d), b64pad);
42275                 };
42276
42277                 this.any_hmac = function (k, d, e) {
42278                   return rstr2any(rstr_hmac(k, d), e);
42279                 };
42280                 /**
42281                  * Perform a simple self-test to see if the VM is working
42282                  * @return {String} Hexadecimal hash sample
42283                  * @public
42284                  */
42285
42286
42287                 this.vm_test = function () {
42288                   return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
42289                 };
42290                 /**
42291                  * @description Enable/disable uppercase hexadecimal returned string
42292                  * @param {boolean}
42293                  * @return {Object} this
42294                  * @public
42295                  */
42296
42297
42298                 this.setUpperCase = function (a) {
42299                   if (typeof a === 'boolean') {
42300                     hexcase = a;
42301                   }
42302
42303                   return this;
42304                 };
42305                 /**
42306                  * @description Defines a base64 pad string
42307                  * @param {string} Pad
42308                  * @return {Object} this
42309                  * @public
42310                  */
42311
42312
42313                 this.setPad = function (a) {
42314                   if (typeof a !== 'undefined') {
42315                     b64pad = a;
42316                   }
42317
42318                   return this;
42319                 };
42320                 /**
42321                  * @description Defines a base64 pad string
42322                  * @param {boolean}
42323                  * @return {Object} this
42324                  * @public
42325                  */
42326
42327
42328                 this.setUTF8 = function (a) {
42329                   if (typeof a === 'boolean') {
42330                     utf8 = a;
42331                   }
42332
42333                   return this;
42334                 };
42335                 /* private methods */
42336
42337                 /**
42338                  * Calculate the rmd160 of a raw string
42339                  */
42340
42341
42342                 function rstr(s) {
42343                   s = utf8 ? utf8Encode(s) : s;
42344                   return binl2rstr(binl(rstr2binl(s), s.length * 8));
42345                 }
42346                 /**
42347                  * Calculate the HMAC-rmd160 of a key and some data (raw strings)
42348                  */
42349
42350
42351                 function rstr_hmac(key, data) {
42352                   key = utf8 ? utf8Encode(key) : key;
42353                   data = utf8 ? utf8Encode(data) : data;
42354                   var i,
42355                       hash,
42356                       bkey = rstr2binl(key),
42357                       ipad = Array(16),
42358                       opad = Array(16);
42359
42360                   if (bkey.length > 16) {
42361                     bkey = binl(bkey, key.length * 8);
42362                   }
42363
42364                   for (i = 0; i < 16; i += 1) {
42365                     ipad[i] = bkey[i] ^ 0x36363636;
42366                     opad[i] = bkey[i] ^ 0x5C5C5C5C;
42367                   }
42368
42369                   hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
42370                   return binl2rstr(binl(opad.concat(hash), 512 + 160));
42371                 }
42372                 /**
42373                  * Convert an array of little-endian words to a string
42374                  */
42375
42376
42377                 function binl2rstr(input) {
42378                   var i,
42379                       output = '',
42380                       l = input.length * 32;
42381
42382                   for (i = 0; i < l; i += 8) {
42383                     output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
42384                   }
42385
42386                   return output;
42387                 }
42388                 /**
42389                  * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
42390                  */
42391
42392
42393                 function binl(x, len) {
42394                   var T,
42395                       j,
42396                       i,
42397                       l,
42398                       h0 = 0x67452301,
42399                       h1 = 0xefcdab89,
42400                       h2 = 0x98badcfe,
42401                       h3 = 0x10325476,
42402                       h4 = 0xc3d2e1f0,
42403                       A1,
42404                       B1,
42405                       C1,
42406                       D1,
42407                       E1,
42408                       A2,
42409                       B2,
42410                       C2,
42411                       D2,
42412                       E2;
42413                   /* append padding */
42414
42415                   x[len >> 5] |= 0x80 << len % 32;
42416                   x[(len + 64 >>> 9 << 4) + 14] = len;
42417                   l = x.length;
42418
42419                   for (i = 0; i < l; i += 16) {
42420                     A1 = A2 = h0;
42421                     B1 = B2 = h1;
42422                     C1 = C2 = h2;
42423                     D1 = D2 = h3;
42424                     E1 = E2 = h4;
42425
42426                     for (j = 0; j <= 79; j += 1) {
42427                       T = safe_add(A1, rmd160_f(j, B1, C1, D1));
42428                       T = safe_add(T, x[i + rmd160_r1[j]]);
42429                       T = safe_add(T, rmd160_K1(j));
42430                       T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
42431                       A1 = E1;
42432                       E1 = D1;
42433                       D1 = bit_rol(C1, 10);
42434                       C1 = B1;
42435                       B1 = T;
42436                       T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
42437                       T = safe_add(T, x[i + rmd160_r2[j]]);
42438                       T = safe_add(T, rmd160_K2(j));
42439                       T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
42440                       A2 = E2;
42441                       E2 = D2;
42442                       D2 = bit_rol(C2, 10);
42443                       C2 = B2;
42444                       B2 = T;
42445                     }
42446
42447                     T = safe_add(h1, safe_add(C1, D2));
42448                     h1 = safe_add(h2, safe_add(D1, E2));
42449                     h2 = safe_add(h3, safe_add(E1, A2));
42450                     h3 = safe_add(h4, safe_add(A1, B2));
42451                     h4 = safe_add(h0, safe_add(B1, C2));
42452                     h0 = T;
42453                   }
42454
42455                   return [h0, h1, h2, h3, h4];
42456                 } // specific algorithm methods
42457
42458
42459                 function rmd160_f(j, x, y, z) {
42460                   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';
42461                 }
42462
42463                 function rmd160_K1(j) {
42464                   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';
42465                 }
42466
42467                 function rmd160_K2(j) {
42468                   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';
42469                 }
42470               }
42471             }; // exposes Hashes
42472
42473             (function (window, undefined$1) {
42474               var freeExports = false;
42475
42476               {
42477                 freeExports = exports;
42478
42479                 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
42480                   window = commonjsGlobal;
42481                 }
42482               }
42483
42484               if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
42485                 // define as an anonymous module, so, through path mapping, it can be aliased
42486                 undefined$1(function () {
42487                   return Hashes;
42488                 });
42489               } else if (freeExports) {
42490                 // in Node.js or RingoJS v0.8.0+
42491                 if ( module && module.exports === freeExports) {
42492                   module.exports = Hashes;
42493                 } // in Narwhal or RingoJS v0.7.0-
42494                 else {
42495                     freeExports.Hashes = Hashes;
42496                   }
42497               } else {
42498                 // in a browser or Rhino
42499                 window.Hashes = Hashes;
42500               }
42501             })(this);
42502           })(); // IIFE
42503
42504         });
42505
42506         var immutable = extend$2;
42507         var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
42508
42509         function extend$2() {
42510           var target = {};
42511
42512           for (var i = 0; i < arguments.length; i++) {
42513             var source = arguments[i];
42514
42515             for (var key in source) {
42516               if (hasOwnProperty$2.call(source, key)) {
42517                 target[key] = source[key];
42518               }
42519             }
42520           }
42521
42522           return target;
42523         }
42524
42525         var sha1 = new hashes.SHA1();
42526         var ohauth = {};
42527
42528         ohauth.qsString = function (obj) {
42529           return Object.keys(obj).sort().map(function (key) {
42530             return ohauth.percentEncode(key) + '=' + ohauth.percentEncode(obj[key]);
42531           }).join('&');
42532         };
42533
42534         ohauth.stringQs = function (str) {
42535           return str.split('&').filter(function (pair) {
42536             return pair !== '';
42537           }).reduce(function (obj, pair) {
42538             var parts = pair.split('=');
42539             obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
42540             return obj;
42541           }, {});
42542         };
42543
42544         ohauth.rawxhr = function (method, url, data, headers, callback) {
42545           var xhr = new XMLHttpRequest(),
42546               twoHundred = /^20\d$/;
42547
42548           xhr.onreadystatechange = function () {
42549             if (4 === xhr.readyState && 0 !== xhr.status) {
42550               if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
42551             }
42552           };
42553
42554           xhr.onerror = function (e) {
42555             return callback(e, null);
42556           };
42557
42558           xhr.open(method, url, true);
42559
42560           for (var h in headers) {
42561             xhr.setRequestHeader(h, headers[h]);
42562           }
42563
42564           xhr.send(data);
42565           return xhr;
42566         };
42567
42568         ohauth.xhr = function (method, url, auth, data, options, callback) {
42569           var headers = options && options.header || {
42570             'Content-Type': 'application/x-www-form-urlencoded'
42571           };
42572           headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
42573           return ohauth.rawxhr(method, url, data, headers, callback);
42574         };
42575
42576         ohauth.nonce = function () {
42577           for (var o = ''; o.length < 6;) {
42578             o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
42579           }
42580
42581           return o;
42582         };
42583
42584         ohauth.authHeader = function (obj) {
42585           return Object.keys(obj).sort().map(function (key) {
42586             return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
42587           }).join(', ');
42588         };
42589
42590         ohauth.timestamp = function () {
42591           return ~~(+new Date() / 1000);
42592         };
42593
42594         ohauth.percentEncode = function (s) {
42595           return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
42596         };
42597
42598         ohauth.baseString = function (method, url, params) {
42599           if (params.oauth_signature) delete params.oauth_signature;
42600           return [method, ohauth.percentEncode(url), ohauth.percentEncode(ohauth.qsString(params))].join('&');
42601         };
42602
42603         ohauth.signature = function (oauth_secret, token_secret, baseString) {
42604           return sha1.b64_hmac(ohauth.percentEncode(oauth_secret) + '&' + ohauth.percentEncode(token_secret), baseString);
42605         };
42606         /**
42607          * Takes an options object for configuration (consumer_key,
42608          * consumer_secret, version, signature_method, token, token_secret)
42609          * and returns a function that generates the Authorization header
42610          * for given data.
42611          *
42612          * The returned function takes these parameters:
42613          * - method: GET/POST/...
42614          * - uri: full URI with protocol, port, path and query string
42615          * - extra_params: any extra parameters (that are passed in the POST data),
42616          *   can be an object or a from-urlencoded string.
42617          *
42618          * Returned function returns full OAuth header with "OAuth" string in it.
42619          */
42620
42621
42622         ohauth.headerGenerator = function (options) {
42623           options = options || {};
42624           var consumer_key = options.consumer_key || '',
42625               consumer_secret = options.consumer_secret || '',
42626               signature_method = options.signature_method || 'HMAC-SHA1',
42627               version = options.version || '1.0',
42628               token = options.token || '',
42629               token_secret = options.token_secret || '';
42630           return function (method, uri, extra_params) {
42631             method = method.toUpperCase();
42632
42633             if (typeof extra_params === 'string' && extra_params.length > 0) {
42634               extra_params = ohauth.stringQs(extra_params);
42635             }
42636
42637             var uri_parts = uri.split('?', 2),
42638                 base_uri = uri_parts[0];
42639             var query_params = uri_parts.length === 2 ? ohauth.stringQs(uri_parts[1]) : {};
42640             var oauth_params = {
42641               oauth_consumer_key: consumer_key,
42642               oauth_signature_method: signature_method,
42643               oauth_version: version,
42644               oauth_timestamp: ohauth.timestamp(),
42645               oauth_nonce: ohauth.nonce()
42646             };
42647             if (token) oauth_params.oauth_token = token;
42648             var all_params = immutable({}, oauth_params, query_params, extra_params),
42649                 base_str = ohauth.baseString(method, base_uri, all_params);
42650             oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
42651             return 'OAuth ' + ohauth.authHeader(oauth_params);
42652           };
42653         };
42654
42655         var ohauth_1 = ohauth;
42656
42657         var resolveUrl$1 = createCommonjsModule(function (module, exports) {
42658           // Copyright 2014 Simon Lydell
42659           // X11 (“MIT”) Licensed. (See LICENSE.)
42660           void function (root, factory) {
42661             {
42662               module.exports = factory();
42663             }
42664           }(commonjsGlobal, function () {
42665             function resolveUrl()
42666             /* ...urls */
42667             {
42668               var numUrls = arguments.length;
42669
42670               if (numUrls === 0) {
42671                 throw new Error("resolveUrl requires at least one argument; got none.");
42672               }
42673
42674               var base = document.createElement("base");
42675               base.href = arguments[0];
42676
42677               if (numUrls === 1) {
42678                 return base.href;
42679               }
42680
42681               var head = document.getElementsByTagName("head")[0];
42682               head.insertBefore(base, head.firstChild);
42683               var a = document.createElement("a");
42684               var resolved;
42685
42686               for (var index = 1; index < numUrls; index++) {
42687                 a.href = arguments[index];
42688                 resolved = a.href;
42689                 base.href = resolved;
42690               }
42691
42692               head.removeChild(base);
42693               return resolved;
42694             }
42695
42696             return resolveUrl;
42697           });
42698         });
42699
42700         var assign = make_assign();
42701         var create$1 = make_create();
42702         var trim$3 = make_trim();
42703         var Global = typeof window !== 'undefined' ? window : commonjsGlobal;
42704         var util = {
42705           assign: assign,
42706           create: create$1,
42707           trim: trim$3,
42708           bind: bind$1,
42709           slice: slice$2,
42710           each: each,
42711           map: map$1,
42712           pluck: pluck,
42713           isList: isList,
42714           isFunction: isFunction,
42715           isObject: isObject$2,
42716           Global: Global
42717         };
42718
42719         function make_assign() {
42720           if (Object.assign) {
42721             return Object.assign;
42722           } else {
42723             return function shimAssign(obj, props1, props2, etc) {
42724               for (var i = 1; i < arguments.length; i++) {
42725                 each(Object(arguments[i]), function (val, key) {
42726                   obj[key] = val;
42727                 });
42728               }
42729
42730               return obj;
42731             };
42732           }
42733         }
42734
42735         function make_create() {
42736           if (Object.create) {
42737             return function create(obj, assignProps1, assignProps2, etc) {
42738               var assignArgsList = slice$2(arguments, 1);
42739               return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
42740             };
42741           } else {
42742             var F = function F() {}; // eslint-disable-line no-inner-declarations
42743
42744
42745             return function create(obj, assignProps1, assignProps2, etc) {
42746               var assignArgsList = slice$2(arguments, 1);
42747               F.prototype = obj;
42748               return assign.apply(this, [new F()].concat(assignArgsList));
42749             };
42750           }
42751         }
42752
42753         function make_trim() {
42754           if (String.prototype.trim) {
42755             return function trim(str) {
42756               return String.prototype.trim.call(str);
42757             };
42758           } else {
42759             return function trim(str) {
42760               return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
42761             };
42762           }
42763         }
42764
42765         function bind$1(obj, fn) {
42766           return function () {
42767             return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
42768           };
42769         }
42770
42771         function slice$2(arr, index) {
42772           return Array.prototype.slice.call(arr, index || 0);
42773         }
42774
42775         function each(obj, fn) {
42776           pluck(obj, function (val, key) {
42777             fn(val, key);
42778             return false;
42779           });
42780         }
42781
42782         function map$1(obj, fn) {
42783           var res = isList(obj) ? [] : {};
42784           pluck(obj, function (v, k) {
42785             res[k] = fn(v, k);
42786             return false;
42787           });
42788           return res;
42789         }
42790
42791         function pluck(obj, fn) {
42792           if (isList(obj)) {
42793             for (var i = 0; i < obj.length; i++) {
42794               if (fn(obj[i], i)) {
42795                 return obj[i];
42796               }
42797             }
42798           } else {
42799             for (var key in obj) {
42800               if (obj.hasOwnProperty(key)) {
42801                 if (fn(obj[key], key)) {
42802                   return obj[key];
42803                 }
42804               }
42805             }
42806           }
42807         }
42808
42809         function isList(val) {
42810           return val != null && typeof val != 'function' && typeof val.length == 'number';
42811         }
42812
42813         function isFunction(val) {
42814           return val && {}.toString.call(val) === '[object Function]';
42815         }
42816
42817         function isObject$2(val) {
42818           return val && {}.toString.call(val) === '[object Object]';
42819         }
42820
42821         var slice$3 = util.slice;
42822         var pluck$1 = util.pluck;
42823         var each$1 = util.each;
42824         var bind$2 = util.bind;
42825         var create$2 = util.create;
42826         var isList$1 = util.isList;
42827         var isFunction$1 = util.isFunction;
42828         var isObject$3 = util.isObject;
42829         var storeEngine = {
42830           createStore: _createStore
42831         };
42832         var storeAPI = {
42833           version: '2.0.12',
42834           enabled: false,
42835           // get returns the value of the given key. If that value
42836           // is undefined, it returns optionalDefaultValue instead.
42837           get: function get(key, optionalDefaultValue) {
42838             var data = this.storage.read(this._namespacePrefix + key);
42839             return this._deserialize(data, optionalDefaultValue);
42840           },
42841           // set will store the given value at key and returns value.
42842           // Calling set with value === undefined is equivalent to calling remove.
42843           set: function set(key, value) {
42844             if (value === undefined) {
42845               return this.remove(key);
42846             }
42847
42848             this.storage.write(this._namespacePrefix + key, this._serialize(value));
42849             return value;
42850           },
42851           // remove deletes the key and value stored at the given key.
42852           remove: function remove(key) {
42853             this.storage.remove(this._namespacePrefix + key);
42854           },
42855           // each will call the given callback once for each key-value pair
42856           // in this store.
42857           each: function each(callback) {
42858             var self = this;
42859             this.storage.each(function (val, namespacedKey) {
42860               callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
42861             });
42862           },
42863           // clearAll will remove all the stored key-value pairs in this store.
42864           clearAll: function clearAll() {
42865             this.storage.clearAll();
42866           },
42867           // additional functionality that can't live in plugins
42868           // ---------------------------------------------------
42869           // hasNamespace returns true if this store instance has the given namespace.
42870           hasNamespace: function hasNamespace(namespace) {
42871             return this._namespacePrefix == '__storejs_' + namespace + '_';
42872           },
42873           // createStore creates a store.js instance with the first
42874           // functioning storage in the list of storage candidates,
42875           // and applies the the given mixins to the instance.
42876           createStore: function createStore() {
42877             return _createStore.apply(this, arguments);
42878           },
42879           addPlugin: function addPlugin(plugin) {
42880             this._addPlugin(plugin);
42881           },
42882           namespace: function namespace(_namespace) {
42883             return _createStore(this.storage, this.plugins, _namespace);
42884           }
42885         };
42886
42887         function _warn() {
42888           var _console = typeof console == 'undefined' ? null : console;
42889
42890           if (!_console) {
42891             return;
42892           }
42893
42894           var fn = _console.warn ? _console.warn : _console.log;
42895           fn.apply(_console, arguments);
42896         }
42897
42898         function _createStore(storages, plugins, namespace) {
42899           if (!namespace) {
42900             namespace = '';
42901           }
42902
42903           if (storages && !isList$1(storages)) {
42904             storages = [storages];
42905           }
42906
42907           if (plugins && !isList$1(plugins)) {
42908             plugins = [plugins];
42909           }
42910
42911           var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
42912           var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
42913           var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
42914
42915           if (!legalNamespaces.test(namespace)) {
42916             throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
42917           }
42918
42919           var _privateStoreProps = {
42920             _namespacePrefix: namespacePrefix,
42921             _namespaceRegexp: namespaceRegexp,
42922             _testStorage: function _testStorage(storage) {
42923               try {
42924                 var testStr = '__storejs__test__';
42925                 storage.write(testStr, testStr);
42926                 var ok = storage.read(testStr) === testStr;
42927                 storage.remove(testStr);
42928                 return ok;
42929               } catch (e) {
42930                 return false;
42931               }
42932             },
42933             _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
42934               var oldFn = this[propName];
42935
42936               this[propName] = function pluginFn() {
42937                 var args = slice$3(arguments, 0);
42938                 var self = this; // super_fn calls the old function which was overwritten by
42939                 // this mixin.
42940
42941                 function super_fn() {
42942                   if (!oldFn) {
42943                     return;
42944                   }
42945
42946                   each$1(arguments, function (arg, i) {
42947                     args[i] = arg;
42948                   });
42949                   return oldFn.apply(self, args);
42950                 } // Give mixing function access to super_fn by prefixing all mixin function
42951                 // arguments with super_fn.
42952
42953
42954                 var newFnArgs = [super_fn].concat(args);
42955                 return pluginFnProp.apply(self, newFnArgs);
42956               };
42957             },
42958             _serialize: function _serialize(obj) {
42959               return JSON.stringify(obj);
42960             },
42961             _deserialize: function _deserialize(strVal, defaultVal) {
42962               if (!strVal) {
42963                 return defaultVal;
42964               } // It is possible that a raw string value has been previously stored
42965               // in a storage without using store.js, meaning it will be a raw
42966               // string value instead of a JSON serialized string. By defaulting
42967               // to the raw string value in case of a JSON parse error, we allow
42968               // for past stored values to be forwards-compatible with store.js
42969
42970
42971               var val = '';
42972
42973               try {
42974                 val = JSON.parse(strVal);
42975               } catch (e) {
42976                 val = strVal;
42977               }
42978
42979               return val !== undefined ? val : defaultVal;
42980             },
42981             _addStorage: function _addStorage(storage) {
42982               if (this.enabled) {
42983                 return;
42984               }
42985
42986               if (this._testStorage(storage)) {
42987                 this.storage = storage;
42988                 this.enabled = true;
42989               }
42990             },
42991             _addPlugin: function _addPlugin(plugin) {
42992               var self = this; // If the plugin is an array, then add all plugins in the array.
42993               // This allows for a plugin to depend on other plugins.
42994
42995               if (isList$1(plugin)) {
42996                 each$1(plugin, function (plugin) {
42997                   self._addPlugin(plugin);
42998                 });
42999                 return;
43000               } // Keep track of all plugins we've seen so far, so that we
43001               // don't add any of them twice.
43002
43003
43004               var seenPlugin = pluck$1(this.plugins, function (seenPlugin) {
43005                 return plugin === seenPlugin;
43006               });
43007
43008               if (seenPlugin) {
43009                 return;
43010               }
43011
43012               this.plugins.push(plugin); // Check that the plugin is properly formed
43013
43014               if (!isFunction$1(plugin)) {
43015                 throw new Error('Plugins must be function values that return objects');
43016               }
43017
43018               var pluginProperties = plugin.call(this);
43019
43020               if (!isObject$3(pluginProperties)) {
43021                 throw new Error('Plugins must return an object of function properties');
43022               } // Add the plugin function properties to this store instance.
43023
43024
43025               each$1(pluginProperties, function (pluginFnProp, propName) {
43026                 if (!isFunction$1(pluginFnProp)) {
43027                   throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
43028                 }
43029
43030                 self._assignPluginFnProp(pluginFnProp, propName);
43031               });
43032             },
43033             // Put deprecated properties in the private API, so as to not expose it to accidential
43034             // discovery through inspection of the store object.
43035             // Deprecated: addStorage
43036             addStorage: function addStorage(storage) {
43037               _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
43038
43039               this._addStorage(storage);
43040             }
43041           };
43042           var store = create$2(_privateStoreProps, storeAPI, {
43043             plugins: []
43044           });
43045           store.raw = {};
43046           each$1(store, function (prop, propName) {
43047             if (isFunction$1(prop)) {
43048               store.raw[propName] = bind$2(store, prop);
43049             }
43050           });
43051           each$1(storages, function (storage) {
43052             store._addStorage(storage);
43053           });
43054           each$1(plugins, function (plugin) {
43055             store._addPlugin(plugin);
43056           });
43057           return store;
43058         }
43059
43060         var Global$1 = util.Global;
43061         var localStorage_1 = {
43062           name: 'localStorage',
43063           read: read,
43064           write: write,
43065           each: each$2,
43066           remove: remove$2,
43067           clearAll: clearAll
43068         };
43069
43070         function localStorage$1() {
43071           return Global$1.localStorage;
43072         }
43073
43074         function read(key) {
43075           return localStorage$1().getItem(key);
43076         }
43077
43078         function write(key, data) {
43079           return localStorage$1().setItem(key, data);
43080         }
43081
43082         function each$2(fn) {
43083           for (var i = localStorage$1().length - 1; i >= 0; i--) {
43084             var key = localStorage$1().key(i);
43085             fn(read(key), key);
43086           }
43087         }
43088
43089         function remove$2(key) {
43090           return localStorage$1().removeItem(key);
43091         }
43092
43093         function clearAll() {
43094           return localStorage$1().clear();
43095         }
43096
43097         // versions 6 and 7, where no localStorage, etc
43098         // is available.
43099
43100         var Global$2 = util.Global;
43101         var oldFFGlobalStorage = {
43102           name: 'oldFF-globalStorage',
43103           read: read$1,
43104           write: write$1,
43105           each: each$3,
43106           remove: remove$3,
43107           clearAll: clearAll$1
43108         };
43109         var globalStorage = Global$2.globalStorage;
43110
43111         function read$1(key) {
43112           return globalStorage[key];
43113         }
43114
43115         function write$1(key, data) {
43116           globalStorage[key] = data;
43117         }
43118
43119         function each$3(fn) {
43120           for (var i = globalStorage.length - 1; i >= 0; i--) {
43121             var key = globalStorage.key(i);
43122             fn(globalStorage[key], key);
43123           }
43124         }
43125
43126         function remove$3(key) {
43127           return globalStorage.removeItem(key);
43128         }
43129
43130         function clearAll$1() {
43131           each$3(function (key, _) {
43132             delete globalStorage[key];
43133           });
43134         }
43135
43136         // versions 6 and 7, where no localStorage, sessionStorage, etc
43137         // is available.
43138
43139         var Global$3 = util.Global;
43140         var oldIEUserDataStorage = {
43141           name: 'oldIE-userDataStorage',
43142           write: write$2,
43143           read: read$2,
43144           each: each$4,
43145           remove: remove$4,
43146           clearAll: clearAll$2
43147         };
43148         var storageName = 'storejs';
43149         var doc = Global$3.document;
43150
43151         var _withStorageEl = _makeIEStorageElFunction();
43152
43153         var disable = (Global$3.navigator ? Global$3.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
43154
43155         function write$2(unfixedKey, data) {
43156           if (disable) {
43157             return;
43158           }
43159
43160           var fixedKey = fixKey(unfixedKey);
43161
43162           _withStorageEl(function (storageEl) {
43163             storageEl.setAttribute(fixedKey, data);
43164             storageEl.save(storageName);
43165           });
43166         }
43167
43168         function read$2(unfixedKey) {
43169           if (disable) {
43170             return;
43171           }
43172
43173           var fixedKey = fixKey(unfixedKey);
43174           var res = null;
43175
43176           _withStorageEl(function (storageEl) {
43177             res = storageEl.getAttribute(fixedKey);
43178           });
43179
43180           return res;
43181         }
43182
43183         function each$4(callback) {
43184           _withStorageEl(function (storageEl) {
43185             var attributes = storageEl.XMLDocument.documentElement.attributes;
43186
43187             for (var i = attributes.length - 1; i >= 0; i--) {
43188               var attr = attributes[i];
43189               callback(storageEl.getAttribute(attr.name), attr.name);
43190             }
43191           });
43192         }
43193
43194         function remove$4(unfixedKey) {
43195           var fixedKey = fixKey(unfixedKey);
43196
43197           _withStorageEl(function (storageEl) {
43198             storageEl.removeAttribute(fixedKey);
43199             storageEl.save(storageName);
43200           });
43201         }
43202
43203         function clearAll$2() {
43204           _withStorageEl(function (storageEl) {
43205             var attributes = storageEl.XMLDocument.documentElement.attributes;
43206             storageEl.load(storageName);
43207
43208             for (var i = attributes.length - 1; i >= 0; i--) {
43209               storageEl.removeAttribute(attributes[i].name);
43210             }
43211
43212             storageEl.save(storageName);
43213           });
43214         } // Helpers
43215         //////////
43216         // In IE7, keys cannot start with a digit or contain certain chars.
43217         // See https://github.com/marcuswestin/store.js/issues/40
43218         // See https://github.com/marcuswestin/store.js/issues/83
43219
43220
43221         var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
43222
43223         function fixKey(key) {
43224           return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
43225         }
43226
43227         function _makeIEStorageElFunction() {
43228           if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
43229             return null;
43230           }
43231
43232           var scriptTag = 'script',
43233               storageOwner,
43234               storageContainer,
43235               storageEl; // Since #userData storage applies only to specific paths, we need to
43236           // somehow link our data to a specific path.  We choose /favicon.ico
43237           // as a pretty safe option, since all browsers already make a request to
43238           // this URL anyway and being a 404 will not hurt us here.  We wrap an
43239           // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
43240           // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
43241           // since the iframe access rules appear to allow direct access and
43242           // manipulation of the document element, even for a 404 page.  This
43243           // document can be used instead of the current document (which would
43244           // have been limited to the current path) to perform #userData storage.
43245
43246           try {
43247             /* global ActiveXObject */
43248             storageContainer = new ActiveXObject('htmlfile');
43249             storageContainer.open();
43250             storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
43251             storageContainer.close();
43252             storageOwner = storageContainer.w.frames[0].document;
43253             storageEl = storageOwner.createElement('div');
43254           } catch (e) {
43255             // somehow ActiveXObject instantiation failed (perhaps some special
43256             // security settings or otherwse), fall back to per-path storage
43257             storageEl = doc.createElement('div');
43258             storageOwner = doc.body;
43259           }
43260
43261           return function (storeFunction) {
43262             var args = [].slice.call(arguments, 0);
43263             args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
43264             // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
43265
43266             storageOwner.appendChild(storageEl);
43267             storageEl.addBehavior('#default#userData');
43268             storageEl.load(storageName);
43269             storeFunction.apply(this, args);
43270             storageOwner.removeChild(storageEl);
43271             return;
43272           };
43273         }
43274
43275         // doesn't work but cookies do. This implementation is adopted from
43276         // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
43277
43278         var Global$4 = util.Global;
43279         var trim$4 = util.trim;
43280         var cookieStorage = {
43281           name: 'cookieStorage',
43282           read: read$3,
43283           write: write$3,
43284           each: each$5,
43285           remove: remove$5,
43286           clearAll: clearAll$3
43287         };
43288         var doc$1 = Global$4.document;
43289
43290         function read$3(key) {
43291           if (!key || !_has(key)) {
43292             return null;
43293           }
43294
43295           var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
43296           return unescape(doc$1.cookie.replace(new RegExp(regexpStr), "$1"));
43297         }
43298
43299         function each$5(callback) {
43300           var cookies = doc$1.cookie.split(/; ?/g);
43301
43302           for (var i = cookies.length - 1; i >= 0; i--) {
43303             if (!trim$4(cookies[i])) {
43304               continue;
43305             }
43306
43307             var kvp = cookies[i].split('=');
43308             var key = unescape(kvp[0]);
43309             var val = unescape(kvp[1]);
43310             callback(val, key);
43311           }
43312         }
43313
43314         function write$3(key, data) {
43315           if (!key) {
43316             return;
43317           }
43318
43319           doc$1.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
43320         }
43321
43322         function remove$5(key) {
43323           if (!key || !_has(key)) {
43324             return;
43325           }
43326
43327           doc$1.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
43328         }
43329
43330         function clearAll$3() {
43331           each$5(function (_, key) {
43332             remove$5(key);
43333           });
43334         }
43335
43336         function _has(key) {
43337           return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc$1.cookie);
43338         }
43339
43340         var Global$5 = util.Global;
43341         var sessionStorage_1 = {
43342           name: 'sessionStorage',
43343           read: read$4,
43344           write: write$4,
43345           each: each$6,
43346           remove: remove$6,
43347           clearAll: clearAll$4
43348         };
43349
43350         function sessionStorage() {
43351           return Global$5.sessionStorage;
43352         }
43353
43354         function read$4(key) {
43355           return sessionStorage().getItem(key);
43356         }
43357
43358         function write$4(key, data) {
43359           return sessionStorage().setItem(key, data);
43360         }
43361
43362         function each$6(fn) {
43363           for (var i = sessionStorage().length - 1; i >= 0; i--) {
43364             var key = sessionStorage().key(i);
43365             fn(read$4(key), key);
43366           }
43367         }
43368
43369         function remove$6(key) {
43370           return sessionStorage().removeItem(key);
43371         }
43372
43373         function clearAll$4() {
43374           return sessionStorage().clear();
43375         }
43376
43377         // memoryStorage is a useful last fallback to ensure that the store
43378         // is functions (meaning store.get(), store.set(), etc will all function).
43379         // However, stored values will not persist when the browser navigates to
43380         // a new page or reloads the current page.
43381         var memoryStorage_1 = {
43382           name: 'memoryStorage',
43383           read: read$5,
43384           write: write$5,
43385           each: each$7,
43386           remove: remove$7,
43387           clearAll: clearAll$5
43388         };
43389         var memoryStorage = {};
43390
43391         function read$5(key) {
43392           return memoryStorage[key];
43393         }
43394
43395         function write$5(key, data) {
43396           memoryStorage[key] = data;
43397         }
43398
43399         function each$7(callback) {
43400           for (var key in memoryStorage) {
43401             if (memoryStorage.hasOwnProperty(key)) {
43402               callback(memoryStorage[key], key);
43403             }
43404           }
43405         }
43406
43407         function remove$7(key) {
43408           delete memoryStorage[key];
43409         }
43410
43411         function clearAll$5(key) {
43412           memoryStorage = {};
43413         }
43414
43415         var all = [// Listed in order of usage preference
43416         localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
43417
43418         /* eslint-disable */
43419         //  json2.js
43420         //  2016-10-28
43421         //  Public Domain.
43422         //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
43423         //  See http://www.JSON.org/js.html
43424         //  This code should be minified before deployment.
43425         //  See http://javascript.crockford.com/jsmin.html
43426         //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
43427         //  NOT CONTROL.
43428         //  This file creates a global JSON object containing two methods: stringify
43429         //  and parse. This file provides the ES5 JSON capability to ES3 systems.
43430         //  If a project might run on IE8 or earlier, then this file should be included.
43431         //  This file does nothing on ES5 systems.
43432         //      JSON.stringify(value, replacer, space)
43433         //          value       any JavaScript value, usually an object or array.
43434         //          replacer    an optional parameter that determines how object
43435         //                      values are stringified for objects. It can be a
43436         //                      function or an array of strings.
43437         //          space       an optional parameter that specifies the indentation
43438         //                      of nested structures. If it is omitted, the text will
43439         //                      be packed without extra whitespace. If it is a number,
43440         //                      it will specify the number of spaces to indent at each
43441         //                      level. If it is a string (such as "\t" or "&nbsp;"),
43442         //                      it contains the characters used to indent at each level.
43443         //          This method produces a JSON text from a JavaScript value.
43444         //          When an object value is found, if the object contains a toJSON
43445         //          method, its toJSON method will be called and the result will be
43446         //          stringified. A toJSON method does not serialize: it returns the
43447         //          value represented by the name/value pair that should be serialized,
43448         //          or undefined if nothing should be serialized. The toJSON method
43449         //          will be passed the key associated with the value, and this will be
43450         //          bound to the value.
43451         //          For example, this would serialize Dates as ISO strings.
43452         //              Date.prototype.toJSON = function (key) {
43453         //                  function f(n) {
43454         //                      // Format integers to have at least two digits.
43455         //                      return (n < 10)
43456         //                          ? "0" + n
43457         //                          : n;
43458         //                  }
43459         //                  return this.getUTCFullYear()   + "-" +
43460         //                       f(this.getUTCMonth() + 1) + "-" +
43461         //                       f(this.getUTCDate())      + "T" +
43462         //                       f(this.getUTCHours())     + ":" +
43463         //                       f(this.getUTCMinutes())   + ":" +
43464         //                       f(this.getUTCSeconds())   + "Z";
43465         //              };
43466         //          You can provide an optional replacer method. It will be passed the
43467         //          key and value of each member, with this bound to the containing
43468         //          object. The value that is returned from your method will be
43469         //          serialized. If your method returns undefined, then the member will
43470         //          be excluded from the serialization.
43471         //          If the replacer parameter is an array of strings, then it will be
43472         //          used to select the members to be serialized. It filters the results
43473         //          such that only members with keys listed in the replacer array are
43474         //          stringified.
43475         //          Values that do not have JSON representations, such as undefined or
43476         //          functions, will not be serialized. Such values in objects will be
43477         //          dropped; in arrays they will be replaced with null. You can use
43478         //          a replacer function to replace those with JSON values.
43479         //          JSON.stringify(undefined) returns undefined.
43480         //          The optional space parameter produces a stringification of the
43481         //          value that is filled with line breaks and indentation to make it
43482         //          easier to read.
43483         //          If the space parameter is a non-empty string, then that string will
43484         //          be used for indentation. If the space parameter is a number, then
43485         //          the indentation will be that many spaces.
43486         //          Example:
43487         //          text = JSON.stringify(["e", {pluribus: "unum"}]);
43488         //          // text is '["e",{"pluribus":"unum"}]'
43489         //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
43490         //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
43491         //          text = JSON.stringify([new Date()], function (key, value) {
43492         //              return this[key] instanceof Date
43493         //                  ? "Date(" + this[key] + ")"
43494         //                  : value;
43495         //          });
43496         //          // text is '["Date(---current time---)"]'
43497         //      JSON.parse(text, reviver)
43498         //          This method parses a JSON text to produce an object or array.
43499         //          It can throw a SyntaxError exception.
43500         //          The optional reviver parameter is a function that can filter and
43501         //          transform the results. It receives each of the keys and values,
43502         //          and its return value is used instead of the original value.
43503         //          If it returns what it received, then the structure is not modified.
43504         //          If it returns undefined then the member is deleted.
43505         //          Example:
43506         //          // Parse the text. Values that look like ISO date strings will
43507         //          // be converted to Date objects.
43508         //          myData = JSON.parse(text, function (key, value) {
43509         //              var a;
43510         //              if (typeof value === "string") {
43511         //                  a =
43512         //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
43513         //                  if (a) {
43514         //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
43515         //                          +a[5], +a[6]));
43516         //                  }
43517         //              }
43518         //              return value;
43519         //          });
43520         //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
43521         //              var d;
43522         //              if (typeof value === "string" &&
43523         //                      value.slice(0, 5) === "Date(" &&
43524         //                      value.slice(-1) === ")") {
43525         //                  d = new Date(value.slice(5, -1));
43526         //                  if (d) {
43527         //                      return d;
43528         //                  }
43529         //              }
43530         //              return value;
43531         //          });
43532         //  This is a reference implementation. You are free to copy, modify, or
43533         //  redistribute.
43534
43535         /*jslint
43536             eval, for, this
43537         */
43538
43539         /*property
43540             JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
43541             getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
43542             lastIndex, length, parse, prototype, push, replace, slice, stringify,
43543             test, toJSON, toString, valueOf
43544         */
43545         // Create a JSON object only if one does not already exist. We create the
43546         // methods in a closure to avoid creating global variables.
43547         if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
43548           JSON = {};
43549         }
43550
43551         (function () {
43552
43553           var rx_one = /^[\],:{}\s]*$/;
43554           var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
43555           var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
43556           var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
43557           var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43558           var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
43559
43560           function f(n) {
43561             // Format integers to have at least two digits.
43562             return n < 10 ? "0" + n : n;
43563           }
43564
43565           function this_value() {
43566             return this.valueOf();
43567           }
43568
43569           if (typeof Date.prototype.toJSON !== "function") {
43570             Date.prototype.toJSON = function () {
43571               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;
43572             };
43573
43574             Boolean.prototype.toJSON = this_value;
43575             Number.prototype.toJSON = this_value;
43576             String.prototype.toJSON = this_value;
43577           }
43578
43579           var gap;
43580           var indent;
43581           var meta;
43582           var rep;
43583
43584           function quote(string) {
43585             // If the string contains no control characters, no quote characters, and no
43586             // backslash characters, then we can safely slap some quotes around it.
43587             // Otherwise we must also replace the offending characters with safe escape
43588             // sequences.
43589             rx_escapable.lastIndex = 0;
43590             return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
43591               var c = meta[a];
43592               return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43593             }) + "\"" : "\"" + string + "\"";
43594           }
43595
43596           function str(key, holder) {
43597             // Produce a string from holder[key].
43598             var i; // The loop counter.
43599
43600             var k; // The member key.
43601
43602             var v; // The member value.
43603
43604             var length;
43605             var mind = gap;
43606             var partial;
43607             var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
43608
43609             if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
43610               value = value.toJSON(key);
43611             } // If we were called with a replacer function, then call the replacer to
43612             // obtain a replacement value.
43613
43614
43615             if (typeof rep === "function") {
43616               value = rep.call(holder, key, value);
43617             } // What happens next depends on the value's type.
43618
43619
43620             switch (_typeof(value)) {
43621               case "string":
43622                 return quote(value);
43623
43624               case "number":
43625                 // JSON numbers must be finite. Encode non-finite numbers as null.
43626                 return isFinite(value) ? String(value) : "null";
43627
43628               case "boolean":
43629               case "null":
43630                 // If the value is a boolean or null, convert it to a string. Note:
43631                 // typeof null does not produce "null". The case is included here in
43632                 // the remote chance that this gets fixed someday.
43633                 return String(value);
43634               // If the type is "object", we might be dealing with an object or an array or
43635               // null.
43636
43637               case "object":
43638                 // Due to a specification blunder in ECMAScript, typeof null is "object",
43639                 // so watch out for that case.
43640                 if (!value) {
43641                   return "null";
43642                 } // Make an array to hold the partial results of stringifying this object value.
43643
43644
43645                 gap += indent;
43646                 partial = []; // Is the value an array?
43647
43648                 if (Object.prototype.toString.apply(value) === "[object Array]") {
43649                   // The value is an array. Stringify every element. Use null as a placeholder
43650                   // for non-JSON values.
43651                   length = value.length;
43652
43653                   for (i = 0; i < length; i += 1) {
43654                     partial[i] = str(i, value) || "null";
43655                   } // Join all of the elements together, separated with commas, and wrap them in
43656                   // brackets.
43657
43658
43659                   v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
43660                   gap = mind;
43661                   return v;
43662                 } // If the replacer is an array, use it to select the members to be stringified.
43663
43664
43665                 if (rep && _typeof(rep) === "object") {
43666                   length = rep.length;
43667
43668                   for (i = 0; i < length; i += 1) {
43669                     if (typeof rep[i] === "string") {
43670                       k = rep[i];
43671                       v = str(k, value);
43672
43673                       if (v) {
43674                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43675                       }
43676                     }
43677                   }
43678                 } else {
43679                   // Otherwise, iterate through all of the keys in the object.
43680                   for (k in value) {
43681                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43682                       v = str(k, value);
43683
43684                       if (v) {
43685                         partial.push(quote(k) + (gap ? ": " : ":") + v);
43686                       }
43687                     }
43688                   }
43689                 } // Join all of the member texts together, separated with commas,
43690                 // and wrap them in braces.
43691
43692
43693                 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
43694                 gap = mind;
43695                 return v;
43696             }
43697           } // If the JSON object does not yet have a stringify method, give it one.
43698
43699
43700           if (typeof JSON.stringify !== "function") {
43701             meta = {
43702               // table of character substitutions
43703               "\b": "\\b",
43704               "\t": "\\t",
43705               "\n": "\\n",
43706               "\f": "\\f",
43707               "\r": "\\r",
43708               "\"": "\\\"",
43709               "\\": "\\\\"
43710             };
43711
43712             JSON.stringify = function (value, replacer, space) {
43713               // The stringify method takes a value and an optional replacer, and an optional
43714               // space parameter, and returns a JSON text. The replacer can be a function
43715               // that can replace values, or an array of strings that will select the keys.
43716               // A default replacer method can be provided. Use of the space parameter can
43717               // produce text that is more easily readable.
43718               var i;
43719               gap = "";
43720               indent = ""; // If the space parameter is a number, make an indent string containing that
43721               // many spaces.
43722
43723               if (typeof space === "number") {
43724                 for (i = 0; i < space; i += 1) {
43725                   indent += " ";
43726                 } // If the space parameter is a string, it will be used as the indent string.
43727
43728               } else if (typeof space === "string") {
43729                 indent = space;
43730               } // If there is a replacer, it must be a function or an array.
43731               // Otherwise, throw an error.
43732
43733
43734               rep = replacer;
43735
43736               if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
43737                 throw new Error("JSON.stringify");
43738               } // Make a fake root object containing our value under the key of "".
43739               // Return the result of stringifying the value.
43740
43741
43742               return str("", {
43743                 "": value
43744               });
43745             };
43746           } // If the JSON object does not yet have a parse method, give it one.
43747
43748
43749           if (typeof JSON.parse !== "function") {
43750             JSON.parse = function (text, reviver) {
43751               // The parse method takes a text and an optional reviver function, and returns
43752               // a JavaScript value if the text is a valid JSON text.
43753               var j;
43754
43755               function walk(holder, key) {
43756                 // The walk method is used to recursively walk the resulting structure so
43757                 // that modifications can be made.
43758                 var k;
43759                 var v;
43760                 var value = holder[key];
43761
43762                 if (value && _typeof(value) === "object") {
43763                   for (k in value) {
43764                     if (Object.prototype.hasOwnProperty.call(value, k)) {
43765                       v = walk(value, k);
43766
43767                       if (v !== undefined) {
43768                         value[k] = v;
43769                       } else {
43770                         delete value[k];
43771                       }
43772                     }
43773                   }
43774                 }
43775
43776                 return reviver.call(holder, key, value);
43777               } // Parsing happens in four stages. In the first stage, we replace certain
43778               // Unicode characters with escape sequences. JavaScript handles many characters
43779               // incorrectly, either silently deleting them, or treating them as line endings.
43780
43781
43782               text = String(text);
43783               rx_dangerous.lastIndex = 0;
43784
43785               if (rx_dangerous.test(text)) {
43786                 text = text.replace(rx_dangerous, function (a) {
43787                   return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
43788                 });
43789               } // In the second stage, we run the text against regular expressions that look
43790               // for non-JSON patterns. We are especially concerned with "()" and "new"
43791               // because they can cause invocation, and "=" because it can cause mutation.
43792               // But just to be safe, we want to reject all unexpected forms.
43793               // We split the second stage into 4 regexp operations in order to work around
43794               // crippling inefficiencies in IE's and Safari's regexp engines. First we
43795               // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
43796               // replace all simple value tokens with "]" characters. Third, we delete all
43797               // open brackets that follow a colon or comma or that begin the text. Finally,
43798               // we look to see that the remaining characters are only whitespace or "]" or
43799               // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
43800
43801
43802               if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
43803                 // In the third stage we use the eval function to compile the text into a
43804                 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
43805                 // in JavaScript: it can begin a block or an object literal. We wrap the text
43806                 // in parens to eliminate the ambiguity.
43807                 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
43808                 // each name/value pair to a reviver function for possible transformation.
43809
43810                 return typeof reviver === "function" ? walk({
43811                   "": j
43812                 }, "") : j;
43813               } // If the text is not JSON parseable, then a SyntaxError is thrown.
43814
43815
43816               throw new SyntaxError("JSON.parse");
43817             };
43818           }
43819         })();
43820
43821         var json2 = json2Plugin;
43822
43823         function json2Plugin() {
43824           return {};
43825         }
43826
43827         var plugins = [json2];
43828         var store_legacy = storeEngine.createStore(all, plugins);
43829
43830         //
43831         // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
43832         // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
43833         // does not support custom headers, which this uses everywhere.
43834
43835
43836         var osmAuth = function osmAuth(o) {
43837           var oauth = {}; // authenticated users will also have a request token secret, but it's
43838           // not used in transactions with the server
43839
43840           oauth.authenticated = function () {
43841             return !!(token('oauth_token') && token('oauth_token_secret'));
43842           };
43843
43844           oauth.logout = function () {
43845             token('oauth_token', '');
43846             token('oauth_token_secret', '');
43847             token('oauth_request_token_secret', '');
43848             return oauth;
43849           }; // TODO: detect lack of click event
43850
43851
43852           oauth.authenticate = function (callback) {
43853             if (oauth.authenticated()) return callback();
43854             oauth.logout(); // ## Getting a request token
43855
43856             var params = timenonce(getAuth(o)),
43857                 url = o.url + '/oauth/request_token';
43858             params.oauth_signature = ohauth_1.signature(o.oauth_secret, '', ohauth_1.baseString('POST', url, params));
43859
43860             if (!o.singlepage) {
43861               // Create a 600x550 popup window in the center of the screen
43862               var w = 600,
43863                   h = 550,
43864                   settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
43865                 return x.join('=');
43866               }).join(','),
43867                   popup = window.open('about:blank', 'oauth_window', settings);
43868               oauth.popupWindow = popup;
43869
43870               if (!popup) {
43871                 var error = new Error('Popup was blocked');
43872                 error.status = 'popup-blocked';
43873                 throw error;
43874               }
43875             } // Request a request token. When this is complete, the popup
43876             // window is redirected to OSM's authorization page.
43877
43878
43879             ohauth_1.xhr('POST', url, params, null, {}, reqTokenDone);
43880             o.loading();
43881
43882             function reqTokenDone(err, xhr) {
43883               o.done();
43884               if (err) return callback(err);
43885               var resp = ohauth_1.stringQs(xhr.response);
43886               token('oauth_request_token_secret', resp.oauth_token_secret);
43887               var authorize_url = o.url + '/oauth/authorize?' + ohauth_1.qsString({
43888                 oauth_token: resp.oauth_token,
43889                 oauth_callback: resolveUrl$1(o.landing)
43890               });
43891
43892               if (o.singlepage) {
43893                 location.href = authorize_url;
43894               } else {
43895                 popup.location = authorize_url;
43896               }
43897             } // Called by a function in a landing page, in the popup window. The
43898             // window closes itself.
43899
43900
43901             window.authComplete = function (token) {
43902               var oauth_token = ohauth_1.stringQs(token.split('?')[1]);
43903               get_access_token(oauth_token.oauth_token);
43904               delete window.authComplete;
43905             }; // ## Getting an request token
43906             //
43907             // At this point we have an `oauth_token`, brought in from a function
43908             // call on a landing page popup.
43909
43910
43911             function get_access_token(oauth_token) {
43912               var url = o.url + '/oauth/access_token',
43913                   params = timenonce(getAuth(o)),
43914                   request_token_secret = token('oauth_request_token_secret');
43915               params.oauth_token = oauth_token;
43916               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43917               //
43918               // The final token required for authentication. At this point
43919               // we have a `request token secret`
43920
43921               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43922               o.loading();
43923             }
43924
43925             function accessTokenDone(err, xhr) {
43926               o.done();
43927               if (err) return callback(err);
43928               var access_token = ohauth_1.stringQs(xhr.response);
43929               token('oauth_token', access_token.oauth_token);
43930               token('oauth_token_secret', access_token.oauth_token_secret);
43931               callback(null, oauth);
43932             }
43933           };
43934
43935           oauth.bringPopupWindowToFront = function () {
43936             var brougtPopupToFront = false;
43937
43938             try {
43939               // This may cause a cross-origin error:
43940               // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
43941               if (oauth.popupWindow && !oauth.popupWindow.closed) {
43942                 oauth.popupWindow.focus();
43943                 brougtPopupToFront = true;
43944               }
43945             } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
43946             }
43947
43948             return brougtPopupToFront;
43949           };
43950
43951           oauth.bootstrapToken = function (oauth_token, callback) {
43952             // ## Getting an request token
43953             // At this point we have an `oauth_token`, brought in from a function
43954             // call on a landing page popup.
43955             function get_access_token(oauth_token) {
43956               var url = o.url + '/oauth/access_token',
43957                   params = timenonce(getAuth(o)),
43958                   request_token_secret = token('oauth_request_token_secret');
43959               params.oauth_token = oauth_token;
43960               params.oauth_signature = ohauth_1.signature(o.oauth_secret, request_token_secret, ohauth_1.baseString('POST', url, params)); // ## Getting an access token
43961               // The final token required for authentication. At this point
43962               // we have a `request token secret`
43963
43964               ohauth_1.xhr('POST', url, params, null, {}, accessTokenDone);
43965               o.loading();
43966             }
43967
43968             function accessTokenDone(err, xhr) {
43969               o.done();
43970               if (err) return callback(err);
43971               var access_token = ohauth_1.stringQs(xhr.response);
43972               token('oauth_token', access_token.oauth_token);
43973               token('oauth_token_secret', access_token.oauth_token_secret);
43974               callback(null, oauth);
43975             }
43976
43977             get_access_token(oauth_token);
43978           }; // # xhr
43979           //
43980           // A single XMLHttpRequest wrapper that does authenticated calls if the
43981           // user has logged in.
43982
43983
43984           oauth.xhr = function (options, callback) {
43985             if (!oauth.authenticated()) {
43986               if (o.auto) {
43987                 return oauth.authenticate(run);
43988               } else {
43989                 callback('not authenticated', null);
43990                 return;
43991               }
43992             } else {
43993               return run();
43994             }
43995
43996             function run() {
43997               var params = timenonce(getAuth(o)),
43998                   oauth_token_secret = token('oauth_token_secret'),
43999                   url = options.prefix !== false ? o.url + options.path : options.path,
44000                   url_parts = url.replace(/#.*$/, '').split('?', 2),
44001                   base_url = url_parts[0],
44002                   query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
44003
44004               if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
44005                 params = immutable(params, ohauth_1.stringQs(options.content));
44006               }
44007
44008               params.oauth_token = token('oauth_token');
44009               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))));
44010               return ohauth_1.xhr(options.method, url, params, options.content, options.options, done);
44011             }
44012
44013             function done(err, xhr) {
44014               if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
44015             }
44016           }; // pre-authorize this object, if we can just get a token and token_secret
44017           // from the start
44018
44019
44020           oauth.preauth = function (c) {
44021             if (!c) return;
44022             if (c.oauth_token) token('oauth_token', c.oauth_token);
44023             if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
44024             return oauth;
44025           };
44026
44027           oauth.options = function (_) {
44028             if (!arguments.length) return o;
44029             o = _;
44030             o.url = o.url || 'https://www.openstreetmap.org';
44031             o.landing = o.landing || 'land.html';
44032             o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
44033             // by default, no-ops
44034
44035             o.loading = o.loading || function () {};
44036
44037             o.done = o.done || function () {};
44038
44039             return oauth.preauth(o);
44040           }; // 'stamp' an authentication object from `getAuth()`
44041           // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
44042           // and timestamp
44043
44044
44045           function timenonce(o) {
44046             o.oauth_timestamp = ohauth_1.timestamp();
44047             o.oauth_nonce = ohauth_1.nonce();
44048             return o;
44049           } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
44050           // can be used with multiple APIs and the keys in `localStorage`
44051           // will not clash
44052
44053
44054           var token;
44055
44056           if (store_legacy.enabled) {
44057             token = function token(x, y) {
44058               if (arguments.length === 1) return store_legacy.get(o.url + x);else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
44059             };
44060           } else {
44061             var storage = {};
44062
44063             token = function token(x, y) {
44064               if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
44065             };
44066           } // Get an authentication object. If you just add and remove properties
44067           // from a single object, you'll need to use `delete` to make sure that
44068           // it doesn't contain undesired properties for authentication
44069
44070
44071           function getAuth(o) {
44072             return {
44073               oauth_consumer_key: o.oauth_consumer_key,
44074               oauth_signature_method: 'HMAC-SHA1'
44075             };
44076           } // potentially pre-authorize
44077
44078
44079           oauth.options(o);
44080           return oauth;
44081         };
44082
44083         var JXON = new function () {
44084           var sValueProp = 'keyValue',
44085               sAttributesProp = 'keyAttributes',
44086               sAttrPref = '@',
44087
44088           /* you can customize these values */
44089           aCache = [],
44090               rIsNull = /^\s*$/,
44091               rIsBool = /^(?:true|false)$/i;
44092
44093           function parseText(sValue) {
44094             if (rIsNull.test(sValue)) {
44095               return null;
44096             }
44097
44098             if (rIsBool.test(sValue)) {
44099               return sValue.toLowerCase() === 'true';
44100             }
44101
44102             if (isFinite(sValue)) {
44103               return parseFloat(sValue);
44104             }
44105
44106             if (isFinite(Date.parse(sValue))) {
44107               return new Date(sValue);
44108             }
44109
44110             return sValue;
44111           }
44112
44113           function EmptyTree() {}
44114
44115           EmptyTree.prototype.toString = function () {
44116             return 'null';
44117           };
44118
44119           EmptyTree.prototype.valueOf = function () {
44120             return null;
44121           };
44122
44123           function objectify(vValue) {
44124             return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
44125           }
44126
44127           function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
44128             var nLevelStart = aCache.length,
44129                 bChildren = oParentNode.hasChildNodes(),
44130                 bAttributes = oParentNode.hasAttributes(),
44131                 bHighVerb = Boolean(nVerb & 2);
44132             var sProp,
44133                 vContent,
44134                 nLength = 0,
44135                 sCollectedTxt = '',
44136                 vResult = bHighVerb ? {} :
44137             /* put here the default value for empty nodes: */
44138             true;
44139
44140             if (bChildren) {
44141               for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
44142                 oNode = oParentNode.childNodes.item(nItem);
44143
44144                 if (oNode.nodeType === 4) {
44145                   sCollectedTxt += oNode.nodeValue;
44146                 }
44147                 /* nodeType is 'CDATASection' (4) */
44148                 else if (oNode.nodeType === 3) {
44149                     sCollectedTxt += oNode.nodeValue.trim();
44150                   }
44151                   /* nodeType is 'Text' (3) */
44152                   else if (oNode.nodeType === 1 && !oNode.prefix) {
44153                       aCache.push(oNode);
44154                     }
44155                 /* nodeType is 'Element' (1) */
44156
44157               }
44158             }
44159
44160             var nLevelEnd = aCache.length,
44161                 vBuiltVal = parseText(sCollectedTxt);
44162
44163             if (!bHighVerb && (bChildren || bAttributes)) {
44164               vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
44165             }
44166
44167             for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
44168               sProp = aCache[nElId].nodeName.toLowerCase();
44169               vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
44170
44171               if (vResult.hasOwnProperty(sProp)) {
44172                 if (vResult[sProp].constructor !== Array) {
44173                   vResult[sProp] = [vResult[sProp]];
44174                 }
44175
44176                 vResult[sProp].push(vContent);
44177               } else {
44178                 vResult[sProp] = vContent;
44179                 nLength++;
44180               }
44181             }
44182
44183             if (bAttributes) {
44184               var nAttrLen = oParentNode.attributes.length,
44185                   sAPrefix = bNesteAttr ? '' : sAttrPref,
44186                   oAttrParent = bNesteAttr ? {} : vResult;
44187
44188               for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
44189                 oAttrib = oParentNode.attributes.item(nAttrib);
44190                 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
44191               }
44192
44193               if (bNesteAttr) {
44194                 if (bFreeze) {
44195                   Object.freeze(oAttrParent);
44196                 }
44197
44198                 vResult[sAttributesProp] = oAttrParent;
44199                 nLength -= nAttrLen - 1;
44200               }
44201             }
44202
44203             if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
44204               vResult[sValueProp] = vBuiltVal;
44205             } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
44206               vResult = vBuiltVal;
44207             }
44208
44209             if (bFreeze && (bHighVerb || nLength > 0)) {
44210               Object.freeze(vResult);
44211             }
44212
44213             aCache.length = nLevelStart;
44214             return vResult;
44215           }
44216
44217           function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
44218             var vValue, oChild;
44219
44220             if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
44221               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
44222               /* verbosity level is 0 */
44223             } else if (oParentObj.constructor === Date) {
44224               oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
44225             }
44226
44227             for (var sName in oParentObj) {
44228               vValue = oParentObj[sName];
44229
44230               if (isFinite(sName) || vValue instanceof Function) {
44231                 continue;
44232               }
44233               /* verbosity level is 0 */
44234
44235
44236               if (sName === sValueProp) {
44237                 if (vValue !== null && vValue !== true) {
44238                   oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
44239                 }
44240               } else if (sName === sAttributesProp) {
44241                 /* verbosity level is 3 */
44242                 for (var sAttrib in vValue) {
44243                   oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
44244                 }
44245               } else if (sName.charAt(0) === sAttrPref) {
44246                 oParentEl.setAttribute(sName.slice(1), vValue);
44247               } else if (vValue.constructor === Array) {
44248                 for (var nItem = 0; nItem < vValue.length; nItem++) {
44249                   oChild = oXMLDoc.createElement(sName);
44250                   loadObjTree(oXMLDoc, oChild, vValue[nItem]);
44251                   oParentEl.appendChild(oChild);
44252                 }
44253               } else {
44254                 oChild = oXMLDoc.createElement(sName);
44255
44256                 if (vValue instanceof Object) {
44257                   loadObjTree(oXMLDoc, oChild, vValue);
44258                 } else if (vValue !== null && vValue !== true) {
44259                   oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
44260                 }
44261
44262                 oParentEl.appendChild(oChild);
44263               }
44264             }
44265           }
44266
44267           this.build = function (oXMLParent, nVerbosity
44268           /* optional */
44269           , bFreeze
44270           /* optional */
44271           , bNesteAttributes
44272           /* optional */
44273           ) {
44274             var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
44275             /* put here the default verbosity level: */
44276             1;
44277
44278             return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
44279           };
44280
44281           this.unbuild = function (oObjTree) {
44282             var oNewDoc = document.implementation.createDocument('', '', null);
44283             loadObjTree(oNewDoc, oNewDoc, oObjTree);
44284             return oNewDoc;
44285           };
44286
44287           this.stringify = function (oObjTree) {
44288             return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
44289           };
44290         }(); // var myObject = JXON.build(doc);
44291         // we got our javascript object! try: alert(JSON.stringify(myObject));
44292         // var newDoc = JXON.unbuild(myObject);
44293         // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
44294
44295         var tiler$5 = utilTiler();
44296         var dispatch$6 = dispatch('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
44297         var urlroot = 'https://www.openstreetmap.org';
44298         var oauth = osmAuth({
44299           url: urlroot,
44300           oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
44301           oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
44302           loading: authLoading,
44303           done: authDone
44304         }); // hardcode default block of Google Maps
44305
44306         var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
44307         var _tileCache = {
44308           toLoad: {},
44309           loaded: {},
44310           inflight: {},
44311           seen: {},
44312           rtree: new RBush()
44313         };
44314         var _noteCache = {
44315           toLoad: {},
44316           loaded: {},
44317           inflight: {},
44318           inflightPost: {},
44319           note: {},
44320           closed: {},
44321           rtree: new RBush()
44322         };
44323         var _userCache = {
44324           toLoad: {},
44325           user: {}
44326         };
44327
44328         var _cachedApiStatus;
44329
44330         var _changeset = {};
44331
44332         var _deferred = new Set();
44333
44334         var _connectionID = 1;
44335         var _tileZoom$3 = 16;
44336         var _noteZoom = 12;
44337
44338         var _rateLimitError;
44339
44340         var _userChangesets;
44341
44342         var _userDetails;
44343
44344         var _off; // set a default but also load this from the API status
44345
44346
44347         var _maxWayNodes = 2000;
44348
44349         function authLoading() {
44350           dispatch$6.call('authLoading');
44351         }
44352
44353         function authDone() {
44354           dispatch$6.call('authDone');
44355         }
44356
44357         function abortRequest$5(controllerOrXHR) {
44358           if (controllerOrXHR) {
44359             controllerOrXHR.abort();
44360           }
44361         }
44362
44363         function hasInflightRequests(cache) {
44364           return Object.keys(cache.inflight).length;
44365         }
44366
44367         function abortUnwantedRequests$3(cache, visibleTiles) {
44368           Object.keys(cache.inflight).forEach(function (k) {
44369             if (cache.toLoad[k]) return;
44370             if (visibleTiles.find(function (tile) {
44371               return k === tile.id;
44372             })) return;
44373             abortRequest$5(cache.inflight[k]);
44374             delete cache.inflight[k];
44375           });
44376         }
44377
44378         function getLoc(attrs) {
44379           var lon = attrs.lon && attrs.lon.value;
44380           var lat = attrs.lat && attrs.lat.value;
44381           return [parseFloat(lon), parseFloat(lat)];
44382         }
44383
44384         function getNodes(obj) {
44385           var elems = obj.getElementsByTagName('nd');
44386           var nodes = new Array(elems.length);
44387
44388           for (var i = 0, l = elems.length; i < l; i++) {
44389             nodes[i] = 'n' + elems[i].attributes.ref.value;
44390           }
44391
44392           return nodes;
44393         }
44394
44395         function getNodesJSON(obj) {
44396           var elems = obj.nodes;
44397           var nodes = new Array(elems.length);
44398
44399           for (var i = 0, l = elems.length; i < l; i++) {
44400             nodes[i] = 'n' + elems[i];
44401           }
44402
44403           return nodes;
44404         }
44405
44406         function getTags(obj) {
44407           var elems = obj.getElementsByTagName('tag');
44408           var tags = {};
44409
44410           for (var i = 0, l = elems.length; i < l; i++) {
44411             var attrs = elems[i].attributes;
44412             tags[attrs.k.value] = attrs.v.value;
44413           }
44414
44415           return tags;
44416         }
44417
44418         function getMembers(obj) {
44419           var elems = obj.getElementsByTagName('member');
44420           var members = new Array(elems.length);
44421
44422           for (var i = 0, l = elems.length; i < l; i++) {
44423             var attrs = elems[i].attributes;
44424             members[i] = {
44425               id: attrs.type.value[0] + attrs.ref.value,
44426               type: attrs.type.value,
44427               role: attrs.role.value
44428             };
44429           }
44430
44431           return members;
44432         }
44433
44434         function getMembersJSON(obj) {
44435           var elems = obj.members;
44436           var members = new Array(elems.length);
44437
44438           for (var i = 0, l = elems.length; i < l; i++) {
44439             var attrs = elems[i];
44440             members[i] = {
44441               id: attrs.type[0] + attrs.ref,
44442               type: attrs.type,
44443               role: attrs.role
44444             };
44445           }
44446
44447           return members;
44448         }
44449
44450         function getVisible(attrs) {
44451           return !attrs.visible || attrs.visible.value !== 'false';
44452         }
44453
44454         function parseComments(comments) {
44455           var parsedComments = []; // for each comment
44456
44457           for (var i = 0; i < comments.length; i++) {
44458             var comment = comments[i];
44459
44460             if (comment.nodeName === 'comment') {
44461               var childNodes = comment.childNodes;
44462               var parsedComment = {};
44463
44464               for (var j = 0; j < childNodes.length; j++) {
44465                 var node = childNodes[j];
44466                 var nodeName = node.nodeName;
44467                 if (nodeName === '#text') continue;
44468                 parsedComment[nodeName] = node.textContent;
44469
44470                 if (nodeName === 'uid') {
44471                   var uid = node.textContent;
44472
44473                   if (uid && !_userCache.user[uid]) {
44474                     _userCache.toLoad[uid] = true;
44475                   }
44476                 }
44477               }
44478
44479               if (parsedComment) {
44480                 parsedComments.push(parsedComment);
44481               }
44482             }
44483           }
44484
44485           return parsedComments;
44486         }
44487
44488         function encodeNoteRtree(note) {
44489           return {
44490             minX: note.loc[0],
44491             minY: note.loc[1],
44492             maxX: note.loc[0],
44493             maxY: note.loc[1],
44494             data: note
44495           };
44496         }
44497
44498         var jsonparsers = {
44499           node: function nodeData(obj, uid) {
44500             return new osmNode({
44501               id: uid,
44502               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44503               version: obj.version && obj.version.toString(),
44504               changeset: obj.changeset && obj.changeset.toString(),
44505               timestamp: obj.timestamp,
44506               user: obj.user,
44507               uid: obj.uid && obj.uid.toString(),
44508               loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
44509               tags: obj.tags
44510             });
44511           },
44512           way: function wayData(obj, uid) {
44513             return new osmWay({
44514               id: uid,
44515               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44516               version: obj.version && obj.version.toString(),
44517               changeset: obj.changeset && obj.changeset.toString(),
44518               timestamp: obj.timestamp,
44519               user: obj.user,
44520               uid: obj.uid && obj.uid.toString(),
44521               tags: obj.tags,
44522               nodes: getNodesJSON(obj)
44523             });
44524           },
44525           relation: function relationData(obj, uid) {
44526             return new osmRelation({
44527               id: uid,
44528               visible: typeof obj.visible === 'boolean' ? obj.visible : true,
44529               version: obj.version && obj.version.toString(),
44530               changeset: obj.changeset && obj.changeset.toString(),
44531               timestamp: obj.timestamp,
44532               user: obj.user,
44533               uid: obj.uid && obj.uid.toString(),
44534               tags: obj.tags,
44535               members: getMembersJSON(obj)
44536             });
44537           }
44538         };
44539
44540         function parseJSON(payload, callback, options) {
44541           options = Object.assign({
44542             skipSeen: true
44543           }, options);
44544
44545           if (!payload) {
44546             return callback({
44547               message: 'No JSON',
44548               status: -1
44549             });
44550           }
44551
44552           var json = payload;
44553           if (_typeof(json) !== 'object') json = JSON.parse(payload);
44554           if (!json.elements) return callback({
44555             message: 'No JSON',
44556             status: -1
44557           });
44558           var children = json.elements;
44559           var handle = window.requestIdleCallback(function () {
44560             var results = [];
44561             var result;
44562
44563             for (var i = 0; i < children.length; i++) {
44564               result = parseChild(children[i]);
44565               if (result) results.push(result);
44566             }
44567
44568             callback(null, results);
44569           });
44570
44571           _deferred.add(handle);
44572
44573           function parseChild(child) {
44574             var parser = jsonparsers[child.type];
44575             if (!parser) return null;
44576             var uid;
44577             uid = osmEntity.id.fromOSM(child.type, child.id);
44578
44579             if (options.skipSeen) {
44580               if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44581
44582               _tileCache.seen[uid] = true;
44583             }
44584
44585             return parser(child, uid);
44586           }
44587         }
44588
44589         var parsers = {
44590           node: function nodeData(obj, uid) {
44591             var attrs = obj.attributes;
44592             return new osmNode({
44593               id: uid,
44594               visible: getVisible(attrs),
44595               version: attrs.version.value,
44596               changeset: attrs.changeset && attrs.changeset.value,
44597               timestamp: attrs.timestamp && attrs.timestamp.value,
44598               user: attrs.user && attrs.user.value,
44599               uid: attrs.uid && attrs.uid.value,
44600               loc: getLoc(attrs),
44601               tags: getTags(obj)
44602             });
44603           },
44604           way: function wayData(obj, uid) {
44605             var attrs = obj.attributes;
44606             return new osmWay({
44607               id: uid,
44608               visible: getVisible(attrs),
44609               version: attrs.version.value,
44610               changeset: attrs.changeset && attrs.changeset.value,
44611               timestamp: attrs.timestamp && attrs.timestamp.value,
44612               user: attrs.user && attrs.user.value,
44613               uid: attrs.uid && attrs.uid.value,
44614               tags: getTags(obj),
44615               nodes: getNodes(obj)
44616             });
44617           },
44618           relation: function relationData(obj, uid) {
44619             var attrs = obj.attributes;
44620             return new osmRelation({
44621               id: uid,
44622               visible: getVisible(attrs),
44623               version: attrs.version.value,
44624               changeset: attrs.changeset && attrs.changeset.value,
44625               timestamp: attrs.timestamp && attrs.timestamp.value,
44626               user: attrs.user && attrs.user.value,
44627               uid: attrs.uid && attrs.uid.value,
44628               tags: getTags(obj),
44629               members: getMembers(obj)
44630             });
44631           },
44632           note: function parseNote(obj, uid) {
44633             var attrs = obj.attributes;
44634             var childNodes = obj.childNodes;
44635             var props = {};
44636             props.id = uid;
44637             props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
44638
44639             var coincident = false;
44640             var epsilon = 0.00001;
44641
44642             do {
44643               if (coincident) {
44644                 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
44645               }
44646
44647               var bbox = geoExtent(props.loc).bbox();
44648               coincident = _noteCache.rtree.search(bbox).length;
44649             } while (coincident); // parse note contents
44650
44651
44652             for (var i = 0; i < childNodes.length; i++) {
44653               var node = childNodes[i];
44654               var nodeName = node.nodeName;
44655               if (nodeName === '#text') continue; // if the element is comments, parse the comments
44656
44657               if (nodeName === 'comments') {
44658                 props[nodeName] = parseComments(node.childNodes);
44659               } else {
44660                 props[nodeName] = node.textContent;
44661               }
44662             }
44663
44664             var note = new osmNote(props);
44665             var item = encodeNoteRtree(note);
44666             _noteCache.note[note.id] = note;
44667
44668             _noteCache.rtree.insert(item);
44669
44670             return note;
44671           },
44672           user: function parseUser(obj, uid) {
44673             var attrs = obj.attributes;
44674             var user = {
44675               id: uid,
44676               display_name: attrs.display_name && attrs.display_name.value,
44677               account_created: attrs.account_created && attrs.account_created.value,
44678               changesets_count: '0',
44679               active_blocks: '0'
44680             };
44681             var img = obj.getElementsByTagName('img');
44682
44683             if (img && img[0] && img[0].getAttribute('href')) {
44684               user.image_url = img[0].getAttribute('href');
44685             }
44686
44687             var changesets = obj.getElementsByTagName('changesets');
44688
44689             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
44690               user.changesets_count = changesets[0].getAttribute('count');
44691             }
44692
44693             var blocks = obj.getElementsByTagName('blocks');
44694
44695             if (blocks && blocks[0]) {
44696               var received = blocks[0].getElementsByTagName('received');
44697
44698               if (received && received[0] && received[0].getAttribute('active')) {
44699                 user.active_blocks = received[0].getAttribute('active');
44700               }
44701             }
44702
44703             _userCache.user[uid] = user;
44704             delete _userCache.toLoad[uid];
44705             return user;
44706           }
44707         };
44708
44709         function parseXML(xml, callback, options) {
44710           options = Object.assign({
44711             skipSeen: true
44712           }, options);
44713
44714           if (!xml || !xml.childNodes) {
44715             return callback({
44716               message: 'No XML',
44717               status: -1
44718             });
44719           }
44720
44721           var root = xml.childNodes[0];
44722           var children = root.childNodes;
44723           var handle = window.requestIdleCallback(function () {
44724             var results = [];
44725             var result;
44726
44727             for (var i = 0; i < children.length; i++) {
44728               result = parseChild(children[i]);
44729               if (result) results.push(result);
44730             }
44731
44732             callback(null, results);
44733           });
44734
44735           _deferred.add(handle);
44736
44737           function parseChild(child) {
44738             var parser = parsers[child.nodeName];
44739             if (!parser) return null;
44740             var uid;
44741
44742             if (child.nodeName === 'user') {
44743               uid = child.attributes.id.value;
44744
44745               if (options.skipSeen && _userCache.user[uid]) {
44746                 delete _userCache.toLoad[uid];
44747                 return null;
44748               }
44749             } else if (child.nodeName === 'note') {
44750               uid = child.getElementsByTagName('id')[0].textContent;
44751             } else {
44752               uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
44753
44754               if (options.skipSeen) {
44755                 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
44756
44757                 _tileCache.seen[uid] = true;
44758               }
44759             }
44760
44761             return parser(child, uid);
44762           }
44763         } // replace or remove note from rtree
44764
44765
44766         function updateRtree$3(item, replace) {
44767           _noteCache.rtree.remove(item, function isEql(a, b) {
44768             return a.data.id === b.data.id;
44769           });
44770
44771           if (replace) {
44772             _noteCache.rtree.insert(item);
44773           }
44774         }
44775
44776         function wrapcb(thisArg, callback, cid) {
44777           return function (err, result) {
44778             if (err) {
44779               // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
44780               if (err.status === 400 || err.status === 401 || err.status === 403) {
44781                 thisArg.logout();
44782               }
44783
44784               return callback.call(thisArg, err);
44785             } else if (thisArg.getConnectionId() !== cid) {
44786               return callback.call(thisArg, {
44787                 message: 'Connection Switched',
44788                 status: -1
44789               });
44790             } else {
44791               return callback.call(thisArg, err, result);
44792             }
44793           };
44794         }
44795
44796         var serviceOsm = {
44797           init: function init() {
44798             utilRebind(this, dispatch$6, 'on');
44799           },
44800           reset: function reset() {
44801             Array.from(_deferred).forEach(function (handle) {
44802               window.cancelIdleCallback(handle);
44803
44804               _deferred["delete"](handle);
44805             });
44806             _connectionID++;
44807             _userChangesets = undefined;
44808             _userDetails = undefined;
44809             _rateLimitError = undefined;
44810             Object.values(_tileCache.inflight).forEach(abortRequest$5);
44811             Object.values(_noteCache.inflight).forEach(abortRequest$5);
44812             Object.values(_noteCache.inflightPost).forEach(abortRequest$5);
44813             if (_changeset.inflight) abortRequest$5(_changeset.inflight);
44814             _tileCache = {
44815               toLoad: {},
44816               loaded: {},
44817               inflight: {},
44818               seen: {},
44819               rtree: new RBush()
44820             };
44821             _noteCache = {
44822               toLoad: {},
44823               loaded: {},
44824               inflight: {},
44825               inflightPost: {},
44826               note: {},
44827               closed: {},
44828               rtree: new RBush()
44829             };
44830             _userCache = {
44831               toLoad: {},
44832               user: {}
44833             };
44834             _cachedApiStatus = undefined;
44835             _changeset = {};
44836             return this;
44837           },
44838           getConnectionId: function getConnectionId() {
44839             return _connectionID;
44840           },
44841           changesetURL: function changesetURL(changesetID) {
44842             return urlroot + '/changeset/' + changesetID;
44843           },
44844           changesetsURL: function changesetsURL(center, zoom) {
44845             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
44846             return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
44847           },
44848           entityURL: function entityURL(entity) {
44849             return urlroot + '/' + entity.type + '/' + entity.osmId();
44850           },
44851           historyURL: function historyURL(entity) {
44852             return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
44853           },
44854           userURL: function userURL(username) {
44855             return urlroot + '/user/' + username;
44856           },
44857           noteURL: function noteURL(note) {
44858             return urlroot + '/note/' + note.id;
44859           },
44860           noteReportURL: function noteReportURL(note) {
44861             return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
44862           },
44863           // Generic method to load data from the OSM API
44864           // Can handle either auth or unauth calls.
44865           loadFromAPI: function loadFromAPI(path, callback, options) {
44866             options = Object.assign({
44867               skipSeen: true
44868             }, options);
44869             var that = this;
44870             var cid = _connectionID;
44871
44872             function done(err, payload) {
44873               if (that.getConnectionId() !== cid) {
44874                 if (callback) callback({
44875                   message: 'Connection Switched',
44876                   status: -1
44877                 });
44878                 return;
44879               }
44880
44881               var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
44882               // Logout and retry the request..
44883
44884               if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
44885                 that.logout();
44886                 that.loadFromAPI(path, callback, options); // else, no retry..
44887               } else {
44888                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
44889                 // Set the rateLimitError flag and trigger a warning..
44890                 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
44891                   _rateLimitError = err;
44892                   dispatch$6.call('change');
44893                   that.reloadApiStatus();
44894                 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
44895                   // If the response's error state doesn't match the status,
44896                   // it's likely we lost or gained the connection so reload the status
44897                   that.reloadApiStatus();
44898                 }
44899
44900                 if (callback) {
44901                   if (err) {
44902                     return callback(err);
44903                   } else {
44904                     if (path.indexOf('.json') !== -1) {
44905                       return parseJSON(payload, callback, options);
44906                     } else {
44907                       return parseXML(payload, callback, options);
44908                     }
44909                   }
44910                 }
44911               }
44912             }
44913
44914             if (this.authenticated()) {
44915               return oauth.xhr({
44916                 method: 'GET',
44917                 path: path
44918               }, done);
44919             } else {
44920               var url = urlroot + path;
44921               var controller = new AbortController();
44922               d3_json(url, {
44923                 signal: controller.signal
44924               }).then(function (data) {
44925                 done(null, data);
44926               })["catch"](function (err) {
44927                 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
44928                 // but we can't access the response itself
44929                 // https://github.com/d3/d3-fetch/issues/27
44930
44931                 var match = err.message.match(/^\d{3}/);
44932
44933                 if (match) {
44934                   done({
44935                     status: +match[0],
44936                     statusText: err.message
44937                   });
44938                 } else {
44939                   done(err.message);
44940                 }
44941               });
44942               return controller;
44943             }
44944           },
44945           // Load a single entity by id (ways and relations use the `/full` call)
44946           // GET /api/0.6/node/#id
44947           // GET /api/0.6/[way|relation]/#id/full
44948           loadEntity: function loadEntity(id, callback) {
44949             var type = osmEntity.id.type(id);
44950             var osmID = osmEntity.id.toOSM(id);
44951             var options = {
44952               skipSeen: false
44953             };
44954             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
44955               if (callback) callback(err, {
44956                 data: entities
44957               });
44958             }, options);
44959           },
44960           // Load a single entity with a specific version
44961           // GET /api/0.6/[node|way|relation]/#id/#version
44962           loadEntityVersion: function loadEntityVersion(id, version, callback) {
44963             var type = osmEntity.id.type(id);
44964             var osmID = osmEntity.id.toOSM(id);
44965             var options = {
44966               skipSeen: false
44967             };
44968             this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
44969               if (callback) callback(err, {
44970                 data: entities
44971               });
44972             }, options);
44973           },
44974           // Load multiple entities in chunks
44975           // (note: callback may be called multiple times)
44976           // Unlike `loadEntity`, child nodes and members are not fetched
44977           // GET /api/0.6/[nodes|ways|relations]?#parameters
44978           loadMultiple: function loadMultiple(ids, callback) {
44979             var that = this;
44980             var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
44981             Object.keys(groups).forEach(function (k) {
44982               var type = k + 's'; // nodes, ways, relations
44983
44984               var osmIDs = groups[k].map(function (id) {
44985                 return osmEntity.id.toOSM(id);
44986               });
44987               var options = {
44988                 skipSeen: false
44989               };
44990               utilArrayChunk(osmIDs, 150).forEach(function (arr) {
44991                 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
44992                   if (callback) callback(err, {
44993                     data: entities
44994                   });
44995                 }, options);
44996               });
44997             });
44998           },
44999           // Create, upload, and close a changeset
45000           // PUT /api/0.6/changeset/create
45001           // POST /api/0.6/changeset/#id/upload
45002           // PUT /api/0.6/changeset/#id/close
45003           putChangeset: function putChangeset(changeset, changes, callback) {
45004             var cid = _connectionID;
45005
45006             if (_changeset.inflight) {
45007               return callback({
45008                 message: 'Changeset already inflight',
45009                 status: -2
45010               }, changeset);
45011             } else if (_changeset.open) {
45012               // reuse existing open changeset..
45013               return createdChangeset.call(this, null, _changeset.open);
45014             } else {
45015               // Open a new changeset..
45016               var options = {
45017                 method: 'PUT',
45018                 path: '/api/0.6/changeset/create',
45019                 options: {
45020                   header: {
45021                     'Content-Type': 'text/xml'
45022                   }
45023                 },
45024                 content: JXON.stringify(changeset.asJXON())
45025               };
45026               _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
45027             }
45028
45029             function createdChangeset(err, changesetID) {
45030               _changeset.inflight = null;
45031
45032               if (err) {
45033                 return callback(err, changeset);
45034               }
45035
45036               _changeset.open = changesetID;
45037               changeset = changeset.update({
45038                 id: changesetID
45039               }); // Upload the changeset..
45040
45041               var options = {
45042                 method: 'POST',
45043                 path: '/api/0.6/changeset/' + changesetID + '/upload',
45044                 options: {
45045                   header: {
45046                     'Content-Type': 'text/xml'
45047                   }
45048                 },
45049                 content: JXON.stringify(changeset.osmChangeJXON(changes))
45050               };
45051               _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
45052             }
45053
45054             function uploadedChangeset(err) {
45055               _changeset.inflight = null;
45056               if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
45057               // Add delay to allow for postgres replication #1646 #2678
45058
45059               window.setTimeout(function () {
45060                 callback(null, changeset);
45061               }, 2500);
45062               _changeset.open = null; // At this point, we don't really care if the connection was switched..
45063               // Only try to close the changeset if we're still talking to the same server.
45064
45065               if (this.getConnectionId() === cid) {
45066                 // Still attempt to close changeset, but ignore response because #2667
45067                 oauth.xhr({
45068                   method: 'PUT',
45069                   path: '/api/0.6/changeset/' + changeset.id + '/close',
45070                   options: {
45071                     header: {
45072                       'Content-Type': 'text/xml'
45073                     }
45074                   }
45075                 }, function () {
45076                   return true;
45077                 });
45078               }
45079             }
45080           },
45081           // Load multiple users in chunks
45082           // (note: callback may be called multiple times)
45083           // GET /api/0.6/users?users=#id1,#id2,...,#idn
45084           loadUsers: function loadUsers(uids, callback) {
45085             var toLoad = [];
45086             var cached = [];
45087             utilArrayUniq(uids).forEach(function (uid) {
45088               if (_userCache.user[uid]) {
45089                 delete _userCache.toLoad[uid];
45090                 cached.push(_userCache.user[uid]);
45091               } else {
45092                 toLoad.push(uid);
45093               }
45094             });
45095
45096             if (cached.length || !this.authenticated()) {
45097               callback(undefined, cached);
45098               if (!this.authenticated()) return; // require auth
45099             }
45100
45101             utilArrayChunk(toLoad, 150).forEach(function (arr) {
45102               oauth.xhr({
45103                 method: 'GET',
45104                 path: '/api/0.6/users?users=' + arr.join()
45105               }, wrapcb(this, done, _connectionID));
45106             }.bind(this));
45107
45108             function done(err, xml) {
45109               if (err) {
45110                 return callback(err);
45111               }
45112
45113               var options = {
45114                 skipSeen: true
45115               };
45116               return parseXML(xml, function (err, results) {
45117                 if (err) {
45118                   return callback(err);
45119                 } else {
45120                   return callback(undefined, results);
45121                 }
45122               }, options);
45123             }
45124           },
45125           // Load a given user by id
45126           // GET /api/0.6/user/#id
45127           loadUser: function loadUser(uid, callback) {
45128             if (_userCache.user[uid] || !this.authenticated()) {
45129               // require auth
45130               delete _userCache.toLoad[uid];
45131               return callback(undefined, _userCache.user[uid]);
45132             }
45133
45134             oauth.xhr({
45135               method: 'GET',
45136               path: '/api/0.6/user/' + uid
45137             }, wrapcb(this, done, _connectionID));
45138
45139             function done(err, xml) {
45140               if (err) {
45141                 return callback(err);
45142               }
45143
45144               var options = {
45145                 skipSeen: true
45146               };
45147               return parseXML(xml, function (err, results) {
45148                 if (err) {
45149                   return callback(err);
45150                 } else {
45151                   return callback(undefined, results[0]);
45152                 }
45153               }, options);
45154             }
45155           },
45156           // Load the details of the logged-in user
45157           // GET /api/0.6/user/details
45158           userDetails: function userDetails(callback) {
45159             if (_userDetails) {
45160               // retrieve cached
45161               return callback(undefined, _userDetails);
45162             }
45163
45164             oauth.xhr({
45165               method: 'GET',
45166               path: '/api/0.6/user/details'
45167             }, wrapcb(this, done, _connectionID));
45168
45169             function done(err, xml) {
45170               if (err) {
45171                 return callback(err);
45172               }
45173
45174               var options = {
45175                 skipSeen: false
45176               };
45177               return parseXML(xml, function (err, results) {
45178                 if (err) {
45179                   return callback(err);
45180                 } else {
45181                   _userDetails = results[0];
45182                   return callback(undefined, _userDetails);
45183                 }
45184               }, options);
45185             }
45186           },
45187           // Load previous changesets for the logged in user
45188           // GET /api/0.6/changesets?user=#id
45189           userChangesets: function userChangesets(callback) {
45190             if (_userChangesets) {
45191               // retrieve cached
45192               return callback(undefined, _userChangesets);
45193             }
45194
45195             this.userDetails(wrapcb(this, gotDetails, _connectionID));
45196
45197             function gotDetails(err, user) {
45198               if (err) {
45199                 return callback(err);
45200               }
45201
45202               oauth.xhr({
45203                 method: 'GET',
45204                 path: '/api/0.6/changesets?user=' + user.id
45205               }, wrapcb(this, done, _connectionID));
45206             }
45207
45208             function done(err, xml) {
45209               if (err) {
45210                 return callback(err);
45211               }
45212
45213               _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
45214                 return {
45215                   tags: getTags(changeset)
45216                 };
45217               }).filter(function (changeset) {
45218                 var comment = changeset.tags.comment;
45219                 return comment && comment !== '';
45220               });
45221               return callback(undefined, _userChangesets);
45222             }
45223           },
45224           // Fetch the status of the OSM API
45225           // GET /api/capabilities
45226           status: function status(callback) {
45227             var url = urlroot + '/api/capabilities';
45228             var errback = wrapcb(this, done, _connectionID);
45229             d3_xml(url).then(function (data) {
45230               errback(null, data);
45231             })["catch"](function (err) {
45232               errback(err.message);
45233             });
45234
45235             function done(err, xml) {
45236               if (err) {
45237                 // the status is null if no response could be retrieved
45238                 return callback(err, null);
45239               } // update blocklists
45240
45241
45242               var elements = xml.getElementsByTagName('blacklist');
45243               var regexes = [];
45244
45245               for (var i = 0; i < elements.length; i++) {
45246                 var regexString = elements[i].getAttribute('regex'); // needs unencode?
45247
45248                 if (regexString) {
45249                   try {
45250                     var regex = new RegExp(regexString);
45251                     regexes.push(regex);
45252                   } catch (e) {
45253                     /* noop */
45254                   }
45255                 }
45256               }
45257
45258               if (regexes.length) {
45259                 _imageryBlocklists = regexes;
45260               }
45261
45262               if (_rateLimitError) {
45263                 return callback(_rateLimitError, 'rateLimited');
45264               } else {
45265                 var waynodes = xml.getElementsByTagName('waynodes');
45266                 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
45267                 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
45268                 var apiStatus = xml.getElementsByTagName('status');
45269                 var val = apiStatus[0].getAttribute('api');
45270                 return callback(undefined, val);
45271               }
45272             }
45273           },
45274           // Calls `status` and dispatches an `apiStatusChange` event if the returned
45275           // status differs from the cached status.
45276           reloadApiStatus: function reloadApiStatus() {
45277             // throttle to avoid unnecessary API calls
45278             if (!this.throttledReloadApiStatus) {
45279               var that = this;
45280               this.throttledReloadApiStatus = throttle(function () {
45281                 that.status(function (err, status) {
45282                   if (status !== _cachedApiStatus) {
45283                     _cachedApiStatus = status;
45284                     dispatch$6.call('apiStatusChange', that, err, status);
45285                   }
45286                 });
45287               }, 500);
45288             }
45289
45290             this.throttledReloadApiStatus();
45291           },
45292           // Returns the maximum number of nodes a single way can have
45293           maxWayNodes: function maxWayNodes() {
45294             return _maxWayNodes;
45295           },
45296           // Load data (entities) from the API in tiles
45297           // GET /api/0.6/map?bbox=
45298           loadTiles: function loadTiles(projection, callback) {
45299             if (_off) return; // determine the needed tiles to cover the view
45300
45301             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
45302
45303             var hadRequests = hasInflightRequests(_tileCache);
45304             abortUnwantedRequests$3(_tileCache, tiles);
45305
45306             if (hadRequests && !hasInflightRequests(_tileCache)) {
45307               dispatch$6.call('loaded'); // stop the spinner
45308             } // issue new requests..
45309
45310
45311             tiles.forEach(function (tile) {
45312               this.loadTile(tile, callback);
45313             }, this);
45314           },
45315           // Load a single data tile
45316           // GET /api/0.6/map?bbox=
45317           loadTile: function loadTile(tile, callback) {
45318             if (_off) return;
45319             if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45320
45321             if (!hasInflightRequests(_tileCache)) {
45322               dispatch$6.call('loading'); // start the spinner
45323             }
45324
45325             var path = '/api/0.6/map.json?bbox=';
45326             var options = {
45327               skipSeen: true
45328             };
45329             _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
45330
45331             function tileCallback(err, parsed) {
45332               delete _tileCache.inflight[tile.id];
45333
45334               if (!err) {
45335                 delete _tileCache.toLoad[tile.id];
45336                 _tileCache.loaded[tile.id] = true;
45337                 var bbox = tile.extent.bbox();
45338                 bbox.id = tile.id;
45339
45340                 _tileCache.rtree.insert(bbox);
45341               }
45342
45343               if (callback) {
45344                 callback(err, Object.assign({
45345                   data: parsed
45346                 }, tile));
45347               }
45348
45349               if (!hasInflightRequests(_tileCache)) {
45350                 dispatch$6.call('loaded'); // stop the spinner
45351               }
45352             }
45353           },
45354           isDataLoaded: function isDataLoaded(loc) {
45355             var bbox = {
45356               minX: loc[0],
45357               minY: loc[1],
45358               maxX: loc[0],
45359               maxY: loc[1]
45360             };
45361             return _tileCache.rtree.collides(bbox);
45362           },
45363           // load the tile that covers the given `loc`
45364           loadTileAtLoc: function loadTileAtLoc(loc, callback) {
45365             // Back off if the toLoad queue is filling up.. re #6417
45366             // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
45367             // let users safely edit geometries which extend to unloaded tiles.  We can drop some.)
45368             if (Object.keys(_tileCache.toLoad).length > 50) return;
45369             var k = geoZoomToScale(_tileZoom$3 + 1);
45370             var offset = geoRawMercator().scale(k)(loc);
45371             var projection = geoRawMercator().transform({
45372               k: k,
45373               x: -offset[0],
45374               y: -offset[1]
45375             });
45376             var tiles = tiler$5.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection);
45377             tiles.forEach(function (tile) {
45378               if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
45379               _tileCache.toLoad[tile.id] = true;
45380               this.loadTile(tile, callback);
45381             }, this);
45382           },
45383           // Load notes from the API in tiles
45384           // GET /api/0.6/notes?bbox=
45385           loadNotes: function loadNotes(projection, noteOptions) {
45386             noteOptions = Object.assign({
45387               limit: 10000,
45388               closed: 7
45389             }, noteOptions);
45390             if (_off) return;
45391             var that = this;
45392             var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
45393
45394             var throttleLoadUsers = throttle(function () {
45395               var uids = Object.keys(_userCache.toLoad);
45396               if (!uids.length) return;
45397               that.loadUsers(uids, function () {}); // eagerly load user details
45398             }, 750); // determine the needed tiles to cover the view
45399
45400
45401             var tiles = tiler$5.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
45402
45403             abortUnwantedRequests$3(_noteCache, tiles); // issue new requests..
45404
45405             tiles.forEach(function (tile) {
45406               if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
45407               var options = {
45408                 skipSeen: false
45409               };
45410               _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
45411                 delete _noteCache.inflight[tile.id];
45412
45413                 if (!err) {
45414                   _noteCache.loaded[tile.id] = true;
45415                 }
45416
45417                 throttleLoadUsers();
45418                 dispatch$6.call('loadedNotes');
45419               }, options);
45420             });
45421           },
45422           // Create a note
45423           // POST /api/0.6/notes?params
45424           postNoteCreate: function postNoteCreate(note, callback) {
45425             if (!this.authenticated()) {
45426               return callback({
45427                 message: 'Not Authenticated',
45428                 status: -3
45429               }, note);
45430             }
45431
45432             if (_noteCache.inflightPost[note.id]) {
45433               return callback({
45434                 message: 'Note update already inflight',
45435                 status: -2
45436               }, note);
45437             }
45438
45439             if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
45440
45441             var comment = note.newComment;
45442
45443             if (note.newCategory && note.newCategory !== 'None') {
45444               comment += ' #' + note.newCategory;
45445             }
45446
45447             var path = '/api/0.6/notes?' + utilQsString({
45448               lon: note.loc[0],
45449               lat: note.loc[1],
45450               text: comment
45451             });
45452             _noteCache.inflightPost[note.id] = oauth.xhr({
45453               method: 'POST',
45454               path: path
45455             }, wrapcb(this, done, _connectionID));
45456
45457             function done(err, xml) {
45458               delete _noteCache.inflightPost[note.id];
45459
45460               if (err) {
45461                 return callback(err);
45462               } // we get the updated note back, remove from caches and reparse..
45463
45464
45465               this.removeNote(note);
45466               var options = {
45467                 skipSeen: false
45468               };
45469               return parseXML(xml, function (err, results) {
45470                 if (err) {
45471                   return callback(err);
45472                 } else {
45473                   return callback(undefined, results[0]);
45474                 }
45475               }, options);
45476             }
45477           },
45478           // Update a note
45479           // POST /api/0.6/notes/#id/comment?text=comment
45480           // POST /api/0.6/notes/#id/close?text=comment
45481           // POST /api/0.6/notes/#id/reopen?text=comment
45482           postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
45483             if (!this.authenticated()) {
45484               return callback({
45485                 message: 'Not Authenticated',
45486                 status: -3
45487               }, note);
45488             }
45489
45490             if (_noteCache.inflightPost[note.id]) {
45491               return callback({
45492                 message: 'Note update already inflight',
45493                 status: -2
45494               }, note);
45495             }
45496
45497             var action;
45498
45499             if (note.status !== 'closed' && newStatus === 'closed') {
45500               action = 'close';
45501             } else if (note.status !== 'open' && newStatus === 'open') {
45502               action = 'reopen';
45503             } else {
45504               action = 'comment';
45505               if (!note.newComment) return; // when commenting, comment required
45506             }
45507
45508             var path = '/api/0.6/notes/' + note.id + '/' + action;
45509
45510             if (note.newComment) {
45511               path += '?' + utilQsString({
45512                 text: note.newComment
45513               });
45514             }
45515
45516             _noteCache.inflightPost[note.id] = oauth.xhr({
45517               method: 'POST',
45518               path: path
45519             }, wrapcb(this, done, _connectionID));
45520
45521             function done(err, xml) {
45522               delete _noteCache.inflightPost[note.id];
45523
45524               if (err) {
45525                 return callback(err);
45526               } // we get the updated note back, remove from caches and reparse..
45527
45528
45529               this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
45530
45531               if (action === 'close') {
45532                 _noteCache.closed[note.id] = true;
45533               } else if (action === 'reopen') {
45534                 delete _noteCache.closed[note.id];
45535               }
45536
45537               var options = {
45538                 skipSeen: false
45539               };
45540               return parseXML(xml, function (err, results) {
45541                 if (err) {
45542                   return callback(err);
45543                 } else {
45544                   return callback(undefined, results[0]);
45545                 }
45546               }, options);
45547             }
45548           },
45549           "switch": function _switch(options) {
45550             urlroot = options.urlroot;
45551             oauth.options(Object.assign({
45552               url: urlroot,
45553               loading: authLoading,
45554               done: authDone
45555             }, options));
45556             this.reset();
45557             this.userChangesets(function () {}); // eagerly load user details/changesets
45558
45559             dispatch$6.call('change');
45560             return this;
45561           },
45562           toggle: function toggle(val) {
45563             _off = !val;
45564             return this;
45565           },
45566           isChangesetInflight: function isChangesetInflight() {
45567             return !!_changeset.inflight;
45568           },
45569           // get/set cached data
45570           // This is used to save/restore the state when entering/exiting the walkthrough
45571           // Also used for testing purposes.
45572           caches: function caches(obj) {
45573             function cloneCache(source) {
45574               var target = {};
45575               Object.keys(source).forEach(function (k) {
45576                 if (k === 'rtree') {
45577                   target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
45578                 } else if (k === 'note') {
45579                   target.note = {};
45580                   Object.keys(source.note).forEach(function (id) {
45581                     target.note[id] = osmNote(source.note[id]); // copy notes
45582                   });
45583                 } else {
45584                   target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
45585                 }
45586               });
45587               return target;
45588             }
45589
45590             if (!arguments.length) {
45591               return {
45592                 tile: cloneCache(_tileCache),
45593                 note: cloneCache(_noteCache),
45594                 user: cloneCache(_userCache)
45595               };
45596             } // access caches directly for testing (e.g., loading notes rtree)
45597
45598
45599             if (obj === 'get') {
45600               return {
45601                 tile: _tileCache,
45602                 note: _noteCache,
45603                 user: _userCache
45604               };
45605             }
45606
45607             if (obj.tile) {
45608               _tileCache = obj.tile;
45609               _tileCache.inflight = {};
45610             }
45611
45612             if (obj.note) {
45613               _noteCache = obj.note;
45614               _noteCache.inflight = {};
45615               _noteCache.inflightPost = {};
45616             }
45617
45618             if (obj.user) {
45619               _userCache = obj.user;
45620             }
45621
45622             return this;
45623           },
45624           logout: function logout() {
45625             _userChangesets = undefined;
45626             _userDetails = undefined;
45627             oauth.logout();
45628             dispatch$6.call('change');
45629             return this;
45630           },
45631           authenticated: function authenticated() {
45632             return oauth.authenticated();
45633           },
45634           authenticate: function authenticate(callback) {
45635             var that = this;
45636             var cid = _connectionID;
45637             _userChangesets = undefined;
45638             _userDetails = undefined;
45639
45640             function done(err, res) {
45641               if (err) {
45642                 if (callback) callback(err);
45643                 return;
45644               }
45645
45646               if (that.getConnectionId() !== cid) {
45647                 if (callback) callback({
45648                   message: 'Connection Switched',
45649                   status: -1
45650                 });
45651                 return;
45652               }
45653
45654               _rateLimitError = undefined;
45655               dispatch$6.call('change');
45656               if (callback) callback(err, res);
45657               that.userChangesets(function () {}); // eagerly load user details/changesets
45658             }
45659
45660             return oauth.authenticate(done);
45661           },
45662           imageryBlocklists: function imageryBlocklists() {
45663             return _imageryBlocklists;
45664           },
45665           tileZoom: function tileZoom(val) {
45666             if (!arguments.length) return _tileZoom$3;
45667             _tileZoom$3 = val;
45668             return this;
45669           },
45670           // get all cached notes covering the viewport
45671           notes: function notes(projection) {
45672             var viewport = projection.clipExtent();
45673             var min = [viewport[0][0], viewport[1][1]];
45674             var max = [viewport[1][0], viewport[0][1]];
45675             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
45676             return _noteCache.rtree.search(bbox).map(function (d) {
45677               return d.data;
45678             });
45679           },
45680           // get a single note from the cache
45681           getNote: function getNote(id) {
45682             return _noteCache.note[id];
45683           },
45684           // remove a single note from the cache
45685           removeNote: function removeNote(note) {
45686             if (!(note instanceof osmNote) || !note.id) return;
45687             delete _noteCache.note[note.id];
45688             updateRtree$3(encodeNoteRtree(note), false); // false = remove
45689           },
45690           // replace a single note in the cache
45691           replaceNote: function replaceNote(note) {
45692             if (!(note instanceof osmNote) || !note.id) return;
45693             _noteCache.note[note.id] = note;
45694             updateRtree$3(encodeNoteRtree(note), true); // true = replace
45695
45696             return note;
45697           },
45698           // Get an array of note IDs closed during this session.
45699           // Used to populate `closed:note` changeset tag
45700           getClosedIDs: function getClosedIDs() {
45701             return Object.keys(_noteCache.closed).sort();
45702           }
45703         };
45704
45705         var _apibase = 'https://wiki.openstreetmap.org/w/api.php';
45706         var _inflight$1 = {};
45707         var _wikibaseCache = {};
45708         var _localeIDs = {
45709           en: false
45710         };
45711
45712         var debouncedRequest = debounce(request, 500, {
45713           leading: false
45714         });
45715
45716         function request(url, callback) {
45717           if (_inflight$1[url]) return;
45718           var controller = new AbortController();
45719           _inflight$1[url] = controller;
45720           d3_json(url, {
45721             signal: controller.signal
45722           }).then(function (result) {
45723             delete _inflight$1[url];
45724             if (callback) callback(null, result);
45725           })["catch"](function (err) {
45726             delete _inflight$1[url];
45727             if (err.name === 'AbortError') return;
45728             if (callback) callback(err.message);
45729           });
45730         }
45731
45732         var serviceOsmWikibase = {
45733           init: function init() {
45734             _inflight$1 = {};
45735             _wikibaseCache = {};
45736             _localeIDs = {};
45737           },
45738           reset: function reset() {
45739             Object.values(_inflight$1).forEach(function (controller) {
45740               controller.abort();
45741             });
45742             _inflight$1 = {};
45743           },
45744
45745           /**
45746            * Get the best value for the property, or undefined if not found
45747            * @param entity object from wikibase
45748            * @param property string e.g. 'P4' for image
45749            * @param langCode string e.g. 'fr' for French
45750            */
45751           claimToValue: function claimToValue(entity, property, langCode) {
45752             if (!entity.claims[property]) return undefined;
45753             var locale = _localeIDs[langCode];
45754             var preferredPick, localePick;
45755             entity.claims[property].forEach(function (stmt) {
45756               // If exists, use value limited to the needed language (has a qualifier P26 = locale)
45757               // Or if not found, use the first value with the "preferred" rank
45758               if (!preferredPick && stmt.rank === 'preferred') {
45759                 preferredPick = stmt;
45760               }
45761
45762               if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
45763                 localePick = stmt;
45764               }
45765             });
45766             var result = localePick || preferredPick;
45767
45768             if (result) {
45769               var datavalue = result.mainsnak.datavalue;
45770               return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
45771             } else {
45772               return undefined;
45773             }
45774           },
45775
45776           /**
45777            * Convert monolingual property into a key-value object (language -> value)
45778            * @param entity object from wikibase
45779            * @param property string e.g. 'P31' for monolingual wiki page title
45780            */
45781           monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
45782             if (!entity || !entity.claims[property]) return undefined;
45783             return entity.claims[property].reduce(function (acc, obj) {
45784               var value = obj.mainsnak.datavalue.value;
45785               acc[value.language] = value.text;
45786               return acc;
45787             }, {});
45788           },
45789           toSitelink: function toSitelink(key, value) {
45790             var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
45791             return result.replace(/_/g, ' ').trim();
45792           },
45793           //
45794           // Pass params object of the form:
45795           // {
45796           //   key: 'string',
45797           //   value: 'string',
45798           //   langCode: 'string'
45799           // }
45800           //
45801           getEntity: function getEntity(params, callback) {
45802             var doRequest = params.debounce ? debouncedRequest : request;
45803             var that = this;
45804             var titles = [];
45805             var result = {};
45806             var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
45807             var keySitelink = params.key ? this.toSitelink(params.key) : false;
45808             var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
45809             var localeSitelink;
45810
45811             if (params.langCodes) {
45812               params.langCodes.forEach(function (langCode) {
45813                 if (_localeIDs[langCode] === undefined) {
45814                   // If this is the first time we are asking about this locale,
45815                   // fetch corresponding entity (if it exists), and cache it.
45816                   // If there is no such entry, cache `false` value to avoid re-requesting it.
45817                   localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
45818                   titles.push(localeSitelink);
45819                 }
45820               });
45821             }
45822
45823             if (rtypeSitelink) {
45824               if (_wikibaseCache[rtypeSitelink]) {
45825                 result.rtype = _wikibaseCache[rtypeSitelink];
45826               } else {
45827                 titles.push(rtypeSitelink);
45828               }
45829             }
45830
45831             if (keySitelink) {
45832               if (_wikibaseCache[keySitelink]) {
45833                 result.key = _wikibaseCache[keySitelink];
45834               } else {
45835                 titles.push(keySitelink);
45836               }
45837             }
45838
45839             if (tagSitelink) {
45840               if (_wikibaseCache[tagSitelink]) {
45841                 result.tag = _wikibaseCache[tagSitelink];
45842               } else {
45843                 titles.push(tagSitelink);
45844               }
45845             }
45846
45847             if (!titles.length) {
45848               // Nothing to do, we already had everything in the cache
45849               return callback(null, result);
45850             } // Requesting just the user language code
45851             // If backend recognizes the code, it will perform proper fallbacks,
45852             // and the result will contain the requested code. If not, all values are returned:
45853             // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
45854             // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
45855
45856
45857             var obj = {
45858               action: 'wbgetentities',
45859               sites: 'wiki',
45860               titles: titles.join('|'),
45861               languages: params.langCodes.join('|'),
45862               languagefallback: 1,
45863               origin: '*',
45864               format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
45865               // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
45866               // formatversion: 2,
45867
45868             };
45869             var url = _apibase + '?' + utilQsString(obj);
45870             doRequest(url, function (err, d) {
45871               if (err) {
45872                 callback(err);
45873               } else if (!d.success || d.error) {
45874                 callback(d.error.messages.map(function (v) {
45875                   return v.html['*'];
45876                 }).join('<br>'));
45877               } else {
45878                 var localeID = false;
45879                 Object.values(d.entities).forEach(function (res) {
45880                   if (res.missing !== '') {
45881                     var title = res.sitelinks.wiki.title;
45882
45883                     if (title === rtypeSitelink) {
45884                       _wikibaseCache[rtypeSitelink] = res;
45885                       result.rtype = res;
45886                     } else if (title === keySitelink) {
45887                       _wikibaseCache[keySitelink] = res;
45888                       result.key = res;
45889                     } else if (title === tagSitelink) {
45890                       _wikibaseCache[tagSitelink] = res;
45891                       result.tag = res;
45892                     } else if (title === localeSitelink) {
45893                       localeID = res.id;
45894                     } else {
45895                       console.log('Unexpected title ' + title); // eslint-disable-line no-console
45896                     }
45897                   }
45898                 });
45899
45900                 if (localeSitelink) {
45901                   // If locale ID is not found, store false to prevent repeated queries
45902                   that.addLocale(params.langCodes[0], localeID);
45903                 }
45904
45905                 callback(null, result);
45906               }
45907             });
45908           },
45909           //
45910           // Pass params object of the form:
45911           // {
45912           //   key: 'string',     // required
45913           //   value: 'string'    // optional
45914           // }
45915           //
45916           // Get an result object used to display tag documentation
45917           // {
45918           //   title:        'string',
45919           //   description:  'string',
45920           //   editURL:      'string',
45921           //   imageURL:     'string',
45922           //   wiki:         { title: 'string', text: 'string', url: 'string' }
45923           // }
45924           //
45925           getDocs: function getDocs(params, callback) {
45926             var that = this;
45927             var langCodes = _mainLocalizer.localeCodes().map(function (code) {
45928               return code.toLowerCase();
45929             });
45930             params.langCodes = langCodes;
45931             this.getEntity(params, function (err, data) {
45932               if (err) {
45933                 callback(err);
45934                 return;
45935               }
45936
45937               var entity = data.rtype || data.tag || data.key;
45938
45939               if (!entity) {
45940                 callback('No entity');
45941                 return;
45942               }
45943
45944               var i;
45945               var description;
45946
45947               for (i in langCodes) {
45948                 var _code = langCodes[i];
45949
45950                 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
45951                   description = entity.descriptions[_code];
45952                   break;
45953                 }
45954               }
45955
45956               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
45957
45958               var result = {
45959                 title: entity.title,
45960                 description: description ? description.value : '',
45961                 descriptionLocaleCode: description ? description.language : '',
45962                 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
45963               }; // add image
45964
45965               if (entity.claims) {
45966                 var imageroot;
45967                 var image = that.claimToValue(entity, 'P4', langCodes[0]);
45968
45969                 if (image) {
45970                   imageroot = 'https://commons.wikimedia.org/w/index.php';
45971                 } else {
45972                   image = that.claimToValue(entity, 'P28', langCodes[0]);
45973
45974                   if (image) {
45975                     imageroot = 'https://wiki.openstreetmap.org/w/index.php';
45976                   }
45977                 }
45978
45979                 if (imageroot && image) {
45980                   result.imageURL = imageroot + '?' + utilQsString({
45981                     title: 'Special:Redirect/file/' + image,
45982                     width: 400
45983                   });
45984                 }
45985               } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
45986               // If neither tag nor key data item contain a wiki page in the needed language nor English,
45987               // get the first found wiki page from either the tag or the key item.
45988
45989
45990               var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
45991               var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
45992               var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
45993               var wikis = [rtypeWiki, tagWiki, keyWiki];
45994
45995               for (i in wikis) {
45996                 var wiki = wikis[i];
45997
45998                 for (var j in langCodes) {
45999                   var code = langCodes[j];
46000                   var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
46001                   var info = getWikiInfo(wiki, code, referenceId);
46002
46003                   if (info) {
46004                     result.wiki = info;
46005                     break;
46006                   }
46007                 }
46008
46009                 if (result.wiki) break;
46010               }
46011
46012               callback(null, result); // Helper method to get wiki info if a given language exists
46013
46014               function getWikiInfo(wiki, langCode, tKey) {
46015                 if (wiki && wiki[langCode]) {
46016                   return {
46017                     title: wiki[langCode],
46018                     text: tKey,
46019                     url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
46020                   };
46021                 }
46022               }
46023             });
46024           },
46025           addLocale: function addLocale(langCode, qid) {
46026             // Makes it easier to unit test
46027             _localeIDs[langCode] = qid;
46028           },
46029           apibase: function apibase(val) {
46030             if (!arguments.length) return _apibase;
46031             _apibase = val;
46032             return this;
46033           }
46034         };
46035
46036         var jsonpCache = {};
46037         window.jsonpCache = jsonpCache;
46038         function jsonpRequest(url, callback) {
46039           var request = {
46040             abort: function abort() {}
46041           };
46042
46043           if (window.JSONP_FIX) {
46044             if (window.JSONP_DELAY === 0) {
46045               callback(window.JSONP_FIX);
46046             } else {
46047               var t = window.setTimeout(function () {
46048                 callback(window.JSONP_FIX);
46049               }, window.JSONP_DELAY || 0);
46050
46051               request.abort = function () {
46052                 window.clearTimeout(t);
46053               };
46054             }
46055
46056             return request;
46057           }
46058
46059           function rand() {
46060             var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
46061             var c = '';
46062             var i = -1;
46063
46064             while (++i < 15) {
46065               c += chars.charAt(Math.floor(Math.random() * 52));
46066             }
46067
46068             return c;
46069           }
46070
46071           function create(url) {
46072             var e = url.match(/callback=(\w+)/);
46073             var c = e ? e[1] : rand();
46074
46075             jsonpCache[c] = function (data) {
46076               if (jsonpCache[c]) {
46077                 callback(data);
46078               }
46079
46080               finalize();
46081             };
46082
46083             function finalize() {
46084               delete jsonpCache[c];
46085               script.remove();
46086             }
46087
46088             request.abort = finalize;
46089             return 'jsonpCache.' + c;
46090           }
46091
46092           var cb = create(url);
46093           var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
46094           return request;
46095         }
46096
46097         var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
46098         var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
46099         var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
46100         var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
46101         var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
46102         var maxResults$2 = 2000;
46103         var tileZoom$2 = 16.5;
46104         var tiler$6 = utilTiler().zoomExtent([tileZoom$2, tileZoom$2]).skipNullIsland(true);
46105         var dispatch$7 = dispatch('loadedImages', 'viewerChanged');
46106         var minHfov = 10; // zoom in degrees:  20, 10, 5
46107
46108         var maxHfov = 90; // zoom out degrees
46109
46110         var defaultHfov = 45;
46111         var _hires = false;
46112         var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
46113
46114         var _currScene = 0;
46115
46116         var _ssCache;
46117
46118         var _pannellumViewer;
46119
46120         var _sceneOptions = {
46121           showFullscreenCtrl: false,
46122           autoLoad: true,
46123           compass: true,
46124           yaw: 0,
46125           minHfov: minHfov,
46126           maxHfov: maxHfov,
46127           hfov: defaultHfov,
46128           type: 'cubemap',
46129           cubeMap: []
46130         };
46131
46132         var _loadViewerPromise$2;
46133         /**
46134          * abortRequest().
46135          */
46136
46137
46138         function abortRequest$6(i) {
46139           i.abort();
46140         }
46141         /**
46142          * localeTimeStamp().
46143          */
46144
46145
46146         function localeTimestamp(s) {
46147           if (!s) return null;
46148           var options = {
46149             day: 'numeric',
46150             month: 'short',
46151             year: 'numeric'
46152           };
46153           var d = new Date(s);
46154           if (isNaN(d.getTime())) return null;
46155           return d.toLocaleString(_mainLocalizer.localeCode(), options);
46156         }
46157         /**
46158          * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
46159          */
46160
46161
46162         function loadTiles$2(which, url, projection, margin) {
46163           var tiles = tiler$6.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
46164
46165           var cache = _ssCache[which];
46166           Object.keys(cache.inflight).forEach(function (k) {
46167             var wanted = tiles.find(function (tile) {
46168               return k.indexOf(tile.id + ',') === 0;
46169             });
46170
46171             if (!wanted) {
46172               abortRequest$6(cache.inflight[k]);
46173               delete cache.inflight[k];
46174             }
46175           });
46176           tiles.forEach(function (tile) {
46177             return loadNextTilePage$2(which, url, tile);
46178           });
46179         }
46180         /**
46181          * loadNextTilePage() load data for the next tile page in line.
46182          */
46183
46184
46185         function loadNextTilePage$2(which, url, tile) {
46186           var cache = _ssCache[which];
46187           var nextPage = cache.nextPage[tile.id] || 0;
46188           var id = tile.id + ',' + String(nextPage);
46189           if (cache.loaded[id] || cache.inflight[id]) return;
46190           cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
46191             cache.loaded[id] = true;
46192             delete cache.inflight[id];
46193             if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
46194
46195             bubbles.shift();
46196             var features = bubbles.map(function (bubble) {
46197               if (cache.points[bubble.id]) return null; // skip duplicates
46198
46199               var loc = [bubble.lo, bubble.la];
46200               var d = {
46201                 loc: loc,
46202                 key: bubble.id,
46203                 ca: bubble.he,
46204                 captured_at: bubble.cd,
46205                 captured_by: 'microsoft',
46206                 // nbn: bubble.nbn,
46207                 // pbn: bubble.pbn,
46208                 // ad: bubble.ad,
46209                 // rn: bubble.rn,
46210                 pr: bubble.pr,
46211                 // previous
46212                 ne: bubble.ne,
46213                 // next
46214                 pano: true,
46215                 sequenceKey: null
46216               };
46217               cache.points[bubble.id] = d; // a sequence starts here
46218
46219               if (bubble.pr === undefined) {
46220                 cache.leaders.push(bubble.id);
46221               }
46222
46223               return {
46224                 minX: loc[0],
46225                 minY: loc[1],
46226                 maxX: loc[0],
46227                 maxY: loc[1],
46228                 data: d
46229               };
46230             }).filter(Boolean);
46231             cache.rtree.load(features);
46232             connectSequences();
46233
46234             if (which === 'bubbles') {
46235               dispatch$7.call('loadedImages');
46236             }
46237           });
46238         } // call this sometimes to connect the bubbles into sequences
46239
46240
46241         function connectSequences() {
46242           var cache = _ssCache.bubbles;
46243           var keepLeaders = [];
46244
46245           for (var i = 0; i < cache.leaders.length; i++) {
46246             var bubble = cache.points[cache.leaders[i]];
46247             var seen = {}; // try to make a sequence.. use the key of the leader bubble.
46248
46249             var sequence = {
46250               key: bubble.key,
46251               bubbles: []
46252             };
46253             var complete = false;
46254
46255             do {
46256               sequence.bubbles.push(bubble);
46257               seen[bubble.key] = true;
46258
46259               if (bubble.ne === undefined) {
46260                 complete = true;
46261               } else {
46262                 bubble = cache.points[bubble.ne]; // advance to next
46263               }
46264             } while (bubble && !seen[bubble.key] && !complete);
46265
46266             if (complete) {
46267               _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
46268
46269               for (var j = 0; j < sequence.bubbles.length; j++) {
46270                 sequence.bubbles[j].sequenceKey = sequence.key;
46271               } // create a GeoJSON LineString
46272
46273
46274               sequence.geojson = {
46275                 type: 'LineString',
46276                 properties: {
46277                   captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
46278                   captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
46279                   key: sequence.key
46280                 },
46281                 coordinates: sequence.bubbles.map(function (d) {
46282                   return d.loc;
46283                 })
46284               };
46285             } else {
46286               keepLeaders.push(cache.leaders[i]);
46287             }
46288           } // couldn't complete these, save for later
46289
46290
46291           cache.leaders = keepLeaders;
46292         }
46293         /**
46294          * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
46295          */
46296
46297
46298         function getBubbles(url, tile, callback) {
46299           var rect = tile.extent.rectangle();
46300           var urlForRequest = url + utilQsString({
46301             n: rect[3],
46302             s: rect[1],
46303             e: rect[2],
46304             w: rect[0],
46305             c: maxResults$2,
46306             appkey: bubbleAppKey,
46307             jsCallback: '{callback}'
46308           });
46309           return jsonpRequest(urlForRequest, function (data) {
46310             if (!data || data.error) {
46311               callback(null);
46312             } else {
46313               callback(data);
46314             }
46315           });
46316         } // partition viewport into higher zoom tiles
46317
46318
46319         function partitionViewport$2(projection) {
46320           var z = geoScaleToZoom(projection.scale());
46321           var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
46322
46323           var tiler = utilTiler().zoomExtent([z2, z2]);
46324           return tiler.getTiles(projection).map(function (tile) {
46325             return tile.extent;
46326           });
46327         } // no more than `limit` results per partition.
46328
46329
46330         function searchLimited$2(limit, projection, rtree) {
46331           limit = limit || 5;
46332           return partitionViewport$2(projection).reduce(function (result, extent) {
46333             var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
46334               return d.data;
46335             });
46336             return found.length ? result.concat(found) : result;
46337           }, []);
46338         }
46339         /**
46340          * loadImage()
46341          */
46342
46343
46344         function loadImage(imgInfo) {
46345           return new Promise(function (resolve) {
46346             var img = new Image();
46347
46348             img.onload = function () {
46349               var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
46350               var ctx = canvas.getContext('2d');
46351               ctx.drawImage(img, imgInfo.x, imgInfo.y);
46352               resolve({
46353                 imgInfo: imgInfo,
46354                 status: 'ok'
46355               });
46356             };
46357
46358             img.onerror = function () {
46359               resolve({
46360                 data: imgInfo,
46361                 status: 'error'
46362               });
46363             };
46364
46365             img.setAttribute('crossorigin', '');
46366             img.src = imgInfo.url;
46367           });
46368         }
46369         /**
46370          * loadCanvas()
46371          */
46372
46373
46374         function loadCanvas(imageGroup) {
46375           return Promise.all(imageGroup.map(loadImage)).then(function (data) {
46376             var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
46377             var which = {
46378               '01': 0,
46379               '02': 1,
46380               '03': 2,
46381               '10': 3,
46382               '11': 4,
46383               '12': 5
46384             };
46385             var face = data[0].imgInfo.face;
46386             _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
46387             return {
46388               status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
46389             };
46390           });
46391         }
46392         /**
46393          * loadFaces()
46394          */
46395
46396
46397         function loadFaces(faceGroup) {
46398           return Promise.all(faceGroup.map(loadCanvas)).then(function () {
46399             return {
46400               status: 'loadFaces done'
46401             };
46402           });
46403         }
46404
46405         function setupCanvas(selection, reset) {
46406           if (reset) {
46407             selection.selectAll('#ideditor-stitcher-canvases').remove();
46408           } // Add the Streetside working canvases. These are used for 'stitching', or combining,
46409           // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
46410
46411
46412           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) {
46413             return 'ideditor-' + d;
46414           }).attr('width', _resolution).attr('height', _resolution);
46415         }
46416
46417         function qkToXY(qk) {
46418           var x = 0;
46419           var y = 0;
46420           var scale = 256;
46421
46422           for (var i = qk.length; i > 0; i--) {
46423             var key = qk[i - 1];
46424             x += +(key === '1' || key === '3') * scale;
46425             y += +(key === '2' || key === '3') * scale;
46426             scale *= 2;
46427           }
46428
46429           return [x, y];
46430         }
46431
46432         function getQuadKeys() {
46433           var dim = _resolution / 256;
46434           var quadKeys;
46435
46436           if (dim === 16) {
46437             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'];
46438           } else if (dim === 8) {
46439             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'];
46440           } else if (dim === 4) {
46441             quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
46442           } else {
46443             // dim === 2
46444             quadKeys = ['0', '1', '2', '3'];
46445           }
46446
46447           return quadKeys;
46448         }
46449
46450         var serviceStreetside = {
46451           /**
46452            * init() initialize streetside.
46453            */
46454           init: function init() {
46455             if (!_ssCache) {
46456               this.reset();
46457             }
46458
46459             this.event = utilRebind(this, dispatch$7, 'on');
46460           },
46461
46462           /**
46463            * reset() reset the cache.
46464            */
46465           reset: function reset() {
46466             if (_ssCache) {
46467               Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$6);
46468             }
46469
46470             _ssCache = {
46471               bubbles: {
46472                 inflight: {},
46473                 loaded: {},
46474                 nextPage: {},
46475                 rtree: new RBush(),
46476                 points: {},
46477                 leaders: []
46478               },
46479               sequences: {}
46480             };
46481           },
46482
46483           /**
46484            * bubbles()
46485            */
46486           bubbles: function bubbles(projection) {
46487             var limit = 5;
46488             return searchLimited$2(limit, projection, _ssCache.bubbles.rtree);
46489           },
46490           cachedImage: function cachedImage(imageKey) {
46491             return _ssCache.bubbles.points[imageKey];
46492           },
46493           sequences: function sequences(projection) {
46494             var viewport = projection.clipExtent();
46495             var min = [viewport[0][0], viewport[1][1]];
46496             var max = [viewport[1][0], viewport[0][1]];
46497             var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
46498             var seen = {};
46499             var results = []; // all sequences for bubbles in viewport
46500
46501             _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
46502               var key = d.data.sequenceKey;
46503
46504               if (key && !seen[key]) {
46505                 seen[key] = true;
46506                 results.push(_ssCache.sequences[key].geojson);
46507               }
46508             });
46509
46510             return results;
46511           },
46512
46513           /**
46514            * loadBubbles()
46515            */
46516           loadBubbles: function loadBubbles(projection, margin) {
46517             // by default: request 2 nearby tiles so we can connect sequences.
46518             if (margin === undefined) margin = 2;
46519             loadTiles$2('bubbles', bubbleApi, projection, margin);
46520           },
46521           viewer: function viewer() {
46522             return _pannellumViewer;
46523           },
46524           initViewer: function initViewer() {
46525             if (!window.pannellum) return;
46526             if (_pannellumViewer) return;
46527             _currScene += 1;
46528
46529             var sceneID = _currScene.toString();
46530
46531             var options = {
46532               'default': {
46533                 firstScene: sceneID
46534               },
46535               scenes: {}
46536             };
46537             options.scenes[sceneID] = _sceneOptions;
46538             _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
46539           },
46540           ensureViewerLoaded: function ensureViewerLoaded(context) {
46541             if (_loadViewerPromise$2) return _loadViewerPromise$2; // create ms-wrapper, a photo wrapper class
46542
46543             var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
46544             // (used by all to house each custom photo viewer)
46545
46546             var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
46547             var that = this;
46548             var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
46549
46550             wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
46551               select(window).on(pointerPrefix + 'move.streetside', function () {
46552                 dispatch$7.call('viewerChanged');
46553               }, true);
46554             }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
46555               select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
46556
46557               var t = timer(function (elapsed) {
46558                 dispatch$7.call('viewerChanged');
46559
46560                 if (elapsed > 2000) {
46561                   t.stop();
46562                 }
46563               });
46564             }).append('div').attr('class', 'photo-attribution fillD');
46565             var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
46566             controlsEnter.append('button').on('click.back', step(-1)).html('◄');
46567             controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
46568
46569             wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
46570
46571             context.ui().photoviewer.on('resize.streetside', function () {
46572               if (_pannellumViewer) {
46573                 _pannellumViewer.resize();
46574               }
46575             });
46576             _loadViewerPromise$2 = new Promise(function (resolve, reject) {
46577               var loadedCount = 0;
46578
46579               function loaded() {
46580                 loadedCount += 1; // wait until both files are loaded
46581
46582                 if (loadedCount === 2) resolve();
46583               }
46584
46585               var head = select('head'); // load streetside pannellum viewer css
46586
46587               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 () {
46588                 reject();
46589               }); // load streetside pannellum viewer js
46590
46591               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 () {
46592                 reject();
46593               });
46594             })["catch"](function () {
46595               _loadViewerPromise$2 = null;
46596             });
46597             return _loadViewerPromise$2;
46598
46599             function step(stepBy) {
46600               return function () {
46601                 var viewer = context.container().select('.photoviewer');
46602                 var selected = viewer.empty() ? undefined : viewer.datum();
46603                 if (!selected) return;
46604                 var nextID = stepBy === 1 ? selected.ne : selected.pr;
46605
46606                 var yaw = _pannellumViewer.getYaw();
46607
46608                 var ca = selected.ca + yaw;
46609                 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
46610
46611                 var meters = 35;
46612                 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
46613                 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46614                 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
46615                 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
46616                 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
46617
46618                 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
46619                 poly = geoRotate(poly, -angle, origin);
46620                 var extent = poly.reduce(function (extent, point) {
46621                   return extent.extend(geoExtent(point));
46622                 }, geoExtent()); // find nearest other bubble in the search polygon
46623
46624                 var minDist = Infinity;
46625
46626                 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
46627                   if (d.data.key === selected.key) return;
46628                   if (!geoPointInPolygon(d.data.loc, poly)) return;
46629                   var dist = geoVecLength(d.data.loc, selected.loc);
46630                   var theta = selected.ca - d.data.ca;
46631                   var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
46632
46633                   if (minTheta > 20) {
46634                     dist += 5; // penalize distance if camera angles don't match
46635                   }
46636
46637                   if (dist < minDist) {
46638                     nextID = d.data.key;
46639                     minDist = dist;
46640                   }
46641                 });
46642
46643                 var nextBubble = nextID && that.cachedImage(nextID);
46644                 if (!nextBubble) return;
46645                 context.map().centerEase(nextBubble.loc);
46646                 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
46647               };
46648             }
46649           },
46650           yaw: function yaw(_yaw) {
46651             if (typeof _yaw !== 'number') return _yaw;
46652             _sceneOptions.yaw = _yaw;
46653             return this;
46654           },
46655
46656           /**
46657            * showViewer()
46658            */
46659           showViewer: function showViewer(context) {
46660             var wrap = context.container().select('.photoviewer').classed('hide', false);
46661             var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
46662
46663             if (isHidden) {
46664               wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
46665               wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
46666             }
46667
46668             return this;
46669           },
46670
46671           /**
46672            * hideViewer()
46673            */
46674           hideViewer: function hideViewer(context) {
46675             var viewer = context.container().select('.photoviewer');
46676             if (!viewer.empty()) viewer.datum(null);
46677             viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
46678             context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
46679             this.updateUrlImage(null);
46680             return this.setStyles(context, null, true);
46681           },
46682
46683           /**
46684            * selectImage().
46685            */
46686           selectImage: function selectImage(context, key) {
46687             var that = this;
46688             var d = this.cachedImage(key);
46689             var viewer = context.container().select('.photoviewer');
46690             if (!viewer.empty()) viewer.datum(d);
46691             this.setStyles(context, null, true);
46692             var wrap = context.container().select('.photoviewer .ms-wrapper');
46693             var attribution = wrap.selectAll('.photo-attribution').html('');
46694             wrap.selectAll('.pnlm-load-box') // display "loading.."
46695             .style('display', 'block');
46696             if (!d) return this;
46697             this.updateUrlImage(key);
46698             _sceneOptions.northOffset = d.ca;
46699             var line1 = attribution.append('div').attr('class', 'attribution-row');
46700             var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
46701
46702             var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
46703             label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
46704               d3_event.stopPropagation();
46705               _hires = !_hires;
46706               _resolution = _hires ? 1024 : 512;
46707               wrap.call(setupCanvas, true);
46708               var viewstate = {
46709                 yaw: _pannellumViewer.getYaw(),
46710                 pitch: _pannellumViewer.getPitch(),
46711                 hfov: _pannellumViewer.getHfov()
46712               };
46713               _sceneOptions = Object.assign(_sceneOptions, viewstate);
46714               that.selectImage(context, d.key).showViewer(context);
46715             });
46716             label.append('span').html(_t.html('streetside.hires'));
46717             var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
46718
46719             if (d.captured_by) {
46720               var yyyy = new Date().getFullYear();
46721               captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
46722               captureInfo.append('span').html('|');
46723             }
46724
46725             if (d.captured_at) {
46726               captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
46727             } // Add image links
46728
46729
46730             var line2 = attribution.append('div').attr('class', 'attribution-row');
46731             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'));
46732             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'));
46733             var bubbleIdQuadKey = d.key.toString(4);
46734             var paddingNeeded = 16 - bubbleIdQuadKey.length;
46735
46736             for (var i = 0; i < paddingNeeded; i++) {
46737               bubbleIdQuadKey = '0' + bubbleIdQuadKey;
46738             }
46739
46740             var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
46741             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
46742
46743             var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
46744
46745             var quadKeys = getQuadKeys();
46746             var faces = faceKeys.map(function (faceKey) {
46747               return quadKeys.map(function (quadKey) {
46748                 var xy = qkToXY(quadKey);
46749                 return {
46750                   face: faceKey,
46751                   url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
46752                   x: xy[0],
46753                   y: xy[1]
46754                 };
46755               });
46756             });
46757             loadFaces(faces).then(function () {
46758               if (!_pannellumViewer) {
46759                 that.initViewer();
46760               } else {
46761                 // make a new scene
46762                 _currScene += 1;
46763
46764                 var sceneID = _currScene.toString();
46765
46766                 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
46767
46768
46769                 if (_currScene > 2) {
46770                   sceneID = (_currScene - 1).toString();
46771
46772                   _pannellumViewer.removeScene(sceneID);
46773                 }
46774               }
46775             });
46776             return this;
46777           },
46778           getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
46779             return d && d.sequenceKey;
46780           },
46781           // Updates the currently highlighted sequence and selected bubble.
46782           // Reset is only necessary when interacting with the viewport because
46783           // this implicitly changes the currently selected bubble/sequence
46784           setStyles: function setStyles(context, hovered, reset) {
46785             if (reset) {
46786               // reset all layers
46787               context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
46788               context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
46789             }
46790
46791             var hoveredBubbleKey = hovered && hovered.key;
46792             var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
46793             var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
46794             var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
46795               return d.key;
46796             }) || [];
46797             var viewer = context.container().select('.photoviewer');
46798             var selected = viewer.empty() ? undefined : viewer.datum();
46799             var selectedBubbleKey = selected && selected.key;
46800             var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
46801             var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
46802             var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
46803               return d.key;
46804             }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
46805
46806             var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
46807             context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
46808               return highlightedBubbleKeys.indexOf(d.key) !== -1;
46809             }).classed('hovered', function (d) {
46810               return d.key === hoveredBubbleKey;
46811             }).classed('currentView', function (d) {
46812               return d.key === selectedBubbleKey;
46813             });
46814             context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
46815               return d.properties.key === hoveredSequenceKey;
46816             }).classed('currentView', function (d) {
46817               return d.properties.key === selectedSequenceKey;
46818             }); // update viewfields if needed
46819
46820             context.container().selectAll('.viewfield-group .viewfield').attr('d', viewfieldPath);
46821
46822             function viewfieldPath() {
46823               var d = this.parentNode.__data__;
46824
46825               if (d.pano && d.key !== selectedBubbleKey) {
46826                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
46827               } else {
46828                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
46829               }
46830             }
46831
46832             return this;
46833           },
46834           updateUrlImage: function updateUrlImage(imageKey) {
46835             if (!window.mocha) {
46836               var hash = utilStringQs(window.location.hash);
46837
46838               if (imageKey) {
46839                 hash.photo = 'streetside/' + imageKey;
46840               } else {
46841                 delete hash.photo;
46842               }
46843
46844               window.location.replace('#' + utilQsString(hash, true));
46845             }
46846           },
46847
46848           /**
46849            * cache().
46850            */
46851           cache: function cache() {
46852             return _ssCache;
46853           }
46854         };
46855
46856         var _apibase$1 = 'https://taginfo.openstreetmap.org/api/4/';
46857         var _inflight$2 = {};
46858         var _popularKeys = {};
46859         var _taginfoCache = {};
46860         var tag_sorts = {
46861           point: 'count_nodes',
46862           vertex: 'count_nodes',
46863           area: 'count_ways',
46864           line: 'count_ways'
46865         };
46866         var tag_sort_members = {
46867           point: 'count_node_members',
46868           vertex: 'count_node_members',
46869           area: 'count_way_members',
46870           line: 'count_way_members',
46871           relation: 'count_relation_members'
46872         };
46873         var tag_filters = {
46874           point: 'nodes',
46875           vertex: 'nodes',
46876           area: 'ways',
46877           line: 'ways'
46878         };
46879         var tag_members_fractions = {
46880           point: 'count_node_members_fraction',
46881           vertex: 'count_node_members_fraction',
46882           area: 'count_way_members_fraction',
46883           line: 'count_way_members_fraction',
46884           relation: 'count_relation_members_fraction'
46885         };
46886
46887         function sets(params, n, o) {
46888           if (params.geometry && o[params.geometry]) {
46889             params[n] = o[params.geometry];
46890           }
46891
46892           return params;
46893         }
46894
46895         function setFilter(params) {
46896           return sets(params, 'filter', tag_filters);
46897         }
46898
46899         function setSort(params) {
46900           return sets(params, 'sortname', tag_sorts);
46901         }
46902
46903         function setSortMembers(params) {
46904           return sets(params, 'sortname', tag_sort_members);
46905         }
46906
46907         function clean(params) {
46908           return utilObjectOmit(params, ['geometry', 'debounce']);
46909         }
46910
46911         function filterKeys(type) {
46912           var count_type = type ? 'count_' + type : 'count_all';
46913           return function (d) {
46914             return parseFloat(d[count_type]) > 2500 || d.in_wiki;
46915           };
46916         }
46917
46918         function filterMultikeys(prefix) {
46919           return function (d) {
46920             // d.key begins with prefix, and d.key contains no additional ':'s
46921             var re = new RegExp('^' + prefix + '(.*)$');
46922             var matches = d.key.match(re) || [];
46923             return matches.length === 2 && matches[1].indexOf(':') === -1;
46924           };
46925         }
46926
46927         function filterValues(allowUpperCase) {
46928           return function (d) {
46929             if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
46930
46931             if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
46932
46933             return parseFloat(d.fraction) > 0.0;
46934           };
46935         }
46936
46937         function filterRoles(geometry) {
46938           return function (d) {
46939             if (d.role === '') return false; // exclude empty role
46940
46941             if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
46942
46943             return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
46944           };
46945         }
46946
46947         function valKey(d) {
46948           return {
46949             value: d.key,
46950             title: d.key
46951           };
46952         }
46953
46954         function valKeyDescription(d) {
46955           var obj = {
46956             value: d.value,
46957             title: d.description || d.value
46958           };
46959
46960           if (d.count) {
46961             obj.count = d.count;
46962           }
46963
46964           return obj;
46965         }
46966
46967         function roleKey(d) {
46968           return {
46969             value: d.role,
46970             title: d.role
46971           };
46972         } // sort keys with ':' lower than keys without ':'
46973
46974
46975         function sortKeys(a, b) {
46976           return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
46977         }
46978
46979         var debouncedRequest$1 = debounce(request$1, 300, {
46980           leading: false
46981         });
46982
46983         function request$1(url, params, exactMatch, callback, loaded) {
46984           if (_inflight$2[url]) return;
46985           if (checkCache(url, params, exactMatch, callback)) return;
46986           var controller = new AbortController();
46987           _inflight$2[url] = controller;
46988           d3_json(url, {
46989             signal: controller.signal
46990           }).then(function (result) {
46991             delete _inflight$2[url];
46992             if (loaded) loaded(null, result);
46993           })["catch"](function (err) {
46994             delete _inflight$2[url];
46995             if (err.name === 'AbortError') return;
46996             if (loaded) loaded(err.message);
46997           });
46998         }
46999
47000         function checkCache(url, params, exactMatch, callback) {
47001           var rp = params.rp || 25;
47002           var testQuery = params.query || '';
47003           var testUrl = url;
47004
47005           do {
47006             var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
47007
47008             if (hit && (url === testUrl || hit.length < rp)) {
47009               callback(null, hit);
47010               return true;
47011             } // don't try to shorten the query
47012
47013
47014             if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
47015             // that has returned fewer than max results (rp)
47016
47017             testQuery = testQuery.slice(0, -1);
47018             testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
47019           } while (testQuery.length >= 0);
47020
47021           return false;
47022         }
47023
47024         var serviceTaginfo = {
47025           init: function init() {
47026             _inflight$2 = {};
47027             _taginfoCache = {};
47028             _popularKeys = {
47029               // manually exclude some keys – #5377, #7485
47030               postal_code: true,
47031               full_name: true,
47032               loc_name: true,
47033               reg_name: true,
47034               short_name: true,
47035               sorting_name: true,
47036               artist_name: true,
47037               nat_name: true,
47038               long_name: true,
47039               'bridge:name': true
47040             }; // Fetch popular keys.  We'll exclude these from `values`
47041             // lookups because they stress taginfo, and they aren't likely
47042             // to yield meaningful autocomplete results.. see #3955
47043
47044             var params = {
47045               rp: 100,
47046               sortname: 'values_all',
47047               sortorder: 'desc',
47048               page: 1,
47049               debounce: false,
47050               lang: _mainLocalizer.languageCode()
47051             };
47052             this.keys(params, function (err, data) {
47053               if (err) return;
47054               data.forEach(function (d) {
47055                 if (d.value === 'opening_hours') return; // exception
47056
47057                 _popularKeys[d.value] = true;
47058               });
47059             });
47060           },
47061           reset: function reset() {
47062             Object.values(_inflight$2).forEach(function (controller) {
47063               controller.abort();
47064             });
47065             _inflight$2 = {};
47066           },
47067           keys: function keys(params, callback) {
47068             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47069             params = clean(setSort(params));
47070             params = Object.assign({
47071               rp: 10,
47072               sortname: 'count_all',
47073               sortorder: 'desc',
47074               page: 1,
47075               lang: _mainLocalizer.languageCode()
47076             }, params);
47077             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
47078             doRequest(url, params, false, callback, function (err, d) {
47079               if (err) {
47080                 callback(err);
47081               } else {
47082                 var f = filterKeys(params.filter);
47083                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
47084                 _taginfoCache[url] = result;
47085                 callback(null, result);
47086               }
47087             });
47088           },
47089           multikeys: function multikeys(params, callback) {
47090             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47091             params = clean(setSort(params));
47092             params = Object.assign({
47093               rp: 25,
47094               sortname: 'count_all',
47095               sortorder: 'desc',
47096               page: 1,
47097               lang: _mainLocalizer.languageCode()
47098             }, params);
47099             var prefix = params.query;
47100             var url = _apibase$1 + 'keys/all?' + utilQsString(params);
47101             doRequest(url, params, true, callback, function (err, d) {
47102               if (err) {
47103                 callback(err);
47104               } else {
47105                 var f = filterMultikeys(prefix);
47106                 var result = d.data.filter(f).map(valKey);
47107                 _taginfoCache[url] = result;
47108                 callback(null, result);
47109               }
47110             });
47111           },
47112           values: function values(params, callback) {
47113             // Exclude popular keys from values lookups.. see #3955
47114             var key = params.key;
47115
47116             if (key && _popularKeys[key]) {
47117               callback(null, []);
47118               return;
47119             }
47120
47121             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47122             params = clean(setSort(setFilter(params)));
47123             params = Object.assign({
47124               rp: 25,
47125               sortname: 'count_all',
47126               sortorder: 'desc',
47127               page: 1,
47128               lang: _mainLocalizer.languageCode()
47129             }, params);
47130             var url = _apibase$1 + 'key/values?' + utilQsString(params);
47131             doRequest(url, params, false, callback, function (err, d) {
47132               if (err) {
47133                 callback(err);
47134               } else {
47135                 // In most cases we prefer taginfo value results with lowercase letters.
47136                 // A few OSM keys expect values to contain uppercase values (see #3377).
47137                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
47138                 // but these are the fields where taginfo value lookup is most useful.
47139                 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
47140                 var allowUpperCase = re.test(params.key);
47141                 var f = filterValues(allowUpperCase);
47142                 var result = d.data.filter(f).map(valKeyDescription);
47143                 _taginfoCache[url] = result;
47144                 callback(null, result);
47145               }
47146             });
47147           },
47148           roles: function roles(params, callback) {
47149             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47150             var geometry = params.geometry;
47151             params = clean(setSortMembers(params));
47152             params = Object.assign({
47153               rp: 25,
47154               sortname: 'count_all_members',
47155               sortorder: 'desc',
47156               page: 1,
47157               lang: _mainLocalizer.languageCode()
47158             }, params);
47159             var url = _apibase$1 + 'relation/roles?' + utilQsString(params);
47160             doRequest(url, params, true, callback, function (err, d) {
47161               if (err) {
47162                 callback(err);
47163               } else {
47164                 var f = filterRoles(geometry);
47165                 var result = d.data.filter(f).map(roleKey);
47166                 _taginfoCache[url] = result;
47167                 callback(null, result);
47168               }
47169             });
47170           },
47171           docs: function docs(params, callback) {
47172             var doRequest = params.debounce ? debouncedRequest$1 : request$1;
47173             params = clean(setSort(params));
47174             var path = 'key/wiki_pages?';
47175
47176             if (params.value) {
47177               path = 'tag/wiki_pages?';
47178             } else if (params.rtype) {
47179               path = 'relation/wiki_pages?';
47180             }
47181
47182             var url = _apibase$1 + path + utilQsString(params);
47183             doRequest(url, params, true, callback, function (err, d) {
47184               if (err) {
47185                 callback(err);
47186               } else {
47187                 _taginfoCache[url] = d.data;
47188                 callback(null, d.data);
47189               }
47190             });
47191           },
47192           apibase: function apibase(_) {
47193             if (!arguments.length) return _apibase$1;
47194             _apibase$1 = _;
47195             return this;
47196           }
47197         };
47198
47199         var helpers$1 = createCommonjsModule(function (module, exports) {
47200
47201           Object.defineProperty(exports, "__esModule", {
47202             value: true
47203           });
47204           /**
47205            * @module helpers
47206            */
47207
47208           /**
47209            * Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth.
47210            *
47211            * @memberof helpers
47212            * @type {number}
47213            */
47214
47215           exports.earthRadius = 6371008.8;
47216           /**
47217            * Unit of measurement factors using a spherical (non-ellipsoid) earth radius.
47218            *
47219            * @memberof helpers
47220            * @type {Object}
47221            */
47222
47223           exports.factors = {
47224             centimeters: exports.earthRadius * 100,
47225             centimetres: exports.earthRadius * 100,
47226             degrees: exports.earthRadius / 111325,
47227             feet: exports.earthRadius * 3.28084,
47228             inches: exports.earthRadius * 39.370,
47229             kilometers: exports.earthRadius / 1000,
47230             kilometres: exports.earthRadius / 1000,
47231             meters: exports.earthRadius,
47232             metres: exports.earthRadius,
47233             miles: exports.earthRadius / 1609.344,
47234             millimeters: exports.earthRadius * 1000,
47235             millimetres: exports.earthRadius * 1000,
47236             nauticalmiles: exports.earthRadius / 1852,
47237             radians: 1,
47238             yards: exports.earthRadius / 1.0936
47239           };
47240           /**
47241            * Units of measurement factors based on 1 meter.
47242            *
47243            * @memberof helpers
47244            * @type {Object}
47245            */
47246
47247           exports.unitsFactors = {
47248             centimeters: 100,
47249             centimetres: 100,
47250             degrees: 1 / 111325,
47251             feet: 3.28084,
47252             inches: 39.370,
47253             kilometers: 1 / 1000,
47254             kilometres: 1 / 1000,
47255             meters: 1,
47256             metres: 1,
47257             miles: 1 / 1609.344,
47258             millimeters: 1000,
47259             millimetres: 1000,
47260             nauticalmiles: 1 / 1852,
47261             radians: 1 / exports.earthRadius,
47262             yards: 1 / 1.0936
47263           };
47264           /**
47265            * Area of measurement factors based on 1 square meter.
47266            *
47267            * @memberof helpers
47268            * @type {Object}
47269            */
47270
47271           exports.areaFactors = {
47272             acres: 0.000247105,
47273             centimeters: 10000,
47274             centimetres: 10000,
47275             feet: 10.763910417,
47276             inches: 1550.003100006,
47277             kilometers: 0.000001,
47278             kilometres: 0.000001,
47279             meters: 1,
47280             metres: 1,
47281             miles: 3.86e-7,
47282             millimeters: 1000000,
47283             millimetres: 1000000,
47284             yards: 1.195990046
47285           };
47286           /**
47287            * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
47288            *
47289            * @name feature
47290            * @param {Geometry} geometry input geometry
47291            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47292            * @param {Object} [options={}] Optional Parameters
47293            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47294            * @param {string|number} [options.id] Identifier associated with the Feature
47295            * @returns {Feature} a GeoJSON Feature
47296            * @example
47297            * var geometry = {
47298            *   "type": "Point",
47299            *   "coordinates": [110, 50]
47300            * };
47301            *
47302            * var feature = turf.feature(geometry);
47303            *
47304            * //=feature
47305            */
47306
47307           function feature(geom, properties, options) {
47308             if (options === void 0) {
47309               options = {};
47310             }
47311
47312             var feat = {
47313               type: "Feature"
47314             };
47315
47316             if (options.id === 0 || options.id) {
47317               feat.id = options.id;
47318             }
47319
47320             if (options.bbox) {
47321               feat.bbox = options.bbox;
47322             }
47323
47324             feat.properties = properties || {};
47325             feat.geometry = geom;
47326             return feat;
47327           }
47328
47329           exports.feature = feature;
47330           /**
47331            * Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates.
47332            * For GeometryCollection type use `helpers.geometryCollection`
47333            *
47334            * @name geometry
47335            * @param {string} type Geometry Type
47336            * @param {Array<any>} coordinates Coordinates
47337            * @param {Object} [options={}] Optional Parameters
47338            * @returns {Geometry} a GeoJSON Geometry
47339            * @example
47340            * var type = "Point";
47341            * var coordinates = [110, 50];
47342            * var geometry = turf.geometry(type, coordinates);
47343            * // => geometry
47344            */
47345
47346           function geometry(type, coordinates, options) {
47347
47348             switch (type) {
47349               case "Point":
47350                 return point(coordinates).geometry;
47351
47352               case "LineString":
47353                 return lineString(coordinates).geometry;
47354
47355               case "Polygon":
47356                 return polygon(coordinates).geometry;
47357
47358               case "MultiPoint":
47359                 return multiPoint(coordinates).geometry;
47360
47361               case "MultiLineString":
47362                 return multiLineString(coordinates).geometry;
47363
47364               case "MultiPolygon":
47365                 return multiPolygon(coordinates).geometry;
47366
47367               default:
47368                 throw new Error(type + " is invalid");
47369             }
47370           }
47371
47372           exports.geometry = geometry;
47373           /**
47374            * Creates a {@link Point} {@link Feature} from a Position.
47375            *
47376            * @name point
47377            * @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees)
47378            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47379            * @param {Object} [options={}] Optional Parameters
47380            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47381            * @param {string|number} [options.id] Identifier associated with the Feature
47382            * @returns {Feature<Point>} a Point feature
47383            * @example
47384            * var point = turf.point([-75.343, 39.984]);
47385            *
47386            * //=point
47387            */
47388
47389           function point(coordinates, properties, options) {
47390             if (options === void 0) {
47391               options = {};
47392             }
47393
47394             var geom = {
47395               type: "Point",
47396               coordinates: coordinates
47397             };
47398             return feature(geom, properties, options);
47399           }
47400
47401           exports.point = point;
47402           /**
47403            * Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates.
47404            *
47405            * @name points
47406            * @param {Array<Array<number>>} coordinates an array of Points
47407            * @param {Object} [properties={}] Translate these properties to each Feature
47408            * @param {Object} [options={}] Optional Parameters
47409            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
47410            * associated with the FeatureCollection
47411            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47412            * @returns {FeatureCollection<Point>} Point Feature
47413            * @example
47414            * var points = turf.points([
47415            *   [-75, 39],
47416            *   [-80, 45],
47417            *   [-78, 50]
47418            * ]);
47419            *
47420            * //=points
47421            */
47422
47423           function points(coordinates, properties, options) {
47424             if (options === void 0) {
47425               options = {};
47426             }
47427
47428             return featureCollection(coordinates.map(function (coords) {
47429               return point(coords, properties);
47430             }), options);
47431           }
47432
47433           exports.points = points;
47434           /**
47435            * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
47436            *
47437            * @name polygon
47438            * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47439            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47440            * @param {Object} [options={}] Optional Parameters
47441            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47442            * @param {string|number} [options.id] Identifier associated with the Feature
47443            * @returns {Feature<Polygon>} Polygon Feature
47444            * @example
47445            * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
47446            *
47447            * //=polygon
47448            */
47449
47450           function polygon(coordinates, properties, options) {
47451             if (options === void 0) {
47452               options = {};
47453             }
47454
47455             for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
47456               var ring = coordinates_1[_i];
47457
47458               if (ring.length < 4) {
47459                 throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
47460               }
47461
47462               for (var j = 0; j < ring[ring.length - 1].length; j++) {
47463                 // Check if first point of Polygon contains two numbers
47464                 if (ring[ring.length - 1][j] !== ring[0][j]) {
47465                   throw new Error("First and last Position are not equivalent.");
47466                 }
47467               }
47468             }
47469
47470             var geom = {
47471               type: "Polygon",
47472               coordinates: coordinates
47473             };
47474             return feature(geom, properties, options);
47475           }
47476
47477           exports.polygon = polygon;
47478           /**
47479            * Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates.
47480            *
47481            * @name polygons
47482            * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates
47483            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47484            * @param {Object} [options={}] Optional Parameters
47485            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47486            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47487            * @returns {FeatureCollection<Polygon>} Polygon FeatureCollection
47488            * @example
47489            * var polygons = turf.polygons([
47490            *   [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]],
47491            *   [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]],
47492            * ]);
47493            *
47494            * //=polygons
47495            */
47496
47497           function polygons(coordinates, properties, options) {
47498             if (options === void 0) {
47499               options = {};
47500             }
47501
47502             return featureCollection(coordinates.map(function (coords) {
47503               return polygon(coords, properties);
47504             }), options);
47505           }
47506
47507           exports.polygons = polygons;
47508           /**
47509            * Creates a {@link LineString} {@link Feature} from an Array of Positions.
47510            *
47511            * @name lineString
47512            * @param {Array<Array<number>>} coordinates an array of Positions
47513            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47514            * @param {Object} [options={}] Optional Parameters
47515            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47516            * @param {string|number} [options.id] Identifier associated with the Feature
47517            * @returns {Feature<LineString>} LineString Feature
47518            * @example
47519            * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
47520            * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
47521            *
47522            * //=linestring1
47523            * //=linestring2
47524            */
47525
47526           function lineString(coordinates, properties, options) {
47527             if (options === void 0) {
47528               options = {};
47529             }
47530
47531             if (coordinates.length < 2) {
47532               throw new Error("coordinates must be an array of two or more positions");
47533             }
47534
47535             var geom = {
47536               type: "LineString",
47537               coordinates: coordinates
47538             };
47539             return feature(geom, properties, options);
47540           }
47541
47542           exports.lineString = lineString;
47543           /**
47544            * Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates.
47545            *
47546            * @name lineStrings
47547            * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
47548            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47549            * @param {Object} [options={}] Optional Parameters
47550            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north]
47551            * associated with the FeatureCollection
47552            * @param {string|number} [options.id] Identifier associated with the FeatureCollection
47553            * @returns {FeatureCollection<LineString>} LineString FeatureCollection
47554            * @example
47555            * var linestrings = turf.lineStrings([
47556            *   [[-24, 63], [-23, 60], [-25, 65], [-20, 69]],
47557            *   [[-14, 43], [-13, 40], [-15, 45], [-10, 49]]
47558            * ]);
47559            *
47560            * //=linestrings
47561            */
47562
47563           function lineStrings(coordinates, properties, options) {
47564             if (options === void 0) {
47565               options = {};
47566             }
47567
47568             return featureCollection(coordinates.map(function (coords) {
47569               return lineString(coords, properties);
47570             }), options);
47571           }
47572
47573           exports.lineStrings = lineStrings;
47574           /**
47575            * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}.
47576            *
47577            * @name featureCollection
47578            * @param {Feature[]} features input features
47579            * @param {Object} [options={}] Optional Parameters
47580            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47581            * @param {string|number} [options.id] Identifier associated with the Feature
47582            * @returns {FeatureCollection} FeatureCollection of Features
47583            * @example
47584            * var locationA = turf.point([-75.343, 39.984], {name: 'Location A'});
47585            * var locationB = turf.point([-75.833, 39.284], {name: 'Location B'});
47586            * var locationC = turf.point([-75.534, 39.123], {name: 'Location C'});
47587            *
47588            * var collection = turf.featureCollection([
47589            *   locationA,
47590            *   locationB,
47591            *   locationC
47592            * ]);
47593            *
47594            * //=collection
47595            */
47596
47597           function featureCollection(features, options) {
47598             if (options === void 0) {
47599               options = {};
47600             }
47601
47602             var fc = {
47603               type: "FeatureCollection"
47604             };
47605
47606             if (options.id) {
47607               fc.id = options.id;
47608             }
47609
47610             if (options.bbox) {
47611               fc.bbox = options.bbox;
47612             }
47613
47614             fc.features = features;
47615             return fc;
47616           }
47617
47618           exports.featureCollection = featureCollection;
47619           /**
47620            * Creates a {@link Feature<MultiLineString>} based on a
47621            * coordinate array. Properties can be added optionally.
47622            *
47623            * @name multiLineString
47624            * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
47625            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47626            * @param {Object} [options={}] Optional Parameters
47627            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47628            * @param {string|number} [options.id] Identifier associated with the Feature
47629            * @returns {Feature<MultiLineString>} a MultiLineString feature
47630            * @throws {Error} if no coordinates are passed
47631            * @example
47632            * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
47633            *
47634            * //=multiLine
47635            */
47636
47637           function multiLineString(coordinates, properties, options) {
47638             if (options === void 0) {
47639               options = {};
47640             }
47641
47642             var geom = {
47643               type: "MultiLineString",
47644               coordinates: coordinates
47645             };
47646             return feature(geom, properties, options);
47647           }
47648
47649           exports.multiLineString = multiLineString;
47650           /**
47651            * Creates a {@link Feature<MultiPoint>} based on a
47652            * coordinate array. Properties can be added optionally.
47653            *
47654            * @name multiPoint
47655            * @param {Array<Array<number>>} coordinates an array of Positions
47656            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47657            * @param {Object} [options={}] Optional Parameters
47658            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47659            * @param {string|number} [options.id] Identifier associated with the Feature
47660            * @returns {Feature<MultiPoint>} a MultiPoint feature
47661            * @throws {Error} if no coordinates are passed
47662            * @example
47663            * var multiPt = turf.multiPoint([[0,0],[10,10]]);
47664            *
47665            * //=multiPt
47666            */
47667
47668           function multiPoint(coordinates, properties, options) {
47669             if (options === void 0) {
47670               options = {};
47671             }
47672
47673             var geom = {
47674               type: "MultiPoint",
47675               coordinates: coordinates
47676             };
47677             return feature(geom, properties, options);
47678           }
47679
47680           exports.multiPoint = multiPoint;
47681           /**
47682            * Creates a {@link Feature<MultiPolygon>} based on a
47683            * coordinate array. Properties can be added optionally.
47684            *
47685            * @name multiPolygon
47686            * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
47687            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47688            * @param {Object} [options={}] Optional Parameters
47689            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47690            * @param {string|number} [options.id] Identifier associated with the Feature
47691            * @returns {Feature<MultiPolygon>} a multipolygon feature
47692            * @throws {Error} if no coordinates are passed
47693            * @example
47694            * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
47695            *
47696            * //=multiPoly
47697            *
47698            */
47699
47700           function multiPolygon(coordinates, properties, options) {
47701             if (options === void 0) {
47702               options = {};
47703             }
47704
47705             var geom = {
47706               type: "MultiPolygon",
47707               coordinates: coordinates
47708             };
47709             return feature(geom, properties, options);
47710           }
47711
47712           exports.multiPolygon = multiPolygon;
47713           /**
47714            * Creates a {@link Feature<GeometryCollection>} based on a
47715            * coordinate array. Properties can be added optionally.
47716            *
47717            * @name geometryCollection
47718            * @param {Array<Geometry>} geometries an array of GeoJSON Geometries
47719            * @param {Object} [properties={}] an Object of key-value pairs to add as properties
47720            * @param {Object} [options={}] Optional Parameters
47721            * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
47722            * @param {string|number} [options.id] Identifier associated with the Feature
47723            * @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature
47724            * @example
47725            * var pt = turf.geometry("Point", [100, 0]);
47726            * var line = turf.geometry("LineString", [[101, 0], [102, 1]]);
47727            * var collection = turf.geometryCollection([pt, line]);
47728            *
47729            * // => collection
47730            */
47731
47732           function geometryCollection(geometries, properties, options) {
47733             if (options === void 0) {
47734               options = {};
47735             }
47736
47737             var geom = {
47738               type: "GeometryCollection",
47739               geometries: geometries
47740             };
47741             return feature(geom, properties, options);
47742           }
47743
47744           exports.geometryCollection = geometryCollection;
47745           /**
47746            * Round number to precision
47747            *
47748            * @param {number} num Number
47749            * @param {number} [precision=0] Precision
47750            * @returns {number} rounded number
47751            * @example
47752            * turf.round(120.4321)
47753            * //=120
47754            *
47755            * turf.round(120.4321, 2)
47756            * //=120.43
47757            */
47758
47759           function round(num, precision) {
47760             if (precision === void 0) {
47761               precision = 0;
47762             }
47763
47764             if (precision && !(precision >= 0)) {
47765               throw new Error("precision must be a positive number");
47766             }
47767
47768             var multiplier = Math.pow(10, precision || 0);
47769             return Math.round(num * multiplier) / multiplier;
47770           }
47771
47772           exports.round = round;
47773           /**
47774            * Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit.
47775            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47776            *
47777            * @name radiansToLength
47778            * @param {number} radians in radians across the sphere
47779            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47780            * meters, kilometres, kilometers.
47781            * @returns {number} distance
47782            */
47783
47784           function radiansToLength(radians, units) {
47785             if (units === void 0) {
47786               units = "kilometers";
47787             }
47788
47789             var factor = exports.factors[units];
47790
47791             if (!factor) {
47792               throw new Error(units + " units is invalid");
47793             }
47794
47795             return radians * factor;
47796           }
47797
47798           exports.radiansToLength = radiansToLength;
47799           /**
47800            * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians
47801            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47802            *
47803            * @name lengthToRadians
47804            * @param {number} distance in real units
47805            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47806            * meters, kilometres, kilometers.
47807            * @returns {number} radians
47808            */
47809
47810           function lengthToRadians(distance, units) {
47811             if (units === void 0) {
47812               units = "kilometers";
47813             }
47814
47815             var factor = exports.factors[units];
47816
47817             if (!factor) {
47818               throw new Error(units + " units is invalid");
47819             }
47820
47821             return distance / factor;
47822           }
47823
47824           exports.lengthToRadians = lengthToRadians;
47825           /**
47826            * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees
47827            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet
47828            *
47829            * @name lengthToDegrees
47830            * @param {number} distance in real units
47831            * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres,
47832            * meters, kilometres, kilometers.
47833            * @returns {number} degrees
47834            */
47835
47836           function lengthToDegrees(distance, units) {
47837             return radiansToDegrees(lengthToRadians(distance, units));
47838           }
47839
47840           exports.lengthToDegrees = lengthToDegrees;
47841           /**
47842            * Converts any bearing angle from the north line direction (positive clockwise)
47843            * and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line
47844            *
47845            * @name bearingToAzimuth
47846            * @param {number} bearing angle, between -180 and +180 degrees
47847            * @returns {number} angle between 0 and 360 degrees
47848            */
47849
47850           function bearingToAzimuth(bearing) {
47851             var angle = bearing % 360;
47852
47853             if (angle < 0) {
47854               angle += 360;
47855             }
47856
47857             return angle;
47858           }
47859
47860           exports.bearingToAzimuth = bearingToAzimuth;
47861           /**
47862            * Converts an angle in radians to degrees
47863            *
47864            * @name radiansToDegrees
47865            * @param {number} radians angle in radians
47866            * @returns {number} degrees between 0 and 360 degrees
47867            */
47868
47869           function radiansToDegrees(radians) {
47870             var degrees = radians % (2 * Math.PI);
47871             return degrees * 180 / Math.PI;
47872           }
47873
47874           exports.radiansToDegrees = radiansToDegrees;
47875           /**
47876            * Converts an angle in degrees to radians
47877            *
47878            * @name degreesToRadians
47879            * @param {number} degrees angle between 0 and 360 degrees
47880            * @returns {number} angle in radians
47881            */
47882
47883           function degreesToRadians(degrees) {
47884             var radians = degrees % 360;
47885             return radians * Math.PI / 180;
47886           }
47887
47888           exports.degreesToRadians = degreesToRadians;
47889           /**
47890            * Converts a length to the requested unit.
47891            * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet
47892            *
47893            * @param {number} length to be converted
47894            * @param {Units} [originalUnit="kilometers"] of the length
47895            * @param {Units} [finalUnit="kilometers"] returned unit
47896            * @returns {number} the converted length
47897            */
47898
47899           function convertLength(length, originalUnit, finalUnit) {
47900             if (originalUnit === void 0) {
47901               originalUnit = "kilometers";
47902             }
47903
47904             if (finalUnit === void 0) {
47905               finalUnit = "kilometers";
47906             }
47907
47908             if (!(length >= 0)) {
47909               throw new Error("length must be a positive number");
47910             }
47911
47912             return radiansToLength(lengthToRadians(length, originalUnit), finalUnit);
47913           }
47914
47915           exports.convertLength = convertLength;
47916           /**
47917            * Converts a area to the requested unit.
47918            * Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches
47919            * @param {number} area to be converted
47920            * @param {Units} [originalUnit="meters"] of the distance
47921            * @param {Units} [finalUnit="kilometers"] returned unit
47922            * @returns {number} the converted distance
47923            */
47924
47925           function convertArea(area, originalUnit, finalUnit) {
47926             if (originalUnit === void 0) {
47927               originalUnit = "meters";
47928             }
47929
47930             if (finalUnit === void 0) {
47931               finalUnit = "kilometers";
47932             }
47933
47934             if (!(area >= 0)) {
47935               throw new Error("area must be a positive number");
47936             }
47937
47938             var startFactor = exports.areaFactors[originalUnit];
47939
47940             if (!startFactor) {
47941               throw new Error("invalid original units");
47942             }
47943
47944             var finalFactor = exports.areaFactors[finalUnit];
47945
47946             if (!finalFactor) {
47947               throw new Error("invalid final units");
47948             }
47949
47950             return area / startFactor * finalFactor;
47951           }
47952
47953           exports.convertArea = convertArea;
47954           /**
47955            * isNumber
47956            *
47957            * @param {*} num Number to validate
47958            * @returns {boolean} true/false
47959            * @example
47960            * turf.isNumber(123)
47961            * //=true
47962            * turf.isNumber('foo')
47963            * //=false
47964            */
47965
47966           function isNumber(num) {
47967             return !isNaN(num) && num !== null && !Array.isArray(num) && !/^\s*$/.test(num);
47968           }
47969
47970           exports.isNumber = isNumber;
47971           /**
47972            * isObject
47973            *
47974            * @param {*} input variable to validate
47975            * @returns {boolean} true/false
47976            * @example
47977            * turf.isObject({elevation: 10})
47978            * //=true
47979            * turf.isObject('foo')
47980            * //=false
47981            */
47982
47983           function isObject(input) {
47984             return !!input && input.constructor === Object;
47985           }
47986
47987           exports.isObject = isObject;
47988           /**
47989            * Validate BBox
47990            *
47991            * @private
47992            * @param {Array<number>} bbox BBox to validate
47993            * @returns {void}
47994            * @throws Error if BBox is not valid
47995            * @example
47996            * validateBBox([-180, -40, 110, 50])
47997            * //=OK
47998            * validateBBox([-180, -40])
47999            * //=Error
48000            * validateBBox('Foo')
48001            * //=Error
48002            * validateBBox(5)
48003            * //=Error
48004            * validateBBox(null)
48005            * //=Error
48006            * validateBBox(undefined)
48007            * //=Error
48008            */
48009
48010           function validateBBox(bbox) {
48011             if (!bbox) {
48012               throw new Error("bbox is required");
48013             }
48014
48015             if (!Array.isArray(bbox)) {
48016               throw new Error("bbox must be an Array");
48017             }
48018
48019             if (bbox.length !== 4 && bbox.length !== 6) {
48020               throw new Error("bbox must be an Array of 4 or 6 numbers");
48021             }
48022
48023             bbox.forEach(function (num) {
48024               if (!isNumber(num)) {
48025                 throw new Error("bbox must only contain numbers");
48026               }
48027             });
48028           }
48029
48030           exports.validateBBox = validateBBox;
48031           /**
48032            * Validate Id
48033            *
48034            * @private
48035            * @param {string|number} id Id to validate
48036            * @returns {void}
48037            * @throws Error if Id is not valid
48038            * @example
48039            * validateId([-180, -40, 110, 50])
48040            * //=Error
48041            * validateId([-180, -40])
48042            * //=Error
48043            * validateId('Foo')
48044            * //=OK
48045            * validateId(5)
48046            * //=OK
48047            * validateId(null)
48048            * //=Error
48049            * validateId(undefined)
48050            * //=Error
48051            */
48052
48053           function validateId(id) {
48054             if (!id) {
48055               throw new Error("id is required");
48056             }
48057
48058             if (["string", "number"].indexOf(_typeof(id)) === -1) {
48059               throw new Error("id must be a number or a string");
48060             }
48061           }
48062
48063           exports.validateId = validateId; // Deprecated methods
48064
48065           function radians2degrees() {
48066             throw new Error("method has been renamed to `radiansToDegrees`");
48067           }
48068
48069           exports.radians2degrees = radians2degrees;
48070
48071           function degrees2radians() {
48072             throw new Error("method has been renamed to `degreesToRadians`");
48073           }
48074
48075           exports.degrees2radians = degrees2radians;
48076
48077           function distanceToDegrees() {
48078             throw new Error("method has been renamed to `lengthToDegrees`");
48079           }
48080
48081           exports.distanceToDegrees = distanceToDegrees;
48082
48083           function distanceToRadians() {
48084             throw new Error("method has been renamed to `lengthToRadians`");
48085           }
48086
48087           exports.distanceToRadians = distanceToRadians;
48088
48089           function radiansToDistance() {
48090             throw new Error("method has been renamed to `radiansToLength`");
48091           }
48092
48093           exports.radiansToDistance = radiansToDistance;
48094
48095           function bearingToAngle() {
48096             throw new Error("method has been renamed to `bearingToAzimuth`");
48097           }
48098
48099           exports.bearingToAngle = bearingToAngle;
48100
48101           function convertDistance() {
48102             throw new Error("method has been renamed to `convertLength`");
48103           }
48104
48105           exports.convertDistance = convertDistance;
48106         });
48107
48108         var invariant = createCommonjsModule(function (module, exports) {
48109
48110           Object.defineProperty(exports, "__esModule", {
48111             value: true
48112           });
48113           /**
48114            * Unwrap a coordinate from a Point Feature, Geometry or a single coordinate.
48115            *
48116            * @name getCoord
48117            * @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers
48118            * @returns {Array<number>} coordinates
48119            * @example
48120            * var pt = turf.point([10, 10]);
48121            *
48122            * var coord = turf.getCoord(pt);
48123            * //= [10, 10]
48124            */
48125
48126           function getCoord(coord) {
48127             if (!coord) {
48128               throw new Error("coord is required");
48129             }
48130
48131             if (!Array.isArray(coord)) {
48132               if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") {
48133                 return coord.geometry.coordinates;
48134               }
48135
48136               if (coord.type === "Point") {
48137                 return coord.coordinates;
48138               }
48139             }
48140
48141             if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) {
48142               return coord;
48143             }
48144
48145             throw new Error("coord must be GeoJSON Point or an Array of numbers");
48146           }
48147
48148           exports.getCoord = getCoord;
48149           /**
48150            * Unwrap coordinates from a Feature, Geometry Object or an Array
48151            *
48152            * @name getCoords
48153            * @param {Array<any>|Geometry|Feature} coords Feature, Geometry Object or an Array
48154            * @returns {Array<any>} coordinates
48155            * @example
48156            * var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]);
48157            *
48158            * var coords = turf.getCoords(poly);
48159            * //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]
48160            */
48161
48162           function getCoords(coords) {
48163             if (Array.isArray(coords)) {
48164               return coords;
48165             } // Feature
48166
48167
48168             if (coords.type === "Feature") {
48169               if (coords.geometry !== null) {
48170                 return coords.geometry.coordinates;
48171               }
48172             } else {
48173               // Geometry
48174               if (coords.coordinates) {
48175                 return coords.coordinates;
48176               }
48177             }
48178
48179             throw new Error("coords must be GeoJSON Feature, Geometry Object or an Array");
48180           }
48181
48182           exports.getCoords = getCoords;
48183           /**
48184            * Checks if coordinates contains a number
48185            *
48186            * @name containsNumber
48187            * @param {Array<any>} coordinates GeoJSON Coordinates
48188            * @returns {boolean} true if Array contains a number
48189            */
48190
48191           function containsNumber(coordinates) {
48192             if (coordinates.length > 1 && helpers$1.isNumber(coordinates[0]) && helpers$1.isNumber(coordinates[1])) {
48193               return true;
48194             }
48195
48196             if (Array.isArray(coordinates[0]) && coordinates[0].length) {
48197               return containsNumber(coordinates[0]);
48198             }
48199
48200             throw new Error("coordinates must only contain numbers");
48201           }
48202
48203           exports.containsNumber = containsNumber;
48204           /**
48205            * Enforce expectations about types of GeoJSON objects for Turf.
48206            *
48207            * @name geojsonType
48208            * @param {GeoJSON} value any GeoJSON object
48209            * @param {string} type expected GeoJSON type
48210            * @param {string} name name of calling function
48211            * @throws {Error} if value is not the expected type.
48212            */
48213
48214           function geojsonType(value, type, name) {
48215             if (!type || !name) {
48216               throw new Error("type and name required");
48217             }
48218
48219             if (!value || value.type !== type) {
48220               throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + value.type);
48221             }
48222           }
48223
48224           exports.geojsonType = geojsonType;
48225           /**
48226            * Enforce expectations about types of {@link Feature} inputs for Turf.
48227            * Internally this uses {@link geojsonType} to judge geometry types.
48228            *
48229            * @name featureOf
48230            * @param {Feature} feature a feature with an expected geometry type
48231            * @param {string} type expected GeoJSON type
48232            * @param {string} name name of calling function
48233            * @throws {Error} error if value is not the expected type.
48234            */
48235
48236           function featureOf(feature, type, name) {
48237             if (!feature) {
48238               throw new Error("No feature passed");
48239             }
48240
48241             if (!name) {
48242               throw new Error(".featureOf() requires a name");
48243             }
48244
48245             if (!feature || feature.type !== "Feature" || !feature.geometry) {
48246               throw new Error("Invalid input to " + name + ", Feature with geometry required");
48247             }
48248
48249             if (!feature.geometry || feature.geometry.type !== type) {
48250               throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
48251             }
48252           }
48253
48254           exports.featureOf = featureOf;
48255           /**
48256            * Enforce expectations about types of {@link FeatureCollection} inputs for Turf.
48257            * Internally this uses {@link geojsonType} to judge geometry types.
48258            *
48259            * @name collectionOf
48260            * @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged
48261            * @param {string} type expected GeoJSON type
48262            * @param {string} name name of calling function
48263            * @throws {Error} if value is not the expected type.
48264            */
48265
48266           function collectionOf(featureCollection, type, name) {
48267             if (!featureCollection) {
48268               throw new Error("No featureCollection passed");
48269             }
48270
48271             if (!name) {
48272               throw new Error(".collectionOf() requires a name");
48273             }
48274
48275             if (!featureCollection || featureCollection.type !== "FeatureCollection") {
48276               throw new Error("Invalid input to " + name + ", FeatureCollection required");
48277             }
48278
48279             for (var _i = 0, _a = featureCollection.features; _i < _a.length; _i++) {
48280               var feature = _a[_i];
48281
48282               if (!feature || feature.type !== "Feature" || !feature.geometry) {
48283                 throw new Error("Invalid input to " + name + ", Feature with geometry required");
48284               }
48285
48286               if (!feature.geometry || feature.geometry.type !== type) {
48287                 throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type);
48288               }
48289             }
48290           }
48291
48292           exports.collectionOf = collectionOf;
48293           /**
48294            * Get Geometry from Feature or Geometry Object
48295            *
48296            * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
48297            * @returns {Geometry|null} GeoJSON Geometry Object
48298            * @throws {Error} if geojson is not a Feature or Geometry Object
48299            * @example
48300            * var point = {
48301            *   "type": "Feature",
48302            *   "properties": {},
48303            *   "geometry": {
48304            *     "type": "Point",
48305            *     "coordinates": [110, 40]
48306            *   }
48307            * }
48308            * var geom = turf.getGeom(point)
48309            * //={"type": "Point", "coordinates": [110, 40]}
48310            */
48311
48312           function getGeom(geojson) {
48313             if (geojson.type === "Feature") {
48314               return geojson.geometry;
48315             }
48316
48317             return geojson;
48318           }
48319
48320           exports.getGeom = getGeom;
48321           /**
48322            * Get GeoJSON object's type, Geometry type is prioritize.
48323            *
48324            * @param {GeoJSON} geojson GeoJSON object
48325            * @param {string} [name="geojson"] name of the variable to display in error message
48326            * @returns {string} GeoJSON type
48327            * @example
48328            * var point = {
48329            *   "type": "Feature",
48330            *   "properties": {},
48331            *   "geometry": {
48332            *     "type": "Point",
48333            *     "coordinates": [110, 40]
48334            *   }
48335            * }
48336            * var geom = turf.getType(point)
48337            * //="Point"
48338            */
48339
48340           function getType(geojson, name) {
48341             if (geojson.type === "FeatureCollection") {
48342               return "FeatureCollection";
48343             }
48344
48345             if (geojson.type === "GeometryCollection") {
48346               return "GeometryCollection";
48347             }
48348
48349             if (geojson.type === "Feature" && geojson.geometry !== null) {
48350               return geojson.geometry.type;
48351             }
48352
48353             return geojson.type;
48354           }
48355
48356           exports.getType = getType;
48357         });
48358
48359         var lineclip_1 = lineclip;
48360         var _default = lineclip;
48361         lineclip.polyline = lineclip;
48362         lineclip.polygon = polygonclip; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
48363         // handle polylines rather than just segments
48364
48365         function lineclip(points, bbox, result) {
48366           var len = points.length,
48367               codeA = bitCode(points[0], bbox),
48368               part = [],
48369               i,
48370               a,
48371               b,
48372               codeB,
48373               lastCode;
48374           if (!result) result = [];
48375
48376           for (i = 1; i < len; i++) {
48377             a = points[i - 1];
48378             b = points[i];
48379             codeB = lastCode = bitCode(b, bbox);
48380
48381             while (true) {
48382               if (!(codeA | codeB)) {
48383                 // accept
48384                 part.push(a);
48385
48386                 if (codeB !== lastCode) {
48387                   // segment went outside
48388                   part.push(b);
48389
48390                   if (i < len - 1) {
48391                     // start a new line
48392                     result.push(part);
48393                     part = [];
48394                   }
48395                 } else if (i === len - 1) {
48396                   part.push(b);
48397                 }
48398
48399                 break;
48400               } else if (codeA & codeB) {
48401                 // trivial reject
48402                 break;
48403               } else if (codeA) {
48404                 // a outside, intersect with clip edge
48405                 a = intersect(a, b, codeA, bbox);
48406                 codeA = bitCode(a, bbox);
48407               } else {
48408                 // b outside
48409                 b = intersect(a, b, codeB, bbox);
48410                 codeB = bitCode(b, bbox);
48411               }
48412             }
48413
48414             codeA = lastCode;
48415           }
48416
48417           if (part.length) result.push(part);
48418           return result;
48419         } // Sutherland-Hodgeman polygon clipping algorithm
48420
48421
48422         function polygonclip(points, bbox) {
48423           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
48424
48425           for (edge = 1; edge <= 8; edge *= 2) {
48426             result = [];
48427             prev = points[points.length - 1];
48428             prevInside = !(bitCode(prev, bbox) & edge);
48429
48430             for (i = 0; i < points.length; i++) {
48431               p = points[i];
48432               inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
48433
48434               if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
48435               if (inside) result.push(p); // add a point if it's inside
48436
48437               prev = p;
48438               prevInside = inside;
48439             }
48440
48441             points = result;
48442             if (!points.length) break;
48443           }
48444
48445           return result;
48446         } // intersect a segment against one of the 4 lines that make up the bbox
48447
48448
48449         function intersect(a, b, edge, bbox) {
48450           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
48451           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
48452           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
48453           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
48454           null;
48455         } // bit code reflects the point position relative to the bbox:
48456         //         left  mid  right
48457         //    top  1001  1000  1010
48458         //    mid  0001  0000  0010
48459         // bottom  0101  0100  0110
48460
48461
48462         function bitCode(p, bbox) {
48463           var code = 0;
48464           if (p[0] < bbox[0]) code |= 1; // left
48465           else if (p[0] > bbox[2]) code |= 2; // right
48466
48467           if (p[1] < bbox[1]) code |= 4; // bottom
48468           else if (p[1] > bbox[3]) code |= 8; // top
48469
48470           return code;
48471         }
48472         lineclip_1["default"] = _default;
48473
48474         var bboxClip_1 = createCommonjsModule(function (module, exports) {
48475
48476           var __importStar = commonjsGlobal && commonjsGlobal.__importStar || function (mod) {
48477             if (mod && mod.__esModule) return mod;
48478             var result = {};
48479             if (mod != null) for (var k in mod) {
48480               if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
48481             }
48482             result["default"] = mod;
48483             return result;
48484           };
48485
48486           Object.defineProperty(exports, "__esModule", {
48487             value: true
48488           });
48489
48490           var lineclip = __importStar(lineclip_1);
48491           /**
48492            * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
48493            * [lineclip](https://github.com/mapbox/lineclip).
48494            * May result in degenerate edges when clipping Polygons.
48495            *
48496            * @name bboxClip
48497            * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
48498            * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
48499            * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
48500            * @example
48501            * var bbox = [0, 0, 10, 10];
48502            * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
48503            *
48504            * var clipped = turf.bboxClip(poly, bbox);
48505            *
48506            * //addToMap
48507            * var addToMap = [bbox, poly, clipped]
48508            */
48509
48510
48511           function bboxClip(feature, bbox) {
48512             var geom = invariant.getGeom(feature);
48513             var type = geom.type;
48514             var properties = feature.type === "Feature" ? feature.properties : {};
48515             var coords = geom.coordinates;
48516
48517             switch (type) {
48518               case "LineString":
48519               case "MultiLineString":
48520                 var lines_1 = [];
48521
48522                 if (type === "LineString") {
48523                   coords = [coords];
48524                 }
48525
48526                 coords.forEach(function (line) {
48527                   lineclip.polyline(line, bbox, lines_1);
48528                 });
48529
48530                 if (lines_1.length === 1) {
48531                   return helpers$1.lineString(lines_1[0], properties);
48532                 }
48533
48534                 return helpers$1.multiLineString(lines_1, properties);
48535
48536               case "Polygon":
48537                 return helpers$1.polygon(clipPolygon(coords, bbox), properties);
48538
48539               case "MultiPolygon":
48540                 return helpers$1.multiPolygon(coords.map(function (poly) {
48541                   return clipPolygon(poly, bbox);
48542                 }), properties);
48543
48544               default:
48545                 throw new Error("geometry " + type + " not supported");
48546             }
48547           }
48548
48549           exports["default"] = bboxClip;
48550
48551           function clipPolygon(rings, bbox) {
48552             var outRings = [];
48553
48554             for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
48555               var ring = rings_1[_i];
48556               var clipped = lineclip.polygon(ring, bbox);
48557
48558               if (clipped.length > 0) {
48559                 if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
48560                   clipped.push(clipped[0]);
48561                 }
48562
48563                 if (clipped.length >= 4) {
48564                   outRings.push(clipped);
48565                 }
48566               }
48567             }
48568
48569             return outRings;
48570           }
48571         });
48572         var turf_bboxClip = /*@__PURE__*/getDefaultExportFromCjs(bboxClip_1);
48573
48574         var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
48575           if (!opts) opts = {};
48576           if (typeof opts === 'function') opts = {
48577             cmp: opts
48578           };
48579           var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
48580
48581           var cmp = opts.cmp && function (f) {
48582             return function (node) {
48583               return function (a, b) {
48584                 var aobj = {
48585                   key: a,
48586                   value: node[a]
48587                 };
48588                 var bobj = {
48589                   key: b,
48590                   value: node[b]
48591                 };
48592                 return f(aobj, bobj);
48593               };
48594             };
48595           }(opts.cmp);
48596
48597           var seen = [];
48598           return function stringify(node) {
48599             if (node && node.toJSON && typeof node.toJSON === 'function') {
48600               node = node.toJSON();
48601             }
48602
48603             if (node === undefined) return;
48604             if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
48605             if (_typeof(node) !== 'object') return JSON.stringify(node);
48606             var i, out;
48607
48608             if (Array.isArray(node)) {
48609               out = '[';
48610
48611               for (i = 0; i < node.length; i++) {
48612                 if (i) out += ',';
48613                 out += stringify(node[i]) || 'null';
48614               }
48615
48616               return out + ']';
48617             }
48618
48619             if (node === null) return 'null';
48620
48621             if (seen.indexOf(node) !== -1) {
48622               if (cycles) return JSON.stringify('__cycle__');
48623               throw new TypeError('Converting circular structure to JSON');
48624             }
48625
48626             var seenIndex = seen.push(node) - 1;
48627             var keys = Object.keys(node).sort(cmp && cmp(node));
48628             out = '';
48629
48630             for (i = 0; i < keys.length; i++) {
48631               var key = keys[i];
48632               var value = stringify(node[key]);
48633               if (!value) continue;
48634               if (out) out += ',';
48635               out += JSON.stringify(key) + ':' + value;
48636             }
48637
48638             seen.splice(seenIndex, 1);
48639             return '{' + out + '}';
48640           }(data);
48641         };
48642
48643         function DEFAULT_COMPARE(a, b) {
48644           return a > b ? 1 : a < b ? -1 : 0;
48645         }
48646
48647         var SplayTree = /*#__PURE__*/function () {
48648           function SplayTree() {
48649             var compare = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE;
48650             var noDuplicates = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
48651
48652             _classCallCheck(this, SplayTree);
48653
48654             this._compare = compare;
48655             this._root = null;
48656             this._size = 0;
48657             this._noDuplicates = !!noDuplicates;
48658           }
48659
48660           _createClass(SplayTree, [{
48661             key: "rotateLeft",
48662             value: function rotateLeft(x) {
48663               var y = x.right;
48664
48665               if (y) {
48666                 x.right = y.left;
48667                 if (y.left) y.left.parent = x;
48668                 y.parent = x.parent;
48669               }
48670
48671               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
48672               if (y) y.left = x;
48673               x.parent = y;
48674             }
48675           }, {
48676             key: "rotateRight",
48677             value: function rotateRight(x) {
48678               var y = x.left;
48679
48680               if (y) {
48681                 x.left = y.right;
48682                 if (y.right) y.right.parent = x;
48683                 y.parent = x.parent;
48684               }
48685
48686               if (!x.parent) this._root = y;else if (x === x.parent.left) x.parent.left = y;else x.parent.right = y;
48687               if (y) y.right = x;
48688               x.parent = y;
48689             }
48690           }, {
48691             key: "_splay",
48692             value: function _splay(x) {
48693               while (x.parent) {
48694                 var p = x.parent;
48695
48696                 if (!p.parent) {
48697                   if (p.left === x) this.rotateRight(p);else this.rotateLeft(p);
48698                 } else if (p.left === x && p.parent.left === p) {
48699                   this.rotateRight(p.parent);
48700                   this.rotateRight(p);
48701                 } else if (p.right === x && p.parent.right === p) {
48702                   this.rotateLeft(p.parent);
48703                   this.rotateLeft(p);
48704                 } else if (p.left === x && p.parent.right === p) {
48705                   this.rotateRight(p);
48706                   this.rotateLeft(p);
48707                 } else {
48708                   this.rotateLeft(p);
48709                   this.rotateRight(p);
48710                 }
48711               }
48712             }
48713           }, {
48714             key: "splay",
48715             value: function splay(x) {
48716               var p, gp, ggp, l, r;
48717
48718               while (x.parent) {
48719                 p = x.parent;
48720                 gp = p.parent;
48721
48722                 if (gp && gp.parent) {
48723                   ggp = gp.parent;
48724                   if (ggp.left === gp) ggp.left = x;else ggp.right = x;
48725                   x.parent = ggp;
48726                 } else {
48727                   x.parent = null;
48728                   this._root = x;
48729                 }
48730
48731                 l = x.left;
48732                 r = x.right;
48733
48734                 if (x === p.left) {
48735                   // left
48736                   if (gp) {
48737                     if (gp.left === p) {
48738                       /* zig-zig */
48739                       if (p.right) {
48740                         gp.left = p.right;
48741                         gp.left.parent = gp;
48742                       } else gp.left = null;
48743
48744                       p.right = gp;
48745                       gp.parent = p;
48746                     } else {
48747                       /* zig-zag */
48748                       if (l) {
48749                         gp.right = l;
48750                         l.parent = gp;
48751                       } else gp.right = null;
48752
48753                       x.left = gp;
48754                       gp.parent = x;
48755                     }
48756                   }
48757
48758                   if (r) {
48759                     p.left = r;
48760                     r.parent = p;
48761                   } else p.left = null;
48762
48763                   x.right = p;
48764                   p.parent = x;
48765                 } else {
48766                   // right
48767                   if (gp) {
48768                     if (gp.right === p) {
48769                       /* zig-zig */
48770                       if (p.left) {
48771                         gp.right = p.left;
48772                         gp.right.parent = gp;
48773                       } else gp.right = null;
48774
48775                       p.left = gp;
48776                       gp.parent = p;
48777                     } else {
48778                       /* zig-zag */
48779                       if (r) {
48780                         gp.left = r;
48781                         r.parent = gp;
48782                       } else gp.left = null;
48783
48784                       x.right = gp;
48785                       gp.parent = x;
48786                     }
48787                   }
48788
48789                   if (l) {
48790                     p.right = l;
48791                     l.parent = p;
48792                   } else p.right = null;
48793
48794                   x.left = p;
48795                   p.parent = x;
48796                 }
48797               }
48798             }
48799           }, {
48800             key: "replace",
48801             value: function replace(u, v) {
48802               if (!u.parent) this._root = v;else if (u === u.parent.left) u.parent.left = v;else u.parent.right = v;
48803               if (v) v.parent = u.parent;
48804             }
48805           }, {
48806             key: "minNode",
48807             value: function minNode() {
48808               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
48809               if (u) while (u.left) {
48810                 u = u.left;
48811               }
48812               return u;
48813             }
48814           }, {
48815             key: "maxNode",
48816             value: function maxNode() {
48817               var u = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
48818               if (u) while (u.right) {
48819                 u = u.right;
48820               }
48821               return u;
48822             }
48823           }, {
48824             key: "insert",
48825             value: function insert(key, data) {
48826               var z = this._root;
48827               var p = null;
48828               var comp = this._compare;
48829               var cmp;
48830
48831               if (this._noDuplicates) {
48832                 while (z) {
48833                   p = z;
48834                   cmp = comp(z.key, key);
48835                   if (cmp === 0) return;else if (comp(z.key, key) < 0) z = z.right;else z = z.left;
48836                 }
48837               } else {
48838                 while (z) {
48839                   p = z;
48840                   if (comp(z.key, key) < 0) z = z.right;else z = z.left;
48841                 }
48842               }
48843
48844               z = {
48845                 key: key,
48846                 data: data,
48847                 left: null,
48848                 right: null,
48849                 parent: p
48850               };
48851               if (!p) this._root = z;else if (comp(p.key, z.key) < 0) p.right = z;else p.left = z;
48852               this.splay(z);
48853               this._size++;
48854               return z;
48855             }
48856           }, {
48857             key: "find",
48858             value: function find(key) {
48859               var z = this._root;
48860               var comp = this._compare;
48861
48862               while (z) {
48863                 var cmp = comp(z.key, key);
48864                 if (cmp < 0) z = z.right;else if (cmp > 0) z = z.left;else return z;
48865               }
48866
48867               return null;
48868             }
48869             /**
48870              * Whether the tree contains a node with the given key
48871              * @param  {Key} key
48872              * @return {boolean} true/false
48873              */
48874
48875           }, {
48876             key: "contains",
48877             value: function contains(key) {
48878               var node = this._root;
48879               var comparator = this._compare;
48880
48881               while (node) {
48882                 var cmp = comparator(key, node.key);
48883                 if (cmp === 0) return true;else if (cmp < 0) node = node.left;else node = node.right;
48884               }
48885
48886               return false;
48887             }
48888           }, {
48889             key: "remove",
48890             value: function remove(key) {
48891               var z = this.find(key);
48892               if (!z) return false;
48893               this.splay(z);
48894               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
48895                 var y = this.minNode(z.right);
48896
48897                 if (y.parent !== z) {
48898                   this.replace(y, y.right);
48899                   y.right = z.right;
48900                   y.right.parent = y;
48901                 }
48902
48903                 this.replace(z, y);
48904                 y.left = z.left;
48905                 y.left.parent = y;
48906               }
48907               this._size--;
48908               return true;
48909             }
48910           }, {
48911             key: "removeNode",
48912             value: function removeNode(z) {
48913               if (!z) return false;
48914               this.splay(z);
48915               if (!z.left) this.replace(z, z.right);else if (!z.right) this.replace(z, z.left);else {
48916                 var y = this.minNode(z.right);
48917
48918                 if (y.parent !== z) {
48919                   this.replace(y, y.right);
48920                   y.right = z.right;
48921                   y.right.parent = y;
48922                 }
48923
48924                 this.replace(z, y);
48925                 y.left = z.left;
48926                 y.left.parent = y;
48927               }
48928               this._size--;
48929               return true;
48930             }
48931           }, {
48932             key: "erase",
48933             value: function erase(key) {
48934               var z = this.find(key);
48935               if (!z) return;
48936               this.splay(z);
48937               var s = z.left;
48938               var t = z.right;
48939               var sMax = null;
48940
48941               if (s) {
48942                 s.parent = null;
48943                 sMax = this.maxNode(s);
48944                 this.splay(sMax);
48945                 this._root = sMax;
48946               }
48947
48948               if (t) {
48949                 if (s) sMax.right = t;else this._root = t;
48950                 t.parent = sMax;
48951               }
48952
48953               this._size--;
48954             }
48955             /**
48956              * Removes and returns the node with smallest key
48957              * @return {?Node}
48958              */
48959
48960           }, {
48961             key: "pop",
48962             value: function pop() {
48963               var node = this._root,
48964                   returnValue = null;
48965
48966               if (node) {
48967                 while (node.left) {
48968                   node = node.left;
48969                 }
48970
48971                 returnValue = {
48972                   key: node.key,
48973                   data: node.data
48974                 };
48975                 this.remove(node.key);
48976               }
48977
48978               return returnValue;
48979             }
48980             /* eslint-disable class-methods-use-this */
48981
48982             /**
48983              * Successor node
48984              * @param  {Node} node
48985              * @return {?Node}
48986              */
48987
48988           }, {
48989             key: "next",
48990             value: function next(node) {
48991               var successor = node;
48992
48993               if (successor) {
48994                 if (successor.right) {
48995                   successor = successor.right;
48996
48997                   while (successor && successor.left) {
48998                     successor = successor.left;
48999                   }
49000                 } else {
49001                   successor = node.parent;
49002
49003                   while (successor && successor.right === node) {
49004                     node = successor;
49005                     successor = successor.parent;
49006                   }
49007                 }
49008               }
49009
49010               return successor;
49011             }
49012             /**
49013              * Predecessor node
49014              * @param  {Node} node
49015              * @return {?Node}
49016              */
49017
49018           }, {
49019             key: "prev",
49020             value: function prev(node) {
49021               var predecessor = node;
49022
49023               if (predecessor) {
49024                 if (predecessor.left) {
49025                   predecessor = predecessor.left;
49026
49027                   while (predecessor && predecessor.right) {
49028                     predecessor = predecessor.right;
49029                   }
49030                 } else {
49031                   predecessor = node.parent;
49032
49033                   while (predecessor && predecessor.left === node) {
49034                     node = predecessor;
49035                     predecessor = predecessor.parent;
49036                   }
49037                 }
49038               }
49039
49040               return predecessor;
49041             }
49042             /* eslint-enable class-methods-use-this */
49043
49044             /**
49045              * @param  {forEachCallback} callback
49046              * @return {SplayTree}
49047              */
49048
49049           }, {
49050             key: "forEach",
49051             value: function forEach(callback) {
49052               var current = this._root;
49053               var s = [],
49054                   done = false,
49055                   i = 0;
49056
49057               while (!done) {
49058                 // Reach the left most Node of the current Node
49059                 if (current) {
49060                   // Place pointer to a tree node on the stack
49061                   // before traversing the node's left subtree
49062                   s.push(current);
49063                   current = current.left;
49064                 } else {
49065                   // BackTrack from the empty subtree and visit the Node
49066                   // at the top of the stack; however, if the stack is
49067                   // empty you are done
49068                   if (s.length > 0) {
49069                     current = s.pop();
49070                     callback(current, i++); // We have visited the node and its left
49071                     // subtree. Now, it's right subtree's turn
49072
49073                     current = current.right;
49074                   } else done = true;
49075                 }
49076               }
49077
49078               return this;
49079             }
49080             /**
49081              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
49082              * @param  {Key}      low
49083              * @param  {Key}      high
49084              * @param  {Function} fn
49085              * @param  {*?}       ctx
49086              * @return {SplayTree}
49087              */
49088
49089           }, {
49090             key: "range",
49091             value: function range(low, high, fn, ctx) {
49092               var Q = [];
49093               var compare = this._compare;
49094               var node = this._root,
49095                   cmp;
49096
49097               while (Q.length !== 0 || node) {
49098                 if (node) {
49099                   Q.push(node);
49100                   node = node.left;
49101                 } else {
49102                   node = Q.pop();
49103                   cmp = compare(node.key, high);
49104
49105                   if (cmp > 0) {
49106                     break;
49107                   } else if (compare(node.key, low) >= 0) {
49108                     if (fn.call(ctx, node)) return this; // stop if smth is returned
49109                   }
49110
49111                   node = node.right;
49112                 }
49113               }
49114
49115               return this;
49116             }
49117             /**
49118              * Returns all keys in order
49119              * @return {Array<Key>}
49120              */
49121
49122           }, {
49123             key: "keys",
49124             value: function keys() {
49125               var current = this._root;
49126               var s = [],
49127                   r = [],
49128                   done = false;
49129
49130               while (!done) {
49131                 if (current) {
49132                   s.push(current);
49133                   current = current.left;
49134                 } else {
49135                   if (s.length > 0) {
49136                     current = s.pop();
49137                     r.push(current.key);
49138                     current = current.right;
49139                   } else done = true;
49140                 }
49141               }
49142
49143               return r;
49144             }
49145             /**
49146              * Returns `data` fields of all nodes in order.
49147              * @return {Array<Value>}
49148              */
49149
49150           }, {
49151             key: "values",
49152             value: function values() {
49153               var current = this._root;
49154               var s = [],
49155                   r = [],
49156                   done = false;
49157
49158               while (!done) {
49159                 if (current) {
49160                   s.push(current);
49161                   current = current.left;
49162                 } else {
49163                   if (s.length > 0) {
49164                     current = s.pop();
49165                     r.push(current.data);
49166                     current = current.right;
49167                   } else done = true;
49168                 }
49169               }
49170
49171               return r;
49172             }
49173             /**
49174              * Returns node at given index
49175              * @param  {number} index
49176              * @return {?Node}
49177              */
49178
49179           }, {
49180             key: "at",
49181             value: function at(index) {
49182               // removed after a consideration, more misleading than useful
49183               // index = index % this.size;
49184               // if (index < 0) index = this.size - index;
49185               var current = this._root;
49186               var s = [],
49187                   done = false,
49188                   i = 0;
49189
49190               while (!done) {
49191                 if (current) {
49192                   s.push(current);
49193                   current = current.left;
49194                 } else {
49195                   if (s.length > 0) {
49196                     current = s.pop();
49197                     if (i === index) return current;
49198                     i++;
49199                     current = current.right;
49200                   } else done = true;
49201                 }
49202               }
49203
49204               return null;
49205             }
49206             /**
49207              * Bulk-load items. Both array have to be same size
49208              * @param  {Array<Key>}    keys
49209              * @param  {Array<Value>}  [values]
49210              * @param  {Boolean}       [presort=false] Pre-sort keys and values, using
49211              *                                         tree's comparator. Sorting is done
49212              *                                         in-place
49213              * @return {AVLTree}
49214              */
49215
49216           }, {
49217             key: "load",
49218             value: function load() {
49219               var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
49220               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49221               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
49222               if (this._size !== 0) throw new Error('bulk-load: tree is not empty');
49223               var size = keys.length;
49224               if (presort) sort(keys, values, 0, size - 1, this._compare);
49225               this._root = loadRecursive(null, keys, values, 0, size);
49226               this._size = size;
49227               return this;
49228             }
49229           }, {
49230             key: "min",
49231             value: function min() {
49232               var node = this.minNode(this._root);
49233               if (node) return node.key;else return null;
49234             }
49235           }, {
49236             key: "max",
49237             value: function max() {
49238               var node = this.maxNode(this._root);
49239               if (node) return node.key;else return null;
49240             }
49241           }, {
49242             key: "isEmpty",
49243             value: function isEmpty() {
49244               return this._root === null;
49245             }
49246           }, {
49247             key: "size",
49248             get: function get() {
49249               return this._size;
49250             }
49251             /**
49252              * Create a tree and load it with items
49253              * @param  {Array<Key>}          keys
49254              * @param  {Array<Value>?}        [values]
49255               * @param  {Function?}            [comparator]
49256              * @param  {Boolean?}             [presort=false] Pre-sort keys and values, using
49257              *                                               tree's comparator. Sorting is done
49258              *                                               in-place
49259              * @param  {Boolean?}             [noDuplicates=false]   Allow duplicates
49260              * @return {SplayTree}
49261              */
49262
49263           }], [{
49264             key: "createTree",
49265             value: function createTree(keys, values, comparator, presort, noDuplicates) {
49266               return new SplayTree(comparator, noDuplicates).load(keys, values, presort);
49267             }
49268           }]);
49269
49270           return SplayTree;
49271         }();
49272
49273         function loadRecursive(parent, keys, values, start, end) {
49274           var size = end - start;
49275
49276           if (size > 0) {
49277             var middle = start + Math.floor(size / 2);
49278             var key = keys[middle];
49279             var data = values[middle];
49280             var node = {
49281               key: key,
49282               data: data,
49283               parent: parent
49284             };
49285             node.left = loadRecursive(node, keys, values, start, middle);
49286             node.right = loadRecursive(node, keys, values, middle + 1, end);
49287             return node;
49288           }
49289
49290           return null;
49291         }
49292
49293         function sort(keys, values, left, right, compare) {
49294           if (left >= right) return;
49295           var pivot = keys[left + right >> 1];
49296           var i = left - 1;
49297           var j = right + 1;
49298
49299           while (true) {
49300             do {
49301               i++;
49302             } while (compare(keys[i], pivot) < 0);
49303
49304             do {
49305               j--;
49306             } while (compare(keys[j], pivot) > 0);
49307
49308             if (i >= j) break;
49309             var tmp = keys[i];
49310             keys[i] = keys[j];
49311             keys[j] = tmp;
49312             tmp = values[i];
49313             values[i] = values[j];
49314             values[j] = tmp;
49315           }
49316
49317           sort(keys, values, left, j, compare);
49318           sort(keys, values, j + 1, right, compare);
49319         }
49320
49321         var NORMAL = 0;
49322         var NON_CONTRIBUTING = 1;
49323         var SAME_TRANSITION = 2;
49324         var DIFFERENT_TRANSITION = 3;
49325
49326         var INTERSECTION = 0;
49327         var UNION = 1;
49328         var DIFFERENCE = 2;
49329         var XOR = 3;
49330
49331         /**
49332          * @param  {SweepEvent} event
49333          * @param  {SweepEvent} prev
49334          * @param  {Operation} operation
49335          */
49336
49337         function computeFields(event, prev, operation) {
49338           // compute inOut and otherInOut fields
49339           if (prev === null) {
49340             event.inOut = false;
49341             event.otherInOut = true; // previous line segment in sweepline belongs to the same polygon
49342           } else {
49343             if (event.isSubject === prev.isSubject) {
49344               event.inOut = !prev.inOut;
49345               event.otherInOut = prev.otherInOut; // previous line segment in sweepline belongs to the clipping polygon
49346             } else {
49347               event.inOut = !prev.otherInOut;
49348               event.otherInOut = prev.isVertical() ? !prev.inOut : prev.inOut;
49349             } // compute prevInResult field
49350
49351
49352             if (prev) {
49353               event.prevInResult = !inResult(prev, operation) || prev.isVertical() ? prev.prevInResult : prev;
49354             }
49355           } // check if the line segment belongs to the Boolean operation
49356
49357
49358           var isInResult = inResult(event, operation);
49359
49360           if (isInResult) {
49361             event.resultTransition = determineResultTransition(event, operation);
49362           } else {
49363             event.resultTransition = 0;
49364           }
49365         }
49366         /* eslint-disable indent */
49367
49368         function inResult(event, operation) {
49369           switch (event.type) {
49370             case NORMAL:
49371               switch (operation) {
49372                 case INTERSECTION:
49373                   return !event.otherInOut;
49374
49375                 case UNION:
49376                   return event.otherInOut;
49377
49378                 case DIFFERENCE:
49379                   // return (event.isSubject && !event.otherInOut) ||
49380                   //         (!event.isSubject && event.otherInOut);
49381                   return event.isSubject && event.otherInOut || !event.isSubject && !event.otherInOut;
49382
49383                 case XOR:
49384                   return true;
49385               }
49386
49387               break;
49388
49389             case SAME_TRANSITION:
49390               return operation === INTERSECTION || operation === UNION;
49391
49392             case DIFFERENT_TRANSITION:
49393               return operation === DIFFERENCE;
49394
49395             case NON_CONTRIBUTING:
49396               return false;
49397           }
49398
49399           return false;
49400         }
49401         /* eslint-enable indent */
49402
49403
49404         function determineResultTransition(event, operation) {
49405           var thisIn = !event.inOut;
49406           var thatIn = !event.otherInOut;
49407           var isIn;
49408
49409           switch (operation) {
49410             case INTERSECTION:
49411               isIn = thisIn && thatIn;
49412               break;
49413
49414             case UNION:
49415               isIn = thisIn || thatIn;
49416               break;
49417
49418             case XOR:
49419               isIn = thisIn ^ thatIn;
49420               break;
49421
49422             case DIFFERENCE:
49423               if (event.isSubject) {
49424                 isIn = thisIn && !thatIn;
49425               } else {
49426                 isIn = thatIn && !thisIn;
49427               }
49428
49429               break;
49430           }
49431
49432           return isIn ? +1 : -1;
49433         }
49434
49435         var SweepEvent = /*#__PURE__*/function () {
49436           /**
49437            * Sweepline event
49438            *
49439            * @class {SweepEvent}
49440            * @param {Array.<Number>}  point
49441            * @param {Boolean}         left
49442            * @param {SweepEvent=}     otherEvent
49443            * @param {Boolean}         isSubject
49444            * @param {Number}          edgeType
49445            */
49446           function SweepEvent(point, left, otherEvent, isSubject, edgeType) {
49447             _classCallCheck(this, SweepEvent);
49448
49449             /**
49450              * Is left endpoint?
49451              * @type {Boolean}
49452              */
49453             this.left = left;
49454             /**
49455              * @type {Array.<Number>}
49456              */
49457
49458             this.point = point;
49459             /**
49460              * Other edge reference
49461              * @type {SweepEvent}
49462              */
49463
49464             this.otherEvent = otherEvent;
49465             /**
49466              * Belongs to source or clipping polygon
49467              * @type {Boolean}
49468              */
49469
49470             this.isSubject = isSubject;
49471             /**
49472              * Edge contribution type
49473              * @type {Number}
49474              */
49475
49476             this.type = edgeType || NORMAL;
49477             /**
49478              * In-out transition for the sweepline crossing polygon
49479              * @type {Boolean}
49480              */
49481
49482             this.inOut = false;
49483             /**
49484              * @type {Boolean}
49485              */
49486
49487             this.otherInOut = false;
49488             /**
49489              * Previous event in result?
49490              * @type {SweepEvent}
49491              */
49492
49493             this.prevInResult = null;
49494             /**
49495              * Type of result transition (0 = not in result, +1 = out-in, -1, in-out)
49496              * @type {Number}
49497              */
49498
49499             this.resultTransition = 0; // connection step
49500
49501             /**
49502              * @type {Number}
49503              */
49504
49505             this.otherPos = -1;
49506             /**
49507              * @type {Number}
49508              */
49509
49510             this.outputContourId = -1;
49511             this.isExteriorRing = true; // TODO: Looks unused, remove?
49512           }
49513           /**
49514            * @param  {Array.<Number>}  p
49515            * @return {Boolean}
49516            */
49517
49518
49519           _createClass(SweepEvent, [{
49520             key: "isBelow",
49521             value: function isBelow(p) {
49522               var p0 = this.point,
49523                   p1 = this.otherEvent.point;
49524               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 :
49525               : (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;
49526             }
49527             /**
49528              * @param  {Array.<Number>}  p
49529              * @return {Boolean}
49530              */
49531
49532           }, {
49533             key: "isAbove",
49534             value: function isAbove(p) {
49535               return !this.isBelow(p);
49536             }
49537             /**
49538              * @return {Boolean}
49539              */
49540
49541           }, {
49542             key: "isVertical",
49543             value: function isVertical() {
49544               return this.point[0] === this.otherEvent.point[0];
49545             }
49546             /**
49547              * Does event belong to result?
49548              * @return {Boolean}
49549              */
49550
49551           }, {
49552             key: "clone",
49553             value: function clone() {
49554               var copy = new SweepEvent(this.point, this.left, this.otherEvent, this.isSubject, this.type);
49555               copy.contourId = this.contourId;
49556               copy.resultTransition = this.resultTransition;
49557               copy.prevInResult = this.prevInResult;
49558               copy.isExteriorRing = this.isExteriorRing;
49559               copy.inOut = this.inOut;
49560               copy.otherInOut = this.otherInOut;
49561               return copy;
49562             }
49563           }, {
49564             key: "inResult",
49565             get: function get() {
49566               return this.resultTransition !== 0;
49567             }
49568           }]);
49569
49570           return SweepEvent;
49571         }();
49572
49573         function equals(p1, p2) {
49574           if (p1[0] === p2[0]) {
49575             if (p1[1] === p2[1]) {
49576               return true;
49577             } else {
49578               return false;
49579             }
49580           }
49581
49582           return false;
49583         } // const EPSILON = 1e-9;
49584         // const abs = Math.abs;
49585         // TODO https://github.com/w8r/martinez/issues/6#issuecomment-262847164
49586         // Precision problem.
49587         //
49588         // module.exports = function equals(p1, p2) {
49589         //   return abs(p1[0] - p2[0]) <= EPSILON && abs(p1[1] - p2[1]) <= EPSILON;
49590         // };
49591
49592         var epsilon$1 = 1.1102230246251565e-16;
49593         var splitter = 134217729;
49594         var resulterrbound = (3 + 8 * epsilon$1) * epsilon$1; // fast_expansion_sum_zeroelim routine from oritinal code
49595
49596         function sum(elen, e, flen, f, h) {
49597           var Q, Qnew, hh, bvirt;
49598           var enow = e[0];
49599           var fnow = f[0];
49600           var eindex = 0;
49601           var findex = 0;
49602
49603           if (fnow > enow === fnow > -enow) {
49604             Q = enow;
49605             enow = e[++eindex];
49606           } else {
49607             Q = fnow;
49608             fnow = f[++findex];
49609           }
49610
49611           var hindex = 0;
49612
49613           if (eindex < elen && findex < flen) {
49614             if (fnow > enow === fnow > -enow) {
49615               Qnew = enow + Q;
49616               hh = Q - (Qnew - enow);
49617               enow = e[++eindex];
49618             } else {
49619               Qnew = fnow + Q;
49620               hh = Q - (Qnew - fnow);
49621               fnow = f[++findex];
49622             }
49623
49624             Q = Qnew;
49625
49626             if (hh !== 0) {
49627               h[hindex++] = hh;
49628             }
49629
49630             while (eindex < elen && findex < flen) {
49631               if (fnow > enow === fnow > -enow) {
49632                 Qnew = Q + enow;
49633                 bvirt = Qnew - Q;
49634                 hh = Q - (Qnew - bvirt) + (enow - bvirt);
49635                 enow = e[++eindex];
49636               } else {
49637                 Qnew = Q + fnow;
49638                 bvirt = Qnew - Q;
49639                 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
49640                 fnow = f[++findex];
49641               }
49642
49643               Q = Qnew;
49644
49645               if (hh !== 0) {
49646                 h[hindex++] = hh;
49647               }
49648             }
49649           }
49650
49651           while (eindex < elen) {
49652             Qnew = Q + enow;
49653             bvirt = Qnew - Q;
49654             hh = Q - (Qnew - bvirt) + (enow - bvirt);
49655             enow = e[++eindex];
49656             Q = Qnew;
49657
49658             if (hh !== 0) {
49659               h[hindex++] = hh;
49660             }
49661           }
49662
49663           while (findex < flen) {
49664             Qnew = Q + fnow;
49665             bvirt = Qnew - Q;
49666             hh = Q - (Qnew - bvirt) + (fnow - bvirt);
49667             fnow = f[++findex];
49668             Q = Qnew;
49669
49670             if (hh !== 0) {
49671               h[hindex++] = hh;
49672             }
49673           }
49674
49675           if (Q !== 0 || hindex === 0) {
49676             h[hindex++] = Q;
49677           }
49678
49679           return hindex;
49680         }
49681         function estimate(elen, e) {
49682           var Q = e[0];
49683
49684           for (var i = 1; i < elen; i++) {
49685             Q += e[i];
49686           }
49687
49688           return Q;
49689         }
49690         function vec(n) {
49691           return new Float64Array(n);
49692         }
49693
49694         var ccwerrboundA = (3 + 16 * epsilon$1) * epsilon$1;
49695         var ccwerrboundB = (2 + 12 * epsilon$1) * epsilon$1;
49696         var ccwerrboundC = (9 + 64 * epsilon$1) * epsilon$1 * epsilon$1;
49697         var B = vec(4);
49698         var C1 = vec(8);
49699         var C2 = vec(12);
49700         var D = vec(16);
49701         var u = vec(4);
49702
49703         function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
49704           var acxtail, acytail, bcxtail, bcytail;
49705
49706           var bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
49707
49708           var acx = ax - cx;
49709           var bcx = bx - cx;
49710           var acy = ay - cy;
49711           var bcy = by - cy;
49712           s1 = acx * bcy;
49713           c = splitter * acx;
49714           ahi = c - (c - acx);
49715           alo = acx - ahi;
49716           c = splitter * bcy;
49717           bhi = c - (c - bcy);
49718           blo = bcy - bhi;
49719           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49720           t1 = acy * bcx;
49721           c = splitter * acy;
49722           ahi = c - (c - acy);
49723           alo = acy - ahi;
49724           c = splitter * bcx;
49725           bhi = c - (c - bcx);
49726           blo = bcx - bhi;
49727           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49728           _i = s0 - t0;
49729           bvirt = s0 - _i;
49730           B[0] = s0 - (_i + bvirt) + (bvirt - t0);
49731           _j = s1 + _i;
49732           bvirt = _j - s1;
49733           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49734           _i = _0 - t1;
49735           bvirt = _0 - _i;
49736           B[1] = _0 - (_i + bvirt) + (bvirt - t1);
49737           u3 = _j + _i;
49738           bvirt = u3 - _j;
49739           B[2] = _j - (u3 - bvirt) + (_i - bvirt);
49740           B[3] = u3;
49741           var det = estimate(4, B);
49742           var errbound = ccwerrboundB * detsum;
49743
49744           if (det >= errbound || -det >= errbound) {
49745             return det;
49746           }
49747
49748           bvirt = ax - acx;
49749           acxtail = ax - (acx + bvirt) + (bvirt - cx);
49750           bvirt = bx - bcx;
49751           bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
49752           bvirt = ay - acy;
49753           acytail = ay - (acy + bvirt) + (bvirt - cy);
49754           bvirt = by - bcy;
49755           bcytail = by - (bcy + bvirt) + (bvirt - cy);
49756
49757           if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
49758             return det;
49759           }
49760
49761           errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
49762           det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
49763           if (det >= errbound || -det >= errbound) return det;
49764           s1 = acxtail * bcy;
49765           c = splitter * acxtail;
49766           ahi = c - (c - acxtail);
49767           alo = acxtail - ahi;
49768           c = splitter * bcy;
49769           bhi = c - (c - bcy);
49770           blo = bcy - bhi;
49771           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49772           t1 = acytail * bcx;
49773           c = splitter * acytail;
49774           ahi = c - (c - acytail);
49775           alo = acytail - ahi;
49776           c = splitter * bcx;
49777           bhi = c - (c - bcx);
49778           blo = bcx - bhi;
49779           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49780           _i = s0 - t0;
49781           bvirt = s0 - _i;
49782           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49783           _j = s1 + _i;
49784           bvirt = _j - s1;
49785           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49786           _i = _0 - t1;
49787           bvirt = _0 - _i;
49788           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49789           u3 = _j + _i;
49790           bvirt = u3 - _j;
49791           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49792           u[3] = u3;
49793           var C1len = sum(4, B, 4, u, C1);
49794           s1 = acx * bcytail;
49795           c = splitter * acx;
49796           ahi = c - (c - acx);
49797           alo = acx - ahi;
49798           c = splitter * bcytail;
49799           bhi = c - (c - bcytail);
49800           blo = bcytail - bhi;
49801           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49802           t1 = acy * bcxtail;
49803           c = splitter * acy;
49804           ahi = c - (c - acy);
49805           alo = acy - ahi;
49806           c = splitter * bcxtail;
49807           bhi = c - (c - bcxtail);
49808           blo = bcxtail - bhi;
49809           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49810           _i = s0 - t0;
49811           bvirt = s0 - _i;
49812           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49813           _j = s1 + _i;
49814           bvirt = _j - s1;
49815           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49816           _i = _0 - t1;
49817           bvirt = _0 - _i;
49818           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49819           u3 = _j + _i;
49820           bvirt = u3 - _j;
49821           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49822           u[3] = u3;
49823           var C2len = sum(C1len, C1, 4, u, C2);
49824           s1 = acxtail * bcytail;
49825           c = splitter * acxtail;
49826           ahi = c - (c - acxtail);
49827           alo = acxtail - ahi;
49828           c = splitter * bcytail;
49829           bhi = c - (c - bcytail);
49830           blo = bcytail - bhi;
49831           s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
49832           t1 = acytail * bcxtail;
49833           c = splitter * acytail;
49834           ahi = c - (c - acytail);
49835           alo = acytail - ahi;
49836           c = splitter * bcxtail;
49837           bhi = c - (c - bcxtail);
49838           blo = bcxtail - bhi;
49839           t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
49840           _i = s0 - t0;
49841           bvirt = s0 - _i;
49842           u[0] = s0 - (_i + bvirt) + (bvirt - t0);
49843           _j = s1 + _i;
49844           bvirt = _j - s1;
49845           _0 = s1 - (_j - bvirt) + (_i - bvirt);
49846           _i = _0 - t1;
49847           bvirt = _0 - _i;
49848           u[1] = _0 - (_i + bvirt) + (bvirt - t1);
49849           u3 = _j + _i;
49850           bvirt = u3 - _j;
49851           u[2] = _j - (u3 - bvirt) + (_i - bvirt);
49852           u[3] = u3;
49853           var Dlen = sum(C2len, C2, 4, u, D);
49854           return D[Dlen - 1];
49855         }
49856
49857         function orient2d(ax, ay, bx, by, cx, cy) {
49858           var detleft = (ay - cy) * (bx - cx);
49859           var detright = (ax - cx) * (by - cy);
49860           var det = detleft - detright;
49861           if (detleft === 0 || detright === 0 || detleft > 0 !== detright > 0) return det;
49862           var detsum = Math.abs(detleft + detright);
49863           if (Math.abs(det) >= ccwerrboundA * detsum) return det;
49864           return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
49865         }
49866
49867         /**
49868          * Signed area of the triangle (p0, p1, p2)
49869          * @param  {Array.<Number>} p0
49870          * @param  {Array.<Number>} p1
49871          * @param  {Array.<Number>} p2
49872          * @return {Number}
49873          */
49874
49875         function signedArea(p0, p1, p2) {
49876           var res = orient2d(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]);
49877           if (res > 0) return -1;
49878           if (res < 0) return 1;
49879           return 0;
49880         }
49881
49882         /**
49883          * @param  {SweepEvent} e1
49884          * @param  {SweepEvent} e2
49885          * @return {Number}
49886          */
49887
49888         function compareEvents(e1, e2) {
49889           var p1 = e1.point;
49890           var p2 = e2.point; // Different x-coordinate
49891
49892           if (p1[0] > p2[0]) return 1;
49893           if (p1[0] < p2[0]) return -1; // Different points, but same x-coordinate
49894           // Event with lower y-coordinate is processed first
49895
49896           if (p1[1] !== p2[1]) return p1[1] > p2[1] ? 1 : -1;
49897           return specialCases(e1, e2, p1);
49898         }
49899         /* eslint-disable no-unused-vars */
49900
49901         function specialCases(e1, e2, p1, p2) {
49902           // Same coordinates, but one is a left endpoint and the other is
49903           // a right endpoint. The right endpoint is processed first
49904           if (e1.left !== e2.left) return e1.left ? 1 : -1; // const p2 = e1.otherEvent.point, p3 = e2.otherEvent.point;
49905           // const sa = (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1])
49906           // Same coordinates, both events
49907           // are left endpoints or right endpoints.
49908           // not collinear
49909
49910           if (signedArea(p1, e1.otherEvent.point, e2.otherEvent.point) !== 0) {
49911             // the event associate to the bottom segment is processed first
49912             return !e1.isBelow(e2.otherEvent.point) ? 1 : -1;
49913           }
49914
49915           return !e1.isSubject && e2.isSubject ? 1 : -1;
49916         }
49917         /* eslint-enable no-unused-vars */
49918
49919         /**
49920          * @param  {SweepEvent} se
49921          * @param  {Array.<Number>} p
49922          * @param  {Queue} queue
49923          * @return {Queue}
49924          */
49925
49926         function divideSegment(se, p, queue) {
49927           var r = new SweepEvent(p, false, se, se.isSubject);
49928           var l = new SweepEvent(p, true, se.otherEvent, se.isSubject);
49929           /* eslint-disable no-console */
49930
49931           if (equals(se.point, se.otherEvent.point)) {
49932             console.warn('what is that, a collapsed segment?', se);
49933           }
49934           /* eslint-enable no-console */
49935
49936
49937           r.contourId = l.contourId = se.contourId; // avoid a rounding error. The left event would be processed after the right event
49938
49939           if (compareEvents(l, se.otherEvent) > 0) {
49940             se.otherEvent.left = true;
49941             l.left = false;
49942           } // avoid a rounding error. The left event would be processed after the right event
49943           // if (compareEvents(se, r) > 0) {}
49944
49945
49946           se.otherEvent.otherEvent = l;
49947           se.otherEvent = r;
49948           queue.push(l);
49949           queue.push(r);
49950           return queue;
49951         }
49952
49953         //const EPS = 1e-9;
49954
49955         /**
49956          * Finds the magnitude of the cross product of two vectors (if we pretend
49957          * they're in three dimensions)
49958          *
49959          * @param {Object} a First vector
49960          * @param {Object} b Second vector
49961          * @private
49962          * @returns {Number} The magnitude of the cross product
49963          */
49964         function crossProduct(a, b) {
49965           return a[0] * b[1] - a[1] * b[0];
49966         }
49967         /**
49968          * Finds the dot product of two vectors.
49969          *
49970          * @param {Object} a First vector
49971          * @param {Object} b Second vector
49972          * @private
49973          * @returns {Number} The dot product
49974          */
49975
49976
49977         function dotProduct(a, b) {
49978           return a[0] * b[0] + a[1] * b[1];
49979         }
49980         /**
49981          * Finds the intersection (if any) between two line segments a and b, given the
49982          * line segments' end points a1, a2 and b1, b2.
49983          *
49984          * This algorithm is based on Schneider and Eberly.
49985          * http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf
49986          * Page 244.
49987          *
49988          * @param {Array.<Number>} a1 point of first line
49989          * @param {Array.<Number>} a2 point of first line
49990          * @param {Array.<Number>} b1 point of second line
49991          * @param {Array.<Number>} b2 point of second line
49992          * @param {Boolean=}       noEndpointTouch whether to skip single touchpoints
49993          *                                         (meaning connected segments) as
49994          *                                         intersections
49995          * @returns {Array.<Array.<Number>>|Null} If the lines intersect, the point of
49996          * intersection. If they overlap, the two end points of the overlapping segment.
49997          * Otherwise, null.
49998          */
49999
50000
50001         function intersection (a1, a2, b1, b2, noEndpointTouch) {
50002           // The algorithm expects our lines in the form P + sd, where P is a point,
50003           // s is on the interval [0, 1], and d is a vector.
50004           // We are passed two points. P can be the first point of each pair. The
50005           // vector, then, could be thought of as the distance (in x and y components)
50006           // from the first point to the second point.
50007           // So first, let's make our vectors:
50008           var va = [a2[0] - a1[0], a2[1] - a1[1]];
50009           var vb = [b2[0] - b1[0], b2[1] - b1[1]]; // We also define a function to convert back to regular point form:
50010
50011           /* eslint-disable arrow-body-style */
50012
50013           function toPoint(p, s, d) {
50014             return [p[0] + s * d[0], p[1] + s * d[1]];
50015           }
50016           /* eslint-enable arrow-body-style */
50017           // The rest is pretty much a straight port of the algorithm.
50018
50019
50020           var e = [b1[0] - a1[0], b1[1] - a1[1]];
50021           var kross = crossProduct(va, vb);
50022           var sqrKross = kross * kross;
50023           var sqrLenA = dotProduct(va, va); //const sqrLenB  = dotProduct(vb, vb);
50024           // Check for line intersection. This works because of the properties of the
50025           // cross product -- specifically, two vectors are parallel if and only if the
50026           // cross product is the 0 vector. The full calculation involves relative error
50027           // to account for possible very small line segments. See Schneider & Eberly
50028           // for details.
50029
50030           if (sqrKross > 0
50031           /* EPS * sqrLenB * sqLenA */
50032           ) {
50033               // If they're not parallel, then (because these are line segments) they
50034               // still might not actually intersect. This code checks that the
50035               // intersection point of the lines is actually on both line segments.
50036               var s = crossProduct(e, vb) / kross;
50037
50038               if (s < 0 || s > 1) {
50039                 // not on line segment a
50040                 return null;
50041               }
50042
50043               var t = crossProduct(e, va) / kross;
50044
50045               if (t < 0 || t > 1) {
50046                 // not on line segment b
50047                 return null;
50048               }
50049
50050               if (s === 0 || s === 1) {
50051                 // on an endpoint of line segment a
50052                 return noEndpointTouch ? null : [toPoint(a1, s, va)];
50053               }
50054
50055               if (t === 0 || t === 1) {
50056                 // on an endpoint of line segment b
50057                 return noEndpointTouch ? null : [toPoint(b1, t, vb)];
50058               }
50059
50060               return [toPoint(a1, s, va)];
50061             } // If we've reached this point, then the lines are either parallel or the
50062           // same, but the segments could overlap partially or fully, or not at all.
50063           // So we need to find the overlap, if any. To do that, we can use e, which is
50064           // the (vector) difference between the two initial points. If this is parallel
50065           // with the line itself, then the two lines are the same line, and there will
50066           // be overlap.
50067           //const sqrLenE = dotProduct(e, e);
50068
50069
50070           kross = crossProduct(e, va);
50071           sqrKross = kross * kross;
50072
50073           if (sqrKross > 0
50074           /* EPS * sqLenB * sqLenE */
50075           ) {
50076               // Lines are just parallel, not the same. No overlap.
50077               return null;
50078             }
50079
50080           var sa = dotProduct(va, e) / sqrLenA;
50081           var sb = sa + dotProduct(va, vb) / sqrLenA;
50082           var smin = Math.min(sa, sb);
50083           var smax = Math.max(sa, sb); // this is, essentially, the FindIntersection acting on floats from
50084           // Schneider & Eberly, just inlined into this function.
50085
50086           if (smin <= 1 && smax >= 0) {
50087             // overlap on an end point
50088             if (smin === 1) {
50089               return noEndpointTouch ? null : [toPoint(a1, smin > 0 ? smin : 0, va)];
50090             }
50091
50092             if (smax === 0) {
50093               return noEndpointTouch ? null : [toPoint(a1, smax < 1 ? smax : 1, va)];
50094             }
50095
50096             if (noEndpointTouch && smin === 0 && smax === 1) return null; // There's overlap on a segment -- two points of intersection. Return both.
50097
50098             return [toPoint(a1, smin > 0 ? smin : 0, va), toPoint(a1, smax < 1 ? smax : 1, va)];
50099           }
50100
50101           return null;
50102         }
50103
50104         /**
50105          * @param  {SweepEvent} se1
50106          * @param  {SweepEvent} se2
50107          * @param  {Queue}      queue
50108          * @return {Number}
50109          */
50110
50111         function possibleIntersection(se1, se2, queue) {
50112           // that disallows self-intersecting polygons,
50113           // did cost us half a day, so I'll leave it
50114           // out of respect
50115           // if (se1.isSubject === se2.isSubject) return;
50116           var inter = intersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
50117           var nintersections = inter ? inter.length : 0;
50118           if (nintersections === 0) return 0; // no intersection
50119           // the line segments intersect at an endpoint of both line segments
50120
50121           if (nintersections === 1 && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point))) {
50122             return 0;
50123           }
50124
50125           if (nintersections === 2 && se1.isSubject === se2.isSubject) {
50126             // if(se1.contourId === se2.contourId){
50127             // console.warn('Edges of the same polygon overlap',
50128             //   se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point);
50129             // }
50130             //throw new Error('Edges of the same polygon overlap');
50131             return 0;
50132           } // The line segments associated to se1 and se2 intersect
50133
50134
50135           if (nintersections === 1) {
50136             // if the intersection point is not an endpoint of se1
50137             if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) {
50138               divideSegment(se1, inter[0], queue);
50139             } // if the intersection point is not an endpoint of se2
50140
50141
50142             if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) {
50143               divideSegment(se2, inter[0], queue);
50144             }
50145
50146             return 1;
50147           } // The line segments associated to se1 and se2 overlap
50148
50149
50150           var events = [];
50151           var leftCoincide = false;
50152           var rightCoincide = false;
50153
50154           if (equals(se1.point, se2.point)) {
50155             leftCoincide = true; // linked
50156           } else if (compareEvents(se1, se2) === 1) {
50157             events.push(se2, se1);
50158           } else {
50159             events.push(se1, se2);
50160           }
50161
50162           if (equals(se1.otherEvent.point, se2.otherEvent.point)) {
50163             rightCoincide = true;
50164           } else if (compareEvents(se1.otherEvent, se2.otherEvent) === 1) {
50165             events.push(se2.otherEvent, se1.otherEvent);
50166           } else {
50167             events.push(se1.otherEvent, se2.otherEvent);
50168           }
50169
50170           if (leftCoincide && rightCoincide || leftCoincide) {
50171             // both line segments are equal or share the left endpoint
50172             se2.type = NON_CONTRIBUTING;
50173             se1.type = se2.inOut === se1.inOut ? SAME_TRANSITION : DIFFERENT_TRANSITION;
50174
50175             if (leftCoincide && !rightCoincide) {
50176               // honestly no idea, but changing events selection from [2, 1]
50177               // to [0, 1] fixes the overlapping self-intersecting polygons issue
50178               divideSegment(events[1].otherEvent, events[0].point, queue);
50179             }
50180
50181             return 2;
50182           } // the line segments share the right endpoint
50183
50184
50185           if (rightCoincide) {
50186             divideSegment(events[0], events[1].point, queue);
50187             return 3;
50188           } // no line segment includes totally the other one
50189
50190
50191           if (events[0] !== events[3].otherEvent) {
50192             divideSegment(events[0], events[1].point, queue);
50193             divideSegment(events[1], events[2].point, queue);
50194             return 3;
50195           } // one line segment includes the other one
50196
50197
50198           divideSegment(events[0], events[1].point, queue);
50199           divideSegment(events[3].otherEvent, events[2].point, queue);
50200           return 3;
50201         }
50202
50203         /**
50204          * @param  {SweepEvent} le1
50205          * @param  {SweepEvent} le2
50206          * @return {Number}
50207          */
50208
50209         function compareSegments(le1, le2) {
50210           if (le1 === le2) return 0; // Segments are not collinear
50211
50212           if (signedArea(le1.point, le1.otherEvent.point, le2.point) !== 0 || signedArea(le1.point, le1.otherEvent.point, le2.otherEvent.point) !== 0) {
50213             // If they share their left endpoint use the right endpoint to sort
50214             if (equals(le1.point, le2.point)) return le1.isBelow(le2.otherEvent.point) ? -1 : 1; // Different left endpoint: use the left endpoint to sort
50215
50216             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
50217             // into S after the line segment associated to e2 ?
50218
50219             if (compareEvents(le1, le2) === 1) return le2.isAbove(le1.point) ? -1 : 1; // The line segment associated to e2 has been inserted
50220             // into S after the line segment associated to e1
50221
50222             return le1.isBelow(le2.point) ? -1 : 1;
50223           }
50224
50225           if (le1.isSubject === le2.isSubject) {
50226             // same polygon
50227             var p1 = le1.point,
50228                 p2 = le2.point;
50229
50230             if (p1[0] === p2[0] && p1[1] === p2[1]
50231             /*equals(le1.point, le2.point)*/
50232             ) {
50233                 p1 = le1.otherEvent.point;
50234                 p2 = le2.otherEvent.point;
50235                 if (p1[0] === p2[0] && p1[1] === p2[1]) return 0;else return le1.contourId > le2.contourId ? 1 : -1;
50236               }
50237           } else {
50238             // Segments are collinear, but belong to separate polygons
50239             return le1.isSubject ? -1 : 1;
50240           }
50241
50242           return compareEvents(le1, le2) === 1 ? 1 : -1;
50243         }
50244
50245         function subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation) {
50246           var sweepLine = new SplayTree(compareSegments);
50247           var sortedEvents = [];
50248           var rightbound = Math.min(sbbox[2], cbbox[2]);
50249           var prev, next, begin;
50250
50251           while (eventQueue.length !== 0) {
50252             var event = eventQueue.pop();
50253             sortedEvents.push(event); // optimization by bboxes for intersection and difference goes here
50254
50255             if (operation === INTERSECTION && event.point[0] > rightbound || operation === DIFFERENCE && event.point[0] > sbbox[2]) {
50256               break;
50257             }
50258
50259             if (event.left) {
50260               next = prev = sweepLine.insert(event);
50261               begin = sweepLine.minNode();
50262               if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
50263               next = sweepLine.next(next);
50264               var prevEvent = prev ? prev.key : null;
50265               var prevprevEvent = void 0;
50266               computeFields(event, prevEvent, operation);
50267
50268               if (next) {
50269                 if (possibleIntersection(event, next.key, eventQueue) === 2) {
50270                   computeFields(event, prevEvent, operation);
50271                   computeFields(event, next.key, operation);
50272                 }
50273               }
50274
50275               if (prev) {
50276                 if (possibleIntersection(prev.key, event, eventQueue) === 2) {
50277                   var prevprev = prev;
50278                   if (prevprev !== begin) prevprev = sweepLine.prev(prevprev);else prevprev = null;
50279                   prevprevEvent = prevprev ? prevprev.key : null;
50280                   computeFields(prevEvent, prevprevEvent, operation);
50281                   computeFields(event, prevEvent, operation);
50282                 }
50283               }
50284             } else {
50285               event = event.otherEvent;
50286               next = prev = sweepLine.find(event);
50287
50288               if (prev && next) {
50289                 if (prev !== begin) prev = sweepLine.prev(prev);else prev = null;
50290                 next = sweepLine.next(next);
50291                 sweepLine.remove(event);
50292
50293                 if (next && prev) {
50294                   possibleIntersection(prev.key, next.key, eventQueue);
50295                 }
50296               }
50297             }
50298           }
50299
50300           return sortedEvents;
50301         }
50302
50303         var Contour = /*#__PURE__*/function () {
50304           /**
50305            * Contour
50306            *
50307            * @class {Contour}
50308            */
50309           function Contour() {
50310             _classCallCheck(this, Contour);
50311
50312             this.points = [];
50313             this.holeIds = [];
50314             this.holeOf = null;
50315             this.depth = null;
50316           }
50317
50318           _createClass(Contour, [{
50319             key: "isExterior",
50320             value: function isExterior() {
50321               return this.holeOf == null;
50322             }
50323           }]);
50324
50325           return Contour;
50326         }();
50327
50328         /**
50329          * @param  {Array.<SweepEvent>} sortedEvents
50330          * @return {Array.<SweepEvent>}
50331          */
50332
50333         function orderEvents(sortedEvents) {
50334           var event, i, len, tmp;
50335           var resultEvents = [];
50336
50337           for (i = 0, len = sortedEvents.length; i < len; i++) {
50338             event = sortedEvents[i];
50339
50340             if (event.left && event.inResult || !event.left && event.otherEvent.inResult) {
50341               resultEvents.push(event);
50342             }
50343           } // Due to overlapping edges the resultEvents array can be not wholly sorted
50344
50345
50346           var sorted = false;
50347
50348           while (!sorted) {
50349             sorted = true;
50350
50351             for (i = 0, len = resultEvents.length; i < len; i++) {
50352               if (i + 1 < len && compareEvents(resultEvents[i], resultEvents[i + 1]) === 1) {
50353                 tmp = resultEvents[i];
50354                 resultEvents[i] = resultEvents[i + 1];
50355                 resultEvents[i + 1] = tmp;
50356                 sorted = false;
50357               }
50358             }
50359           }
50360
50361           for (i = 0, len = resultEvents.length; i < len; i++) {
50362             event = resultEvents[i];
50363             event.otherPos = i;
50364           } // imagine, the right event is found in the beginning of the queue,
50365           // when his left counterpart is not marked yet
50366
50367
50368           for (i = 0, len = resultEvents.length; i < len; i++) {
50369             event = resultEvents[i];
50370
50371             if (!event.left) {
50372               tmp = event.otherPos;
50373               event.otherPos = event.otherEvent.otherPos;
50374               event.otherEvent.otherPos = tmp;
50375             }
50376           }
50377
50378           return resultEvents;
50379         }
50380         /**
50381          * @param  {Number} pos
50382          * @param  {Array.<SweepEvent>} resultEvents
50383          * @param  {Object>}    processed
50384          * @return {Number}
50385          */
50386
50387
50388         function nextPos(pos, resultEvents, processed, origPos) {
50389           var newPos = pos + 1,
50390               p = resultEvents[pos].point,
50391               p1;
50392           var length = resultEvents.length;
50393           if (newPos < length) p1 = resultEvents[newPos].point;
50394
50395           while (newPos < length && p1[0] === p[0] && p1[1] === p[1]) {
50396             if (!processed[newPos]) {
50397               return newPos;
50398             } else {
50399               newPos++;
50400             }
50401
50402             p1 = resultEvents[newPos].point;
50403           }
50404
50405           newPos = pos - 1;
50406
50407           while (processed[newPos] && newPos > origPos) {
50408             newPos--;
50409           }
50410
50411           return newPos;
50412         }
50413
50414         function initializeContourFromContext(event, contours, contourId) {
50415           var contour = new Contour();
50416
50417           if (event.prevInResult != null) {
50418             var prevInResult = event.prevInResult; // Note that it is valid to query the "previous in result" for its output contour id,
50419             // because we must have already processed it (i.e., assigned an output contour id)
50420             // in an earlier iteration, otherwise it wouldn't be possible that it is "previous in
50421             // result".
50422
50423             var lowerContourId = prevInResult.outputContourId;
50424             var lowerResultTransition = prevInResult.resultTransition;
50425
50426             if (lowerResultTransition > 0) {
50427               // We are inside. Now we have to check if the thing below us is another hole or
50428               // an exterior contour.
50429               var lowerContour = contours[lowerContourId];
50430
50431               if (lowerContour.holeOf != null) {
50432                 // The lower contour is a hole => Connect the new contour as a hole to its parent,
50433                 // and use same depth.
50434                 var parentContourId = lowerContour.holeOf;
50435                 contours[parentContourId].holeIds.push(contourId);
50436                 contour.holeOf = parentContourId;
50437                 contour.depth = contours[lowerContourId].depth;
50438               } else {
50439                 // The lower contour is an exterior contour => Connect the new contour as a hole,
50440                 // and increment depth.
50441                 contours[lowerContourId].holeIds.push(contourId);
50442                 contour.holeOf = lowerContourId;
50443                 contour.depth = contours[lowerContourId].depth + 1;
50444               }
50445             } else {
50446               // We are outside => this contour is an exterior contour of same depth.
50447               contour.holeOf = null;
50448               contour.depth = contours[lowerContourId].depth;
50449             }
50450           } else {
50451             // There is no lower/previous contour => this contour is an exterior contour of depth 0.
50452             contour.holeOf = null;
50453             contour.depth = 0;
50454           }
50455
50456           return contour;
50457         }
50458         /**
50459          * @param  {Array.<SweepEvent>} sortedEvents
50460          * @return {Array.<*>} polygons
50461          */
50462
50463
50464         function connectEdges(sortedEvents) {
50465           var i, len;
50466           var resultEvents = orderEvents(sortedEvents); // "false"-filled array
50467
50468           var processed = {};
50469           var contours = [];
50470
50471           var _loop = function _loop() {
50472             if (processed[i]) {
50473               return "continue";
50474             }
50475
50476             var contourId = contours.length;
50477             var contour = initializeContourFromContext(resultEvents[i], contours, contourId); // Helper function that combines marking an event as processed with assigning its output contour ID
50478
50479             var markAsProcessed = function markAsProcessed(pos) {
50480               processed[pos] = true;
50481               resultEvents[pos].outputContourId = contourId;
50482             };
50483
50484             var pos = i;
50485             var origPos = i;
50486             var initial = resultEvents[i].point;
50487             contour.points.push(initial);
50488             /* eslint no-constant-condition: "off" */
50489
50490             while (true) {
50491               markAsProcessed(pos);
50492               pos = resultEvents[pos].otherPos;
50493               markAsProcessed(pos);
50494               contour.points.push(resultEvents[pos].point);
50495               pos = nextPos(pos, resultEvents, processed, origPos);
50496
50497               if (pos == origPos) {
50498                 break;
50499               }
50500             }
50501
50502             contours.push(contour);
50503           };
50504
50505           for (i = 0, len = resultEvents.length; i < len; i++) {
50506             var _ret = _loop();
50507
50508             if (_ret === "continue") continue;
50509           }
50510
50511           return contours;
50512         }
50513
50514         var tinyqueue = TinyQueue;
50515         var _default$1 = TinyQueue;
50516
50517         function TinyQueue(data, compare) {
50518           if (!(this instanceof TinyQueue)) return new TinyQueue(data, compare);
50519           this.data = data || [];
50520           this.length = this.data.length;
50521           this.compare = compare || defaultCompare$1;
50522
50523           if (this.length > 0) {
50524             for (var i = (this.length >> 1) - 1; i >= 0; i--) {
50525               this._down(i);
50526             }
50527           }
50528         }
50529
50530         function defaultCompare$1(a, b) {
50531           return a < b ? -1 : a > b ? 1 : 0;
50532         }
50533
50534         TinyQueue.prototype = {
50535           push: function push(item) {
50536             this.data.push(item);
50537             this.length++;
50538
50539             this._up(this.length - 1);
50540           },
50541           pop: function pop() {
50542             if (this.length === 0) return undefined;
50543             var top = this.data[0];
50544             this.length--;
50545
50546             if (this.length > 0) {
50547               this.data[0] = this.data[this.length];
50548
50549               this._down(0);
50550             }
50551
50552             this.data.pop();
50553             return top;
50554           },
50555           peek: function peek() {
50556             return this.data[0];
50557           },
50558           _up: function _up(pos) {
50559             var data = this.data;
50560             var compare = this.compare;
50561             var item = data[pos];
50562
50563             while (pos > 0) {
50564               var parent = pos - 1 >> 1;
50565               var current = data[parent];
50566               if (compare(item, current) >= 0) break;
50567               data[pos] = current;
50568               pos = parent;
50569             }
50570
50571             data[pos] = item;
50572           },
50573           _down: function _down(pos) {
50574             var data = this.data;
50575             var compare = this.compare;
50576             var halfLength = this.length >> 1;
50577             var item = data[pos];
50578
50579             while (pos < halfLength) {
50580               var left = (pos << 1) + 1;
50581               var right = left + 1;
50582               var best = data[left];
50583
50584               if (right < this.length && compare(data[right], best) < 0) {
50585                 left = right;
50586                 best = data[right];
50587               }
50588
50589               if (compare(best, item) >= 0) break;
50590               data[pos] = best;
50591               pos = left;
50592             }
50593
50594             data[pos] = item;
50595           }
50596         };
50597         tinyqueue["default"] = _default$1;
50598
50599         var max$5 = Math.max;
50600         var min$a = Math.min;
50601         var contourId = 0;
50602
50603         function processPolygon(contourOrHole, isSubject, depth, Q, bbox, isExteriorRing) {
50604           var i, len, s1, s2, e1, e2;
50605
50606           for (i = 0, len = contourOrHole.length - 1; i < len; i++) {
50607             s1 = contourOrHole[i];
50608             s2 = contourOrHole[i + 1];
50609             e1 = new SweepEvent(s1, false, undefined, isSubject);
50610             e2 = new SweepEvent(s2, false, e1, isSubject);
50611             e1.otherEvent = e2;
50612
50613             if (s1[0] === s2[0] && s1[1] === s2[1]) {
50614               continue; // skip collapsed edges, or it breaks
50615             }
50616
50617             e1.contourId = e2.contourId = depth;
50618
50619             if (!isExteriorRing) {
50620               e1.isExteriorRing = false;
50621               e2.isExteriorRing = false;
50622             }
50623
50624             if (compareEvents(e1, e2) > 0) {
50625               e2.left = true;
50626             } else {
50627               e1.left = true;
50628             }
50629
50630             var x = s1[0],
50631                 y = s1[1];
50632             bbox[0] = min$a(bbox[0], x);
50633             bbox[1] = min$a(bbox[1], y);
50634             bbox[2] = max$5(bbox[2], x);
50635             bbox[3] = max$5(bbox[3], y); // Pushing it so the queue is sorted from left to right,
50636             // with object on the left having the highest priority.
50637
50638             Q.push(e1);
50639             Q.push(e2);
50640           }
50641         }
50642
50643         function fillQueue(subject, clipping, sbbox, cbbox, operation) {
50644           var eventQueue = new tinyqueue(null, compareEvents);
50645           var polygonSet, isExteriorRing, i, ii, j, jj; //, k, kk;
50646
50647           for (i = 0, ii = subject.length; i < ii; i++) {
50648             polygonSet = subject[i];
50649
50650             for (j = 0, jj = polygonSet.length; j < jj; j++) {
50651               isExteriorRing = j === 0;
50652               if (isExteriorRing) contourId++;
50653               processPolygon(polygonSet[j], true, contourId, eventQueue, sbbox, isExteriorRing);
50654             }
50655           }
50656
50657           for (i = 0, ii = clipping.length; i < ii; i++) {
50658             polygonSet = clipping[i];
50659
50660             for (j = 0, jj = polygonSet.length; j < jj; j++) {
50661               isExteriorRing = j === 0;
50662               if (operation === DIFFERENCE) isExteriorRing = false;
50663               if (isExteriorRing) contourId++;
50664               processPolygon(polygonSet[j], false, contourId, eventQueue, cbbox, isExteriorRing);
50665             }
50666           }
50667
50668           return eventQueue;
50669         }
50670
50671         var EMPTY = [];
50672
50673         function trivialOperation(subject, clipping, operation) {
50674           var result = null;
50675
50676           if (subject.length * clipping.length === 0) {
50677             if (operation === INTERSECTION) {
50678               result = EMPTY;
50679             } else if (operation === DIFFERENCE) {
50680               result = subject;
50681             } else if (operation === UNION || operation === XOR) {
50682               result = subject.length === 0 ? clipping : subject;
50683             }
50684           }
50685
50686           return result;
50687         }
50688
50689         function compareBBoxes(subject, clipping, sbbox, cbbox, operation) {
50690           var result = null;
50691
50692           if (sbbox[0] > cbbox[2] || cbbox[0] > sbbox[2] || sbbox[1] > cbbox[3] || cbbox[1] > sbbox[3]) {
50693             if (operation === INTERSECTION) {
50694               result = EMPTY;
50695             } else if (operation === DIFFERENCE) {
50696               result = subject;
50697             } else if (operation === UNION || operation === XOR) {
50698               result = subject.concat(clipping);
50699             }
50700           }
50701
50702           return result;
50703         }
50704
50705         function _boolean(subject, clipping, operation) {
50706           if (typeof subject[0][0][0] === 'number') {
50707             subject = [subject];
50708           }
50709
50710           if (typeof clipping[0][0][0] === 'number') {
50711             clipping = [clipping];
50712           }
50713
50714           var trivial = trivialOperation(subject, clipping, operation);
50715
50716           if (trivial) {
50717             return trivial === EMPTY ? null : trivial;
50718           }
50719
50720           var sbbox = [Infinity, Infinity, -Infinity, -Infinity];
50721           var cbbox = [Infinity, Infinity, -Infinity, -Infinity]; // console.time('fill queue');
50722
50723           var eventQueue = fillQueue(subject, clipping, sbbox, cbbox, operation); //console.timeEnd('fill queue');
50724
50725           trivial = compareBBoxes(subject, clipping, sbbox, cbbox, operation);
50726
50727           if (trivial) {
50728             return trivial === EMPTY ? null : trivial;
50729           } // console.time('subdivide edges');
50730
50731
50732           var sortedEvents = subdivide(eventQueue, subject, clipping, sbbox, cbbox, operation); //console.timeEnd('subdivide edges');
50733           // console.time('connect vertices');
50734
50735           var contours = connectEdges(sortedEvents); //console.timeEnd('connect vertices');
50736           // Convert contours to polygons
50737
50738           var polygons = [];
50739
50740           for (var i = 0; i < contours.length; i++) {
50741             var contour = contours[i];
50742
50743             if (contour.isExterior()) {
50744               // The exterior ring goes first
50745               var rings = [contour.points]; // Followed by holes if any
50746
50747               for (var j = 0; j < contour.holeIds.length; j++) {
50748                 var holeId = contour.holeIds[j];
50749                 rings.push(contours[holeId].points);
50750               }
50751
50752               polygons.push(rings);
50753             }
50754           }
50755
50756           return polygons;
50757         }
50758
50759         function union(subject, clipping) {
50760           return _boolean(subject, clipping, UNION);
50761         }
50762
50763         /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
50764         var read$6 = function read(buffer, offset, isLE, mLen, nBytes) {
50765           var e, m;
50766           var eLen = nBytes * 8 - mLen - 1;
50767           var eMax = (1 << eLen) - 1;
50768           var eBias = eMax >> 1;
50769           var nBits = -7;
50770           var i = isLE ? nBytes - 1 : 0;
50771           var d = isLE ? -1 : 1;
50772           var s = buffer[offset + i];
50773           i += d;
50774           e = s & (1 << -nBits) - 1;
50775           s >>= -nBits;
50776           nBits += eLen;
50777
50778           for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50779
50780           m = e & (1 << -nBits) - 1;
50781           e >>= -nBits;
50782           nBits += mLen;
50783
50784           for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50785
50786           if (e === 0) {
50787             e = 1 - eBias;
50788           } else if (e === eMax) {
50789             return m ? NaN : (s ? -1 : 1) * Infinity;
50790           } else {
50791             m = m + Math.pow(2, mLen);
50792             e = e - eBias;
50793           }
50794
50795           return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
50796         };
50797
50798         var write$6 = function write(buffer, value, offset, isLE, mLen, nBytes) {
50799           var e, m, c;
50800           var eLen = nBytes * 8 - mLen - 1;
50801           var eMax = (1 << eLen) - 1;
50802           var eBias = eMax >> 1;
50803           var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
50804           var i = isLE ? 0 : nBytes - 1;
50805           var d = isLE ? 1 : -1;
50806           var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
50807           value = Math.abs(value);
50808
50809           if (isNaN(value) || value === Infinity) {
50810             m = isNaN(value) ? 1 : 0;
50811             e = eMax;
50812           } else {
50813             e = Math.floor(Math.log(value) / Math.LN2);
50814
50815             if (value * (c = Math.pow(2, -e)) < 1) {
50816               e--;
50817               c *= 2;
50818             }
50819
50820             if (e + eBias >= 1) {
50821               value += rt / c;
50822             } else {
50823               value += rt * Math.pow(2, 1 - eBias);
50824             }
50825
50826             if (value * c >= 2) {
50827               e++;
50828               c /= 2;
50829             }
50830
50831             if (e + eBias >= eMax) {
50832               m = 0;
50833               e = eMax;
50834             } else if (e + eBias >= 1) {
50835               m = (value * c - 1) * Math.pow(2, mLen);
50836               e = e + eBias;
50837             } else {
50838               m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
50839               e = 0;
50840             }
50841           }
50842
50843           for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
50844
50845           e = e << mLen | m;
50846           eLen += mLen;
50847
50848           for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
50849
50850           buffer[offset + i - d] |= s * 128;
50851         };
50852
50853         var ieee754$1 = {
50854           read: read$6,
50855           write: write$6
50856         };
50857
50858         var pbf = Pbf;
50859
50860         function Pbf(buf) {
50861           this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
50862           this.pos = 0;
50863           this.type = 0;
50864           this.length = this.buf.length;
50865         }
50866
50867         Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
50868
50869         Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
50870
50871         Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
50872
50873         Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
50874
50875         var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
50876             SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
50877         // data structures (which currently switch structure types at 12 bytes or more)
50878
50879         var TEXT_DECODER_MIN_LENGTH = 12;
50880         var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
50881         Pbf.prototype = {
50882           destroy: function destroy() {
50883             this.buf = null;
50884           },
50885           // === READING =================================================================
50886           readFields: function readFields(readField, result, end) {
50887             end = end || this.length;
50888
50889             while (this.pos < end) {
50890               var val = this.readVarint(),
50891                   tag = val >> 3,
50892                   startPos = this.pos;
50893               this.type = val & 0x7;
50894               readField(tag, result, this);
50895               if (this.pos === startPos) this.skip(val);
50896             }
50897
50898             return result;
50899           },
50900           readMessage: function readMessage(readField, result) {
50901             return this.readFields(readField, result, this.readVarint() + this.pos);
50902           },
50903           readFixed32: function readFixed32() {
50904             var val = readUInt32(this.buf, this.pos);
50905             this.pos += 4;
50906             return val;
50907           },
50908           readSFixed32: function readSFixed32() {
50909             var val = readInt32(this.buf, this.pos);
50910             this.pos += 4;
50911             return val;
50912           },
50913           // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
50914           readFixed64: function readFixed64() {
50915             var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50916             this.pos += 8;
50917             return val;
50918           },
50919           readSFixed64: function readSFixed64() {
50920             var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50921             this.pos += 8;
50922             return val;
50923           },
50924           readFloat: function readFloat() {
50925             var val = ieee754$1.read(this.buf, this.pos, true, 23, 4);
50926             this.pos += 4;
50927             return val;
50928           },
50929           readDouble: function readDouble() {
50930             var val = ieee754$1.read(this.buf, this.pos, true, 52, 8);
50931             this.pos += 8;
50932             return val;
50933           },
50934           readVarint: function readVarint(isSigned) {
50935             var buf = this.buf,
50936                 val,
50937                 b;
50938             b = buf[this.pos++];
50939             val = b & 0x7f;
50940             if (b < 0x80) return val;
50941             b = buf[this.pos++];
50942             val |= (b & 0x7f) << 7;
50943             if (b < 0x80) return val;
50944             b = buf[this.pos++];
50945             val |= (b & 0x7f) << 14;
50946             if (b < 0x80) return val;
50947             b = buf[this.pos++];
50948             val |= (b & 0x7f) << 21;
50949             if (b < 0x80) return val;
50950             b = buf[this.pos];
50951             val |= (b & 0x0f) << 28;
50952             return readVarintRemainder(val, isSigned, this);
50953           },
50954           readVarint64: function readVarint64() {
50955             // for compatibility with v2.0.1
50956             return this.readVarint(true);
50957           },
50958           readSVarint: function readSVarint() {
50959             var num = this.readVarint();
50960             return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
50961           },
50962           readBoolean: function readBoolean() {
50963             return Boolean(this.readVarint());
50964           },
50965           readString: function readString() {
50966             var end = this.readVarint() + this.pos;
50967             var pos = this.pos;
50968             this.pos = end;
50969
50970             if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
50971               // longer strings are fast with the built-in browser TextDecoder API
50972               return readUtf8TextDecoder(this.buf, pos, end);
50973             } // short strings are fast with our custom implementation
50974
50975
50976             return readUtf8(this.buf, pos, end);
50977           },
50978           readBytes: function readBytes() {
50979             var end = this.readVarint() + this.pos,
50980                 buffer = this.buf.subarray(this.pos, end);
50981             this.pos = end;
50982             return buffer;
50983           },
50984           // verbose for performance reasons; doesn't affect gzipped size
50985           readPackedVarint: function readPackedVarint(arr, isSigned) {
50986             if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
50987             var end = readPackedEnd(this);
50988             arr = arr || [];
50989
50990             while (this.pos < end) {
50991               arr.push(this.readVarint(isSigned));
50992             }
50993
50994             return arr;
50995           },
50996           readPackedSVarint: function readPackedSVarint(arr) {
50997             if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
50998             var end = readPackedEnd(this);
50999             arr = arr || [];
51000
51001             while (this.pos < end) {
51002               arr.push(this.readSVarint());
51003             }
51004
51005             return arr;
51006           },
51007           readPackedBoolean: function readPackedBoolean(arr) {
51008             if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
51009             var end = readPackedEnd(this);
51010             arr = arr || [];
51011
51012             while (this.pos < end) {
51013               arr.push(this.readBoolean());
51014             }
51015
51016             return arr;
51017           },
51018           readPackedFloat: function readPackedFloat(arr) {
51019             if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
51020             var end = readPackedEnd(this);
51021             arr = arr || [];
51022
51023             while (this.pos < end) {
51024               arr.push(this.readFloat());
51025             }
51026
51027             return arr;
51028           },
51029           readPackedDouble: function readPackedDouble(arr) {
51030             if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
51031             var end = readPackedEnd(this);
51032             arr = arr || [];
51033
51034             while (this.pos < end) {
51035               arr.push(this.readDouble());
51036             }
51037
51038             return arr;
51039           },
51040           readPackedFixed32: function readPackedFixed32(arr) {
51041             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
51042             var end = readPackedEnd(this);
51043             arr = arr || [];
51044
51045             while (this.pos < end) {
51046               arr.push(this.readFixed32());
51047             }
51048
51049             return arr;
51050           },
51051           readPackedSFixed32: function readPackedSFixed32(arr) {
51052             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
51053             var end = readPackedEnd(this);
51054             arr = arr || [];
51055
51056             while (this.pos < end) {
51057               arr.push(this.readSFixed32());
51058             }
51059
51060             return arr;
51061           },
51062           readPackedFixed64: function readPackedFixed64(arr) {
51063             if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
51064             var end = readPackedEnd(this);
51065             arr = arr || [];
51066
51067             while (this.pos < end) {
51068               arr.push(this.readFixed64());
51069             }
51070
51071             return arr;
51072           },
51073           readPackedSFixed64: function readPackedSFixed64(arr) {
51074             if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
51075             var end = readPackedEnd(this);
51076             arr = arr || [];
51077
51078             while (this.pos < end) {
51079               arr.push(this.readSFixed64());
51080             }
51081
51082             return arr;
51083           },
51084           skip: function skip(val) {
51085             var type = val & 0x7;
51086             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);
51087           },
51088           // === WRITING =================================================================
51089           writeTag: function writeTag(tag, type) {
51090             this.writeVarint(tag << 3 | type);
51091           },
51092           realloc: function realloc(min) {
51093             var length = this.length || 16;
51094
51095             while (length < this.pos + min) {
51096               length *= 2;
51097             }
51098
51099             if (length !== this.length) {
51100               var buf = new Uint8Array(length);
51101               buf.set(this.buf);
51102               this.buf = buf;
51103               this.length = length;
51104             }
51105           },
51106           finish: function finish() {
51107             this.length = this.pos;
51108             this.pos = 0;
51109             return this.buf.subarray(0, this.length);
51110           },
51111           writeFixed32: function writeFixed32(val) {
51112             this.realloc(4);
51113             writeInt32(this.buf, val, this.pos);
51114             this.pos += 4;
51115           },
51116           writeSFixed32: function writeSFixed32(val) {
51117             this.realloc(4);
51118             writeInt32(this.buf, val, this.pos);
51119             this.pos += 4;
51120           },
51121           writeFixed64: function writeFixed64(val) {
51122             this.realloc(8);
51123             writeInt32(this.buf, val & -1, this.pos);
51124             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51125             this.pos += 8;
51126           },
51127           writeSFixed64: function writeSFixed64(val) {
51128             this.realloc(8);
51129             writeInt32(this.buf, val & -1, this.pos);
51130             writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51131             this.pos += 8;
51132           },
51133           writeVarint: function writeVarint(val) {
51134             val = +val || 0;
51135
51136             if (val > 0xfffffff || val < 0) {
51137               writeBigVarint(val, this);
51138               return;
51139             }
51140
51141             this.realloc(4);
51142             this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
51143             if (val <= 0x7f) return;
51144             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51145             if (val <= 0x7f) return;
51146             this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51147             if (val <= 0x7f) return;
51148             this.buf[this.pos++] = val >>> 7 & 0x7f;
51149           },
51150           writeSVarint: function writeSVarint(val) {
51151             this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
51152           },
51153           writeBoolean: function writeBoolean(val) {
51154             this.writeVarint(Boolean(val));
51155           },
51156           writeString: function writeString(str) {
51157             str = String(str);
51158             this.realloc(str.length * 4);
51159             this.pos++; // reserve 1 byte for short string length
51160
51161             var startPos = this.pos; // write the string directly to the buffer and see how much was written
51162
51163             this.pos = writeUtf8(this.buf, str, this.pos);
51164             var len = this.pos - startPos;
51165             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51166
51167             this.pos = startPos - 1;
51168             this.writeVarint(len);
51169             this.pos += len;
51170           },
51171           writeFloat: function writeFloat(val) {
51172             this.realloc(4);
51173             ieee754$1.write(this.buf, val, this.pos, true, 23, 4);
51174             this.pos += 4;
51175           },
51176           writeDouble: function writeDouble(val) {
51177             this.realloc(8);
51178             ieee754$1.write(this.buf, val, this.pos, true, 52, 8);
51179             this.pos += 8;
51180           },
51181           writeBytes: function writeBytes(buffer) {
51182             var len = buffer.length;
51183             this.writeVarint(len);
51184             this.realloc(len);
51185
51186             for (var i = 0; i < len; i++) {
51187               this.buf[this.pos++] = buffer[i];
51188             }
51189           },
51190           writeRawMessage: function writeRawMessage(fn, obj) {
51191             this.pos++; // reserve 1 byte for short message length
51192             // write the message directly to the buffer and see how much was written
51193
51194             var startPos = this.pos;
51195             fn(obj, this);
51196             var len = this.pos - startPos;
51197             if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51198
51199             this.pos = startPos - 1;
51200             this.writeVarint(len);
51201             this.pos += len;
51202           },
51203           writeMessage: function writeMessage(tag, fn, obj) {
51204             this.writeTag(tag, Pbf.Bytes);
51205             this.writeRawMessage(fn, obj);
51206           },
51207           writePackedVarint: function writePackedVarint(tag, arr) {
51208             if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
51209           },
51210           writePackedSVarint: function writePackedSVarint(tag, arr) {
51211             if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
51212           },
51213           writePackedBoolean: function writePackedBoolean(tag, arr) {
51214             if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
51215           },
51216           writePackedFloat: function writePackedFloat(tag, arr) {
51217             if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
51218           },
51219           writePackedDouble: function writePackedDouble(tag, arr) {
51220             if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
51221           },
51222           writePackedFixed32: function writePackedFixed32(tag, arr) {
51223             if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
51224           },
51225           writePackedSFixed32: function writePackedSFixed32(tag, arr) {
51226             if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
51227           },
51228           writePackedFixed64: function writePackedFixed64(tag, arr) {
51229             if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
51230           },
51231           writePackedSFixed64: function writePackedSFixed64(tag, arr) {
51232             if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
51233           },
51234           writeBytesField: function writeBytesField(tag, buffer) {
51235             this.writeTag(tag, Pbf.Bytes);
51236             this.writeBytes(buffer);
51237           },
51238           writeFixed32Field: function writeFixed32Field(tag, val) {
51239             this.writeTag(tag, Pbf.Fixed32);
51240             this.writeFixed32(val);
51241           },
51242           writeSFixed32Field: function writeSFixed32Field(tag, val) {
51243             this.writeTag(tag, Pbf.Fixed32);
51244             this.writeSFixed32(val);
51245           },
51246           writeFixed64Field: function writeFixed64Field(tag, val) {
51247             this.writeTag(tag, Pbf.Fixed64);
51248             this.writeFixed64(val);
51249           },
51250           writeSFixed64Field: function writeSFixed64Field(tag, val) {
51251             this.writeTag(tag, Pbf.Fixed64);
51252             this.writeSFixed64(val);
51253           },
51254           writeVarintField: function writeVarintField(tag, val) {
51255             this.writeTag(tag, Pbf.Varint);
51256             this.writeVarint(val);
51257           },
51258           writeSVarintField: function writeSVarintField(tag, val) {
51259             this.writeTag(tag, Pbf.Varint);
51260             this.writeSVarint(val);
51261           },
51262           writeStringField: function writeStringField(tag, str) {
51263             this.writeTag(tag, Pbf.Bytes);
51264             this.writeString(str);
51265           },
51266           writeFloatField: function writeFloatField(tag, val) {
51267             this.writeTag(tag, Pbf.Fixed32);
51268             this.writeFloat(val);
51269           },
51270           writeDoubleField: function writeDoubleField(tag, val) {
51271             this.writeTag(tag, Pbf.Fixed64);
51272             this.writeDouble(val);
51273           },
51274           writeBooleanField: function writeBooleanField(tag, val) {
51275             this.writeVarintField(tag, Boolean(val));
51276           }
51277         };
51278
51279         function readVarintRemainder(l, s, p) {
51280           var buf = p.buf,
51281               h,
51282               b;
51283           b = buf[p.pos++];
51284           h = (b & 0x70) >> 4;
51285           if (b < 0x80) return toNum(l, h, s);
51286           b = buf[p.pos++];
51287           h |= (b & 0x7f) << 3;
51288           if (b < 0x80) return toNum(l, h, s);
51289           b = buf[p.pos++];
51290           h |= (b & 0x7f) << 10;
51291           if (b < 0x80) return toNum(l, h, s);
51292           b = buf[p.pos++];
51293           h |= (b & 0x7f) << 17;
51294           if (b < 0x80) return toNum(l, h, s);
51295           b = buf[p.pos++];
51296           h |= (b & 0x7f) << 24;
51297           if (b < 0x80) return toNum(l, h, s);
51298           b = buf[p.pos++];
51299           h |= (b & 0x01) << 31;
51300           if (b < 0x80) return toNum(l, h, s);
51301           throw new Error('Expected varint not more than 10 bytes');
51302         }
51303
51304         function readPackedEnd(pbf) {
51305           return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
51306         }
51307
51308         function toNum(low, high, isSigned) {
51309           if (isSigned) {
51310             return high * 0x100000000 + (low >>> 0);
51311           }
51312
51313           return (high >>> 0) * 0x100000000 + (low >>> 0);
51314         }
51315
51316         function writeBigVarint(val, pbf) {
51317           var low, high;
51318
51319           if (val >= 0) {
51320             low = val % 0x100000000 | 0;
51321             high = val / 0x100000000 | 0;
51322           } else {
51323             low = ~(-val % 0x100000000);
51324             high = ~(-val / 0x100000000);
51325
51326             if (low ^ 0xffffffff) {
51327               low = low + 1 | 0;
51328             } else {
51329               low = 0;
51330               high = high + 1 | 0;
51331             }
51332           }
51333
51334           if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
51335             throw new Error('Given varint doesn\'t fit into 10 bytes');
51336           }
51337
51338           pbf.realloc(10);
51339           writeBigVarintLow(low, high, pbf);
51340           writeBigVarintHigh(high, pbf);
51341         }
51342
51343         function writeBigVarintLow(low, high, pbf) {
51344           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51345           low >>>= 7;
51346           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51347           low >>>= 7;
51348           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51349           low >>>= 7;
51350           pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51351           low >>>= 7;
51352           pbf.buf[pbf.pos] = low & 0x7f;
51353         }
51354
51355         function writeBigVarintHigh(high, pbf) {
51356           var lsb = (high & 0x07) << 4;
51357           pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
51358           if (!high) return;
51359           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51360           if (!high) return;
51361           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51362           if (!high) return;
51363           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51364           if (!high) return;
51365           pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51366           if (!high) return;
51367           pbf.buf[pbf.pos++] = high & 0x7f;
51368         }
51369
51370         function makeRoomForExtraLength(startPos, len, pbf) {
51371           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
51372
51373           pbf.realloc(extraLen);
51374
51375           for (var i = pbf.pos - 1; i >= startPos; i--) {
51376             pbf.buf[i + extraLen] = pbf.buf[i];
51377           }
51378         }
51379
51380         function _writePackedVarint(arr, pbf) {
51381           for (var i = 0; i < arr.length; i++) {
51382             pbf.writeVarint(arr[i]);
51383           }
51384         }
51385
51386         function _writePackedSVarint(arr, pbf) {
51387           for (var i = 0; i < arr.length; i++) {
51388             pbf.writeSVarint(arr[i]);
51389           }
51390         }
51391
51392         function _writePackedFloat(arr, pbf) {
51393           for (var i = 0; i < arr.length; i++) {
51394             pbf.writeFloat(arr[i]);
51395           }
51396         }
51397
51398         function _writePackedDouble(arr, pbf) {
51399           for (var i = 0; i < arr.length; i++) {
51400             pbf.writeDouble(arr[i]);
51401           }
51402         }
51403
51404         function _writePackedBoolean(arr, pbf) {
51405           for (var i = 0; i < arr.length; i++) {
51406             pbf.writeBoolean(arr[i]);
51407           }
51408         }
51409
51410         function _writePackedFixed(arr, pbf) {
51411           for (var i = 0; i < arr.length; i++) {
51412             pbf.writeFixed32(arr[i]);
51413           }
51414         }
51415
51416         function _writePackedSFixed(arr, pbf) {
51417           for (var i = 0; i < arr.length; i++) {
51418             pbf.writeSFixed32(arr[i]);
51419           }
51420         }
51421
51422         function _writePackedFixed2(arr, pbf) {
51423           for (var i = 0; i < arr.length; i++) {
51424             pbf.writeFixed64(arr[i]);
51425           }
51426         }
51427
51428         function _writePackedSFixed2(arr, pbf) {
51429           for (var i = 0; i < arr.length; i++) {
51430             pbf.writeSFixed64(arr[i]);
51431           }
51432         } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
51433
51434
51435         function readUInt32(buf, pos) {
51436           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
51437         }
51438
51439         function writeInt32(buf, val, pos) {
51440           buf[pos] = val;
51441           buf[pos + 1] = val >>> 8;
51442           buf[pos + 2] = val >>> 16;
51443           buf[pos + 3] = val >>> 24;
51444         }
51445
51446         function readInt32(buf, pos) {
51447           return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
51448         }
51449
51450         function readUtf8(buf, pos, end) {
51451           var str = '';
51452           var i = pos;
51453
51454           while (i < end) {
51455             var b0 = buf[i];
51456             var c = null; // codepoint
51457
51458             var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
51459             if (i + bytesPerSequence > end) break;
51460             var b1, b2, b3;
51461
51462             if (bytesPerSequence === 1) {
51463               if (b0 < 0x80) {
51464                 c = b0;
51465               }
51466             } else if (bytesPerSequence === 2) {
51467               b1 = buf[i + 1];
51468
51469               if ((b1 & 0xC0) === 0x80) {
51470                 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
51471
51472                 if (c <= 0x7F) {
51473                   c = null;
51474                 }
51475               }
51476             } else if (bytesPerSequence === 3) {
51477               b1 = buf[i + 1];
51478               b2 = buf[i + 2];
51479
51480               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
51481                 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
51482
51483                 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
51484                   c = null;
51485                 }
51486               }
51487             } else if (bytesPerSequence === 4) {
51488               b1 = buf[i + 1];
51489               b2 = buf[i + 2];
51490               b3 = buf[i + 3];
51491
51492               if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
51493                 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
51494
51495                 if (c <= 0xFFFF || c >= 0x110000) {
51496                   c = null;
51497                 }
51498               }
51499             }
51500
51501             if (c === null) {
51502               c = 0xFFFD;
51503               bytesPerSequence = 1;
51504             } else if (c > 0xFFFF) {
51505               c -= 0x10000;
51506               str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
51507               c = 0xDC00 | c & 0x3FF;
51508             }
51509
51510             str += String.fromCharCode(c);
51511             i += bytesPerSequence;
51512           }
51513
51514           return str;
51515         }
51516
51517         function readUtf8TextDecoder(buf, pos, end) {
51518           return utf8TextDecoder.decode(buf.subarray(pos, end));
51519         }
51520
51521         function writeUtf8(buf, str, pos) {
51522           for (var i = 0, c, lead; i < str.length; i++) {
51523             c = str.charCodeAt(i); // code point
51524
51525             if (c > 0xD7FF && c < 0xE000) {
51526               if (lead) {
51527                 if (c < 0xDC00) {
51528                   buf[pos++] = 0xEF;
51529                   buf[pos++] = 0xBF;
51530                   buf[pos++] = 0xBD;
51531                   lead = c;
51532                   continue;
51533                 } else {
51534                   c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
51535                   lead = null;
51536                 }
51537               } else {
51538                 if (c > 0xDBFF || i + 1 === str.length) {
51539                   buf[pos++] = 0xEF;
51540                   buf[pos++] = 0xBF;
51541                   buf[pos++] = 0xBD;
51542                 } else {
51543                   lead = c;
51544                 }
51545
51546                 continue;
51547               }
51548             } else if (lead) {
51549               buf[pos++] = 0xEF;
51550               buf[pos++] = 0xBF;
51551               buf[pos++] = 0xBD;
51552               lead = null;
51553             }
51554
51555             if (c < 0x80) {
51556               buf[pos++] = c;
51557             } else {
51558               if (c < 0x800) {
51559                 buf[pos++] = c >> 0x6 | 0xC0;
51560               } else {
51561                 if (c < 0x10000) {
51562                   buf[pos++] = c >> 0xC | 0xE0;
51563                 } else {
51564                   buf[pos++] = c >> 0x12 | 0xF0;
51565                   buf[pos++] = c >> 0xC & 0x3F | 0x80;
51566                 }
51567
51568                 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
51569               }
51570
51571               buf[pos++] = c & 0x3F | 0x80;
51572             }
51573           }
51574
51575           return pos;
51576         }
51577
51578         var pointGeometry = Point;
51579         /**
51580          * A standalone point geometry with useful accessor, comparison, and
51581          * modification methods.
51582          *
51583          * @class Point
51584          * @param {Number} x the x-coordinate. this could be longitude or screen
51585          * pixels, or any other sort of unit.
51586          * @param {Number} y the y-coordinate. this could be latitude or screen
51587          * pixels, or any other sort of unit.
51588          * @example
51589          * var point = new Point(-77, 38);
51590          */
51591
51592         function Point(x, y) {
51593           this.x = x;
51594           this.y = y;
51595         }
51596
51597         Point.prototype = {
51598           /**
51599            * Clone this point, returning a new point that can be modified
51600            * without affecting the old one.
51601            * @return {Point} the clone
51602            */
51603           clone: function clone() {
51604             return new Point(this.x, this.y);
51605           },
51606
51607           /**
51608            * Add this point's x & y coordinates to another point,
51609            * yielding a new point.
51610            * @param {Point} p the other point
51611            * @return {Point} output point
51612            */
51613           add: function add(p) {
51614             return this.clone()._add(p);
51615           },
51616
51617           /**
51618            * Subtract this point's x & y coordinates to from point,
51619            * yielding a new point.
51620            * @param {Point} p the other point
51621            * @return {Point} output point
51622            */
51623           sub: function sub(p) {
51624             return this.clone()._sub(p);
51625           },
51626
51627           /**
51628            * Multiply this point's x & y coordinates by point,
51629            * yielding a new point.
51630            * @param {Point} p the other point
51631            * @return {Point} output point
51632            */
51633           multByPoint: function multByPoint(p) {
51634             return this.clone()._multByPoint(p);
51635           },
51636
51637           /**
51638            * Divide this point's x & y coordinates by point,
51639            * yielding a new point.
51640            * @param {Point} p the other point
51641            * @return {Point} output point
51642            */
51643           divByPoint: function divByPoint(p) {
51644             return this.clone()._divByPoint(p);
51645           },
51646
51647           /**
51648            * Multiply this point's x & y coordinates by a factor,
51649            * yielding a new point.
51650            * @param {Point} k factor
51651            * @return {Point} output point
51652            */
51653           mult: function mult(k) {
51654             return this.clone()._mult(k);
51655           },
51656
51657           /**
51658            * Divide this point's x & y coordinates by a factor,
51659            * yielding a new point.
51660            * @param {Point} k factor
51661            * @return {Point} output point
51662            */
51663           div: function div(k) {
51664             return this.clone()._div(k);
51665           },
51666
51667           /**
51668            * Rotate this point around the 0, 0 origin by an angle a,
51669            * given in radians
51670            * @param {Number} a angle to rotate around, in radians
51671            * @return {Point} output point
51672            */
51673           rotate: function rotate(a) {
51674             return this.clone()._rotate(a);
51675           },
51676
51677           /**
51678            * Rotate this point around p point by an angle a,
51679            * given in radians
51680            * @param {Number} a angle to rotate around, in radians
51681            * @param {Point} p Point to rotate around
51682            * @return {Point} output point
51683            */
51684           rotateAround: function rotateAround(a, p) {
51685             return this.clone()._rotateAround(a, p);
51686           },
51687
51688           /**
51689            * Multiply this point by a 4x1 transformation matrix
51690            * @param {Array<Number>} m transformation matrix
51691            * @return {Point} output point
51692            */
51693           matMult: function matMult(m) {
51694             return this.clone()._matMult(m);
51695           },
51696
51697           /**
51698            * Calculate this point but as a unit vector from 0, 0, meaning
51699            * that the distance from the resulting point to the 0, 0
51700            * coordinate will be equal to 1 and the angle from the resulting
51701            * point to the 0, 0 coordinate will be the same as before.
51702            * @return {Point} unit vector point
51703            */
51704           unit: function unit() {
51705             return this.clone()._unit();
51706           },
51707
51708           /**
51709            * Compute a perpendicular point, where the new y coordinate
51710            * is the old x coordinate and the new x coordinate is the old y
51711            * coordinate multiplied by -1
51712            * @return {Point} perpendicular point
51713            */
51714           perp: function perp() {
51715             return this.clone()._perp();
51716           },
51717
51718           /**
51719            * Return a version of this point with the x & y coordinates
51720            * rounded to integers.
51721            * @return {Point} rounded point
51722            */
51723           round: function round() {
51724             return this.clone()._round();
51725           },
51726
51727           /**
51728            * Return the magitude of this point: this is the Euclidean
51729            * distance from the 0, 0 coordinate to this point's x and y
51730            * coordinates.
51731            * @return {Number} magnitude
51732            */
51733           mag: function mag() {
51734             return Math.sqrt(this.x * this.x + this.y * this.y);
51735           },
51736
51737           /**
51738            * Judge whether this point is equal to another point, returning
51739            * true or false.
51740            * @param {Point} other the other point
51741            * @return {boolean} whether the points are equal
51742            */
51743           equals: function equals(other) {
51744             return this.x === other.x && this.y === other.y;
51745           },
51746
51747           /**
51748            * Calculate the distance from this point to another point
51749            * @param {Point} p the other point
51750            * @return {Number} distance
51751            */
51752           dist: function dist(p) {
51753             return Math.sqrt(this.distSqr(p));
51754           },
51755
51756           /**
51757            * Calculate the distance from this point to another point,
51758            * without the square root step. Useful if you're comparing
51759            * relative distances.
51760            * @param {Point} p the other point
51761            * @return {Number} distance
51762            */
51763           distSqr: function distSqr(p) {
51764             var dx = p.x - this.x,
51765                 dy = p.y - this.y;
51766             return dx * dx + dy * dy;
51767           },
51768
51769           /**
51770            * Get the angle from the 0, 0 coordinate to this point, in radians
51771            * coordinates.
51772            * @return {Number} angle
51773            */
51774           angle: function angle() {
51775             return Math.atan2(this.y, this.x);
51776           },
51777
51778           /**
51779            * Get the angle from this point to another point, in radians
51780            * @param {Point} b the other point
51781            * @return {Number} angle
51782            */
51783           angleTo: function angleTo(b) {
51784             return Math.atan2(this.y - b.y, this.x - b.x);
51785           },
51786
51787           /**
51788            * Get the angle between this point and another point, in radians
51789            * @param {Point} b the other point
51790            * @return {Number} angle
51791            */
51792           angleWith: function angleWith(b) {
51793             return this.angleWithSep(b.x, b.y);
51794           },
51795
51796           /*
51797            * Find the angle of the two vectors, solving the formula for
51798            * the cross product a x b = |a||b|sin(θ) for θ.
51799            * @param {Number} x the x-coordinate
51800            * @param {Number} y the y-coordinate
51801            * @return {Number} the angle in radians
51802            */
51803           angleWithSep: function angleWithSep(x, y) {
51804             return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
51805           },
51806           _matMult: function _matMult(m) {
51807             var x = m[0] * this.x + m[1] * this.y,
51808                 y = m[2] * this.x + m[3] * this.y;
51809             this.x = x;
51810             this.y = y;
51811             return this;
51812           },
51813           _add: function _add(p) {
51814             this.x += p.x;
51815             this.y += p.y;
51816             return this;
51817           },
51818           _sub: function _sub(p) {
51819             this.x -= p.x;
51820             this.y -= p.y;
51821             return this;
51822           },
51823           _mult: function _mult(k) {
51824             this.x *= k;
51825             this.y *= k;
51826             return this;
51827           },
51828           _div: function _div(k) {
51829             this.x /= k;
51830             this.y /= k;
51831             return this;
51832           },
51833           _multByPoint: function _multByPoint(p) {
51834             this.x *= p.x;
51835             this.y *= p.y;
51836             return this;
51837           },
51838           _divByPoint: function _divByPoint(p) {
51839             this.x /= p.x;
51840             this.y /= p.y;
51841             return this;
51842           },
51843           _unit: function _unit() {
51844             this._div(this.mag());
51845
51846             return this;
51847           },
51848           _perp: function _perp() {
51849             var y = this.y;
51850             this.y = this.x;
51851             this.x = -y;
51852             return this;
51853           },
51854           _rotate: function _rotate(angle) {
51855             var cos = Math.cos(angle),
51856                 sin = Math.sin(angle),
51857                 x = cos * this.x - sin * this.y,
51858                 y = sin * this.x + cos * this.y;
51859             this.x = x;
51860             this.y = y;
51861             return this;
51862           },
51863           _rotateAround: function _rotateAround(angle, p) {
51864             var cos = Math.cos(angle),
51865                 sin = Math.sin(angle),
51866                 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51867                 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51868             this.x = x;
51869             this.y = y;
51870             return this;
51871           },
51872           _round: function _round() {
51873             this.x = Math.round(this.x);
51874             this.y = Math.round(this.y);
51875             return this;
51876           }
51877         };
51878         /**
51879          * Construct a point from an array if necessary, otherwise if the input
51880          * is already a Point, or an unknown type, return it unchanged
51881          * @param {Array<Number>|Point|*} a any kind of input value
51882          * @return {Point} constructed point, or passed-through value.
51883          * @example
51884          * // this
51885          * var point = Point.convert([0, 1]);
51886          * // is equivalent to
51887          * var point = new Point(0, 1);
51888          */
51889
51890         Point.convert = function (a) {
51891           if (a instanceof Point) {
51892             return a;
51893           }
51894
51895           if (Array.isArray(a)) {
51896             return new Point(a[0], a[1]);
51897           }
51898
51899           return a;
51900         };
51901
51902         var vectortilefeature = VectorTileFeature;
51903
51904         function VectorTileFeature(pbf, end, extent, keys, values) {
51905           // Public
51906           this.properties = {};
51907           this.extent = extent;
51908           this.type = 0; // Private
51909
51910           this._pbf = pbf;
51911           this._geometry = -1;
51912           this._keys = keys;
51913           this._values = values;
51914           pbf.readFields(readFeature, this, end);
51915         }
51916
51917         function readFeature(tag, feature, pbf) {
51918           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;
51919         }
51920
51921         function readTag(pbf, feature) {
51922           var end = pbf.readVarint() + pbf.pos;
51923
51924           while (pbf.pos < end) {
51925             var key = feature._keys[pbf.readVarint()],
51926                 value = feature._values[pbf.readVarint()];
51927
51928             feature.properties[key] = value;
51929           }
51930         }
51931
51932         VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
51933
51934         VectorTileFeature.prototype.loadGeometry = function () {
51935           var pbf = this._pbf;
51936           pbf.pos = this._geometry;
51937           var end = pbf.readVarint() + pbf.pos,
51938               cmd = 1,
51939               length = 0,
51940               x = 0,
51941               y = 0,
51942               lines = [],
51943               line;
51944
51945           while (pbf.pos < end) {
51946             if (length <= 0) {
51947               var cmdLen = pbf.readVarint();
51948               cmd = cmdLen & 0x7;
51949               length = cmdLen >> 3;
51950             }
51951
51952             length--;
51953
51954             if (cmd === 1 || cmd === 2) {
51955               x += pbf.readSVarint();
51956               y += pbf.readSVarint();
51957
51958               if (cmd === 1) {
51959                 // moveTo
51960                 if (line) lines.push(line);
51961                 line = [];
51962               }
51963
51964               line.push(new pointGeometry(x, y));
51965             } else if (cmd === 7) {
51966               // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
51967               if (line) {
51968                 line.push(line[0].clone()); // closePolygon
51969               }
51970             } else {
51971               throw new Error('unknown command ' + cmd);
51972             }
51973           }
51974
51975           if (line) lines.push(line);
51976           return lines;
51977         };
51978
51979         VectorTileFeature.prototype.bbox = function () {
51980           var pbf = this._pbf;
51981           pbf.pos = this._geometry;
51982           var end = pbf.readVarint() + pbf.pos,
51983               cmd = 1,
51984               length = 0,
51985               x = 0,
51986               y = 0,
51987               x1 = Infinity,
51988               x2 = -Infinity,
51989               y1 = Infinity,
51990               y2 = -Infinity;
51991
51992           while (pbf.pos < end) {
51993             if (length <= 0) {
51994               var cmdLen = pbf.readVarint();
51995               cmd = cmdLen & 0x7;
51996               length = cmdLen >> 3;
51997             }
51998
51999             length--;
52000
52001             if (cmd === 1 || cmd === 2) {
52002               x += pbf.readSVarint();
52003               y += pbf.readSVarint();
52004               if (x < x1) x1 = x;
52005               if (x > x2) x2 = x;
52006               if (y < y1) y1 = y;
52007               if (y > y2) y2 = y;
52008             } else if (cmd !== 7) {
52009               throw new Error('unknown command ' + cmd);
52010             }
52011           }
52012
52013           return [x1, y1, x2, y2];
52014         };
52015
52016         VectorTileFeature.prototype.toGeoJSON = function (x, y, z) {
52017           var size = this.extent * Math.pow(2, z),
52018               x0 = this.extent * x,
52019               y0 = this.extent * y,
52020               coords = this.loadGeometry(),
52021               type = VectorTileFeature.types[this.type],
52022               i,
52023               j;
52024
52025           function project(line) {
52026             for (var j = 0; j < line.length; j++) {
52027               var p = line[j],
52028                   y2 = 180 - (p.y + y0) * 360 / size;
52029               line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
52030             }
52031           }
52032
52033           switch (this.type) {
52034             case 1:
52035               var points = [];
52036
52037               for (i = 0; i < coords.length; i++) {
52038                 points[i] = coords[i][0];
52039               }
52040
52041               coords = points;
52042               project(coords);
52043               break;
52044
52045             case 2:
52046               for (i = 0; i < coords.length; i++) {
52047                 project(coords[i]);
52048               }
52049
52050               break;
52051
52052             case 3:
52053               coords = classifyRings(coords);
52054
52055               for (i = 0; i < coords.length; i++) {
52056                 for (j = 0; j < coords[i].length; j++) {
52057                   project(coords[i][j]);
52058                 }
52059               }
52060
52061               break;
52062           }
52063
52064           if (coords.length === 1) {
52065             coords = coords[0];
52066           } else {
52067             type = 'Multi' + type;
52068           }
52069
52070           var result = {
52071             type: "Feature",
52072             geometry: {
52073               type: type,
52074               coordinates: coords
52075             },
52076             properties: this.properties
52077           };
52078
52079           if ('id' in this) {
52080             result.id = this.id;
52081           }
52082
52083           return result;
52084         }; // classifies an array of rings into polygons with outer rings and holes
52085
52086
52087         function classifyRings(rings) {
52088           var len = rings.length;
52089           if (len <= 1) return [rings];
52090           var polygons = [],
52091               polygon,
52092               ccw;
52093
52094           for (var i = 0; i < len; i++) {
52095             var area = signedArea$1(rings[i]);
52096             if (area === 0) continue;
52097             if (ccw === undefined) ccw = area < 0;
52098
52099             if (ccw === area < 0) {
52100               if (polygon) polygons.push(polygon);
52101               polygon = [rings[i]];
52102             } else {
52103               polygon.push(rings[i]);
52104             }
52105           }
52106
52107           if (polygon) polygons.push(polygon);
52108           return polygons;
52109         }
52110
52111         function signedArea$1(ring) {
52112           var sum = 0;
52113
52114           for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
52115             p1 = ring[i];
52116             p2 = ring[j];
52117             sum += (p2.x - p1.x) * (p1.y + p2.y);
52118           }
52119
52120           return sum;
52121         }
52122
52123         var vectortilelayer = VectorTileLayer;
52124
52125         function VectorTileLayer(pbf, end) {
52126           // Public
52127           this.version = 1;
52128           this.name = null;
52129           this.extent = 4096;
52130           this.length = 0; // Private
52131
52132           this._pbf = pbf;
52133           this._keys = [];
52134           this._values = [];
52135           this._features = [];
52136           pbf.readFields(readLayer, this, end);
52137           this.length = this._features.length;
52138         }
52139
52140         function readLayer(tag, layer, pbf) {
52141           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));
52142         }
52143
52144         function readValueMessage(pbf) {
52145           var value = null,
52146               end = pbf.readVarint() + pbf.pos;
52147
52148           while (pbf.pos < end) {
52149             var tag = pbf.readVarint() >> 3;
52150             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;
52151           }
52152
52153           return value;
52154         } // return feature `i` from this layer as a `VectorTileFeature`
52155
52156
52157         VectorTileLayer.prototype.feature = function (i) {
52158           if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
52159           this._pbf.pos = this._features[i];
52160
52161           var end = this._pbf.readVarint() + this._pbf.pos;
52162
52163           return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
52164         };
52165
52166         var vectortile = VectorTile;
52167
52168         function VectorTile(pbf, end) {
52169           this.layers = pbf.readFields(readTile, {}, end);
52170         }
52171
52172         function readTile(tag, layers, pbf) {
52173           if (tag === 3) {
52174             var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
52175             if (layer.length) layers[layer.name] = layer;
52176           }
52177         }
52178
52179         var VectorTile$1 = vectortile;
52180         var VectorTileFeature$1 = vectortilefeature;
52181         var VectorTileLayer$1 = vectortilelayer;
52182         var vectorTile = {
52183           VectorTile: VectorTile$1,
52184           VectorTileFeature: VectorTileFeature$1,
52185           VectorTileLayer: VectorTileLayer$1
52186         };
52187
52188         var tiler$7 = utilTiler().tileSize(512).margin(1);
52189         var dispatch$8 = dispatch('loadedData');
52190
52191         var _vtCache;
52192
52193         function abortRequest$7(controller) {
52194           controller.abort();
52195         }
52196
52197         function vtToGeoJSON(data, tile, mergeCache) {
52198           var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
52199           var layers = Object.keys(vectorTile$1.layers);
52200
52201           if (!Array.isArray(layers)) {
52202             layers = [layers];
52203           }
52204
52205           var features = [];
52206           layers.forEach(function (layerID) {
52207             var layer = vectorTile$1.layers[layerID];
52208
52209             if (layer) {
52210               for (var i = 0; i < layer.length; i++) {
52211                 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52212                 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
52213
52214                 if (geometry.type === 'Polygon') {
52215                   geometry.type = 'MultiPolygon';
52216                   geometry.coordinates = [geometry.coordinates];
52217                 }
52218
52219                 var isClipped = false; // Clip to tile bounds
52220
52221                 if (geometry.type === 'MultiPolygon') {
52222                   var featureClip = turf_bboxClip(feature, tile.extent.rectangle());
52223
52224                   if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
52225                     // feature = featureClip;
52226                     isClipped = true;
52227                   }
52228
52229                   if (!feature.geometry.coordinates.length) continue; // not actually on this tile
52230
52231                   if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
52232                 } // Generate some unique IDs and add some metadata
52233
52234
52235                 var featurehash = utilHashcode(fastJsonStableStringify(feature));
52236                 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
52237                 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
52238                 feature.__featurehash__ = featurehash;
52239                 feature.__propertyhash__ = propertyhash;
52240                 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
52241
52242                 if (isClipped && geometry.type === 'MultiPolygon') {
52243                   var merged = mergeCache[propertyhash];
52244
52245                   if (merged && merged.length) {
52246                     var other = merged[0];
52247                     var coords = union(feature.geometry.coordinates, other.geometry.coordinates);
52248
52249                     if (!coords || !coords.length) {
52250                       continue; // something failed in martinez union
52251                     }
52252
52253                     merged.push(feature);
52254
52255                     for (var j = 0; j < merged.length; j++) {
52256                       // all these features get...
52257                       merged[j].geometry.coordinates = coords; // same coords
52258
52259                       merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
52260                     }
52261                   } else {
52262                     mergeCache[propertyhash] = [feature];
52263                   }
52264                 }
52265               }
52266             }
52267           });
52268           return features;
52269         }
52270
52271         function loadTile(source, tile) {
52272           if (source.loaded[tile.id] || source.inflight[tile.id]) return;
52273           var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
52274           .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
52275             var subdomains = r.split(',');
52276             return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
52277           });
52278           var controller = new AbortController();
52279           source.inflight[tile.id] = controller;
52280           fetch(url, {
52281             signal: controller.signal
52282           }).then(function (response) {
52283             if (!response.ok) {
52284               throw new Error(response.status + ' ' + response.statusText);
52285             }
52286
52287             source.loaded[tile.id] = [];
52288             delete source.inflight[tile.id];
52289             return response.arrayBuffer();
52290           }).then(function (data) {
52291             if (!data) {
52292               throw new Error('No Data');
52293             }
52294
52295             var z = tile.xyz[2];
52296
52297             if (!source.canMerge[z]) {
52298               source.canMerge[z] = {}; // initialize mergeCache
52299             }
52300
52301             source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
52302             dispatch$8.call('loadedData');
52303           })["catch"](function () {
52304             source.loaded[tile.id] = [];
52305             delete source.inflight[tile.id];
52306           });
52307         }
52308
52309         var serviceVectorTile = {
52310           init: function init() {
52311             if (!_vtCache) {
52312               this.reset();
52313             }
52314
52315             this.event = utilRebind(this, dispatch$8, 'on');
52316           },
52317           reset: function reset() {
52318             for (var sourceID in _vtCache) {
52319               var source = _vtCache[sourceID];
52320
52321               if (source && source.inflight) {
52322                 Object.values(source.inflight).forEach(abortRequest$7);
52323               }
52324             }
52325
52326             _vtCache = {};
52327           },
52328           addSource: function addSource(sourceID, template) {
52329             _vtCache[sourceID] = {
52330               template: template,
52331               inflight: {},
52332               loaded: {},
52333               canMerge: {}
52334             };
52335             return _vtCache[sourceID];
52336           },
52337           data: function data(sourceID, projection) {
52338             var source = _vtCache[sourceID];
52339             if (!source) return [];
52340             var tiles = tiler$7.getTiles(projection);
52341             var seen = {};
52342             var results = [];
52343
52344             for (var i = 0; i < tiles.length; i++) {
52345               var features = source.loaded[tiles[i].id];
52346               if (!features || !features.length) continue;
52347
52348               for (var j = 0; j < features.length; j++) {
52349                 var feature = features[j];
52350                 var hash = feature.__featurehash__;
52351                 if (seen[hash]) continue;
52352                 seen[hash] = true; // return a shallow copy, because the hash may change
52353                 // later if this feature gets merged with another
52354
52355                 results.push(Object.assign({}, feature)); // shallow copy
52356               }
52357             }
52358
52359             return results;
52360           },
52361           loadTiles: function loadTiles(sourceID, template, projection) {
52362             var source = _vtCache[sourceID];
52363
52364             if (!source) {
52365               source = this.addSource(sourceID, template);
52366             }
52367
52368             var tiles = tiler$7.getTiles(projection); // abort inflight requests that are no longer needed
52369
52370             Object.keys(source.inflight).forEach(function (k) {
52371               var wanted = tiles.find(function (tile) {
52372                 return k === tile.id;
52373               });
52374
52375               if (!wanted) {
52376                 abortRequest$7(source.inflight[k]);
52377                 delete source.inflight[k];
52378               }
52379             });
52380             tiles.forEach(function (tile) {
52381               loadTile(source, tile);
52382             });
52383           },
52384           cache: function cache() {
52385             return _vtCache;
52386           }
52387         };
52388
52389         var apibase$3 = 'https://www.wikidata.org/w/api.php?';
52390         var _wikidataCache = {};
52391         var serviceWikidata = {
52392           init: function init() {},
52393           reset: function reset() {
52394             _wikidataCache = {};
52395           },
52396           // Search for Wikidata items matching the query
52397           itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
52398             if (!query) {
52399               if (callback) callback('No query', {});
52400               return;
52401             }
52402
52403             var lang = this.languagesToQuery()[0];
52404             var url = apibase$3 + utilQsString({
52405               action: 'wbsearchentities',
52406               format: 'json',
52407               formatversion: 2,
52408               search: query,
52409               type: 'item',
52410               // the language to search
52411               language: lang,
52412               // the language for the label and description in the result
52413               uselang: lang,
52414               limit: 10,
52415               origin: '*'
52416             });
52417             d3_json(url).then(function (result) {
52418               if (result && result.error) {
52419                 throw new Error(result.error);
52420               }
52421
52422               if (callback) callback(null, result.search || {});
52423             })["catch"](function (err) {
52424               if (callback) callback(err.message, {});
52425             });
52426           },
52427           // Given a Wikipedia language and article title,
52428           // return an array of corresponding Wikidata entities.
52429           itemsByTitle: function itemsByTitle(lang, title, callback) {
52430             if (!title) {
52431               if (callback) callback('No title', {});
52432               return;
52433             }
52434
52435             lang = lang || 'en';
52436             var url = apibase$3 + utilQsString({
52437               action: 'wbgetentities',
52438               format: 'json',
52439               formatversion: 2,
52440               sites: lang.replace(/-/g, '_') + 'wiki',
52441               titles: title,
52442               languages: 'en',
52443               // shrink response by filtering to one language
52444               origin: '*'
52445             });
52446             d3_json(url).then(function (result) {
52447               if (result && result.error) {
52448                 throw new Error(result.error);
52449               }
52450
52451               if (callback) callback(null, result.entities || {});
52452             })["catch"](function (err) {
52453               if (callback) callback(err.message, {});
52454             });
52455           },
52456           languagesToQuery: function languagesToQuery() {
52457             return _mainLocalizer.localeCodes().map(function (code) {
52458               return code.toLowerCase();
52459             }).filter(function (code) {
52460               // HACK: en-us isn't a wikidata language. We should really be filtering by
52461               // the languages known to be supported by wikidata.
52462               return code !== 'en-us';
52463             });
52464           },
52465           entityByQID: function entityByQID(qid, callback) {
52466             if (!qid) {
52467               callback('No qid', {});
52468               return;
52469             }
52470
52471             if (_wikidataCache[qid]) {
52472               if (callback) callback(null, _wikidataCache[qid]);
52473               return;
52474             }
52475
52476             var langs = this.languagesToQuery();
52477             var url = apibase$3 + utilQsString({
52478               action: 'wbgetentities',
52479               format: 'json',
52480               formatversion: 2,
52481               ids: qid,
52482               props: 'labels|descriptions|claims|sitelinks',
52483               sitefilter: langs.map(function (d) {
52484                 return d + 'wiki';
52485               }).join('|'),
52486               languages: langs.join('|'),
52487               languagefallback: 1,
52488               origin: '*'
52489             });
52490             d3_json(url).then(function (result) {
52491               if (result && result.error) {
52492                 throw new Error(result.error);
52493               }
52494
52495               if (callback) callback(null, result.entities[qid] || {});
52496             })["catch"](function (err) {
52497               if (callback) callback(err.message, {});
52498             });
52499           },
52500           // Pass `params` object of the form:
52501           // {
52502           //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
52503           // }
52504           //
52505           // Get an result object used to display tag documentation
52506           // {
52507           //   title:        'string',
52508           //   description:  'string',
52509           //   editURL:      'string',
52510           //   imageURL:     'string',
52511           //   wiki:         { title: 'string', text: 'string', url: 'string' }
52512           // }
52513           //
52514           getDocs: function getDocs(params, callback) {
52515             var langs = this.languagesToQuery();
52516             this.entityByQID(params.qid, function (err, entity) {
52517               if (err || !entity) {
52518                 callback(err || 'No entity');
52519                 return;
52520               }
52521
52522               var i;
52523               var description;
52524
52525               for (i in langs) {
52526                 var code = langs[i];
52527
52528                 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
52529                   description = entity.descriptions[code];
52530                   break;
52531                 }
52532               }
52533
52534               if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
52535
52536               var result = {
52537                 title: entity.id,
52538                 description: description ? description.value : '',
52539                 descriptionLocaleCode: description ? description.language : '',
52540                 editURL: 'https://www.wikidata.org/wiki/' + entity.id
52541               }; // add image
52542
52543               if (entity.claims) {
52544                 var imageroot = 'https://commons.wikimedia.org/w/index.php';
52545                 var props = ['P154', 'P18']; // logo image, image
52546
52547                 var prop, image;
52548
52549                 for (i = 0; i < props.length; i++) {
52550                   prop = entity.claims[props[i]];
52551
52552                   if (prop && Object.keys(prop).length > 0) {
52553                     image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
52554
52555                     if (image) {
52556                       result.imageURL = imageroot + '?' + utilQsString({
52557                         title: 'Special:Redirect/file/' + image,
52558                         width: 400
52559                       });
52560                       break;
52561                     }
52562                   }
52563                 }
52564               }
52565
52566               if (entity.sitelinks) {
52567                 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
52568
52569                 for (i = 0; i < langs.length; i++) {
52570                   // check each, in order of preference
52571                   var w = langs[i] + 'wiki';
52572
52573                   if (entity.sitelinks[w]) {
52574                     var title = entity.sitelinks[w].title;
52575                     var tKey = 'inspector.wiki_reference';
52576
52577                     if (!englishLocale && langs[i] === 'en') {
52578                       // user's locale isn't English but
52579                       tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
52580                     }
52581
52582                     result.wiki = {
52583                       title: title,
52584                       text: tKey,
52585                       url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
52586                     };
52587                     break;
52588                   }
52589                 }
52590               }
52591
52592               callback(null, result);
52593             });
52594           }
52595         };
52596
52597         var endpoint = 'https://en.wikipedia.org/w/api.php?';
52598         var serviceWikipedia = {
52599           init: function init() {},
52600           reset: function reset() {},
52601           search: function search(lang, query, callback) {
52602             if (!query) {
52603               if (callback) callback('No Query', []);
52604               return;
52605             }
52606
52607             lang = lang || 'en';
52608             var url = endpoint.replace('en', lang) + utilQsString({
52609               action: 'query',
52610               list: 'search',
52611               srlimit: '10',
52612               srinfo: 'suggestion',
52613               format: 'json',
52614               origin: '*',
52615               srsearch: query
52616             });
52617             d3_json(url).then(function (result) {
52618               if (result && result.error) {
52619                 throw new Error(result.error);
52620               } else if (!result || !result.query || !result.query.search) {
52621                 throw new Error('No Results');
52622               }
52623
52624               if (callback) {
52625                 var titles = result.query.search.map(function (d) {
52626                   return d.title;
52627                 });
52628                 callback(null, titles);
52629               }
52630             })["catch"](function (err) {
52631               if (callback) callback(err, []);
52632             });
52633           },
52634           suggestions: function suggestions(lang, query, callback) {
52635             if (!query) {
52636               if (callback) callback('', []);
52637               return;
52638             }
52639
52640             lang = lang || 'en';
52641             var url = endpoint.replace('en', lang) + utilQsString({
52642               action: 'opensearch',
52643               namespace: 0,
52644               suggest: '',
52645               format: 'json',
52646               origin: '*',
52647               search: query
52648             });
52649             d3_json(url).then(function (result) {
52650               if (result && result.error) {
52651                 throw new Error(result.error);
52652               } else if (!result || result.length < 2) {
52653                 throw new Error('No Results');
52654               }
52655
52656               if (callback) callback(null, result[1] || []);
52657             })["catch"](function (err) {
52658               if (callback) callback(err.message, []);
52659             });
52660           },
52661           translations: function translations(lang, title, callback) {
52662             if (!title) {
52663               if (callback) callback('No Title');
52664               return;
52665             }
52666
52667             var url = endpoint.replace('en', lang) + utilQsString({
52668               action: 'query',
52669               prop: 'langlinks',
52670               format: 'json',
52671               origin: '*',
52672               lllimit: 500,
52673               titles: title
52674             });
52675             d3_json(url).then(function (result) {
52676               if (result && result.error) {
52677                 throw new Error(result.error);
52678               } else if (!result || !result.query || !result.query.pages) {
52679                 throw new Error('No Results');
52680               }
52681
52682               if (callback) {
52683                 var list = result.query.pages[Object.keys(result.query.pages)[0]];
52684                 var translations = {};
52685
52686                 if (list && list.langlinks) {
52687                   list.langlinks.forEach(function (d) {
52688                     translations[d.lang] = d['*'];
52689                   });
52690                 }
52691
52692                 callback(null, translations);
52693               }
52694             })["catch"](function (err) {
52695               if (callback) callback(err.message);
52696             });
52697           }
52698         };
52699
52700         var services = {
52701           geocoder: serviceNominatim,
52702           keepRight: serviceKeepRight,
52703           improveOSM: serviceImproveOSM,
52704           osmose: serviceOsmose,
52705           mapillary: serviceMapillary,
52706           openstreetcam: serviceOpenstreetcam,
52707           osm: serviceOsm,
52708           osmWikibase: serviceOsmWikibase,
52709           maprules: serviceMapRules,
52710           streetside: serviceStreetside,
52711           taginfo: serviceTaginfo,
52712           vectorTile: serviceVectorTile,
52713           wikidata: serviceWikidata,
52714           wikipedia: serviceWikipedia
52715         };
52716
52717         function svgIcon(name, svgklass, useklass) {
52718           return function drawIcon(selection) {
52719             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);
52720           };
52721         }
52722
52723         function uiNoteComments() {
52724           var _note;
52725
52726           function noteComments(selection) {
52727             if (_note.isNew()) return; // don't draw .comments-container
52728
52729             var comments = selection.selectAll('.comments-container').data([0]);
52730             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
52731             var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
52732             commentEnter.append('div').attr('class', function (d) {
52733               return 'comment-avatar user-' + d.uid;
52734             }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
52735             var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
52736             var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
52737             metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
52738               var selection = select(this);
52739               var osm = services.osm;
52740
52741               if (osm && d.user) {
52742                 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
52743               }
52744
52745               selection.html(function (d) {
52746                 return d.user || _t.html('note.anonymous');
52747               });
52748             });
52749             metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
52750               return _t('note.status.' + d.action, {
52751                 when: localeDateString(d.date)
52752               });
52753             });
52754             mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
52755               return d.html;
52756             }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
52757             comments.call(replaceAvatars);
52758           }
52759
52760           function replaceAvatars(selection) {
52761             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
52762             var osm = services.osm;
52763             if (showThirdPartyIcons !== 'true' || !osm) return;
52764             var uids = {}; // gather uids in the comment thread
52765
52766             _note.comments.forEach(function (d) {
52767               if (d.uid) uids[d.uid] = true;
52768             });
52769
52770             Object.keys(uids).forEach(function (uid) {
52771               osm.loadUser(uid, function (err, user) {
52772                 if (!user || !user.image_url) return;
52773                 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);
52774               });
52775             });
52776           }
52777
52778           function localeDateString(s) {
52779             if (!s) return null;
52780             var options = {
52781               day: 'numeric',
52782               month: 'short',
52783               year: 'numeric'
52784             };
52785             s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
52786
52787             var d = new Date(s);
52788             if (isNaN(d.getTime())) return null;
52789             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
52790           }
52791
52792           noteComments.note = function (val) {
52793             if (!arguments.length) return _note;
52794             _note = val;
52795             return noteComments;
52796           };
52797
52798           return noteComments;
52799         }
52800
52801         function uiNoteHeader() {
52802           var _note;
52803
52804           function noteHeader(selection) {
52805             var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
52806               return d.status + d.id;
52807             });
52808             header.exit().remove();
52809             var headerEnter = header.enter().append('div').attr('class', 'note-header');
52810             var iconEnter = headerEnter.append('div').attr('class', function (d) {
52811               return 'note-header-icon ' + d.status;
52812             }).classed('new', function (d) {
52813               return d.id < 0;
52814             });
52815             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
52816             iconEnter.each(function (d) {
52817               var statusIcon = '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
52818               iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
52819             });
52820             headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
52821               if (_note.isNew()) {
52822                 return _t('note.new');
52823               }
52824
52825               return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
52826             });
52827           }
52828
52829           noteHeader.note = function (val) {
52830             if (!arguments.length) return _note;
52831             _note = val;
52832             return noteHeader;
52833           };
52834
52835           return noteHeader;
52836         }
52837
52838         function uiNoteReport() {
52839           var _note;
52840
52841           function noteReport(selection) {
52842             var url;
52843
52844             if (services.osm && _note instanceof osmNote && !_note.isNew()) {
52845               url = services.osm.noteReportURL(_note);
52846             }
52847
52848             var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
52849
52850             link.exit().remove(); // enter
52851
52852             var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
52853               return d;
52854             }).call(svgIcon('#iD-icon-out-link', 'inline'));
52855             linkEnter.append('span').html(_t.html('note.report'));
52856           }
52857
52858           noteReport.note = function (val) {
52859             if (!arguments.length) return _note;
52860             _note = val;
52861             return noteReport;
52862           };
52863
52864           return noteReport;
52865         }
52866
52867         function uiViewOnOSM(context) {
52868           var _what; // an osmEntity or osmNote
52869
52870
52871           function viewOnOSM(selection) {
52872             var url;
52873
52874             if (_what instanceof osmEntity) {
52875               url = context.connection().entityURL(_what);
52876             } else if (_what instanceof osmNote) {
52877               url = context.connection().noteURL(_what);
52878             }
52879
52880             var data = !_what || _what.isNew() ? [] : [_what];
52881             var link = selection.selectAll('.view-on-osm').data(data, function (d) {
52882               return d.id;
52883             }); // exit
52884
52885             link.exit().remove(); // enter
52886
52887             var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
52888             linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
52889           }
52890
52891           viewOnOSM.what = function (_) {
52892             if (!arguments.length) return _what;
52893             _what = _;
52894             return viewOnOSM;
52895           };
52896
52897           return viewOnOSM;
52898         }
52899
52900         function uiNoteEditor(context) {
52901           var dispatch$1 = dispatch('change');
52902           var noteComments = uiNoteComments();
52903           var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
52904
52905           var _note;
52906
52907           var _newNote; // var _fieldsArr;
52908
52909
52910           function noteEditor(selection) {
52911             var header = selection.selectAll('.header').data([0]);
52912             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
52913             headerEnter.append('button').attr('class', 'close').on('click', function () {
52914               context.enter(modeBrowse(context));
52915             }).call(svgIcon('#iD-icon-close'));
52916             headerEnter.append('h3').html(_t.html('note.title'));
52917             var body = selection.selectAll('.body').data([0]);
52918             body = body.enter().append('div').attr('class', 'body').merge(body);
52919             var editor = body.selectAll('.note-editor').data([0]);
52920             editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
52921             var footer = selection.selectAll('.footer').data([0]);
52922             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
52923
52924             var osm = services.osm;
52925
52926             if (osm) {
52927               osm.on('change.note-save', function () {
52928                 selection.call(noteEditor);
52929               });
52930             }
52931           }
52932
52933           function noteSaveSection(selection) {
52934             var isSelected = _note && _note.id === context.selectedNoteID();
52935
52936             var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
52937               return d.status + d.id;
52938             }); // exit
52939
52940             noteSave.exit().remove(); // enter
52941
52942             var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
52943             // if (_note.isNew()) {
52944             //     var presets = presetManager;
52945             //     // NOTE: this key isn't a age and therefore there is no documentation (yet)
52946             //     _fieldsArr = [
52947             //         uiField(context, presets.field('category'), null, { show: true, revert: false }),
52948             //     ];
52949             //     _fieldsArr.forEach(function(field) {
52950             //         field
52951             //             .on('change', changeCategory);
52952             //     });
52953             //     noteSaveEnter
52954             //         .append('div')
52955             //         .attr('class', 'note-category')
52956             //         .call(formFields.fieldsArr(_fieldsArr));
52957             // }
52958             // function changeCategory() {
52959             //     // NOTE: perhaps there is a better way to get value
52960             //     var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
52961             //     // store the unsaved category with the note itself
52962             //     _note = _note.update({ newCategory: val });
52963             //     var osm = services.osm;
52964             //     if (osm) {
52965             //         osm.replaceNote(_note);  // update note cache
52966             //     }
52967             //     noteSave
52968             //         .call(noteSaveButtons);
52969             // }
52970
52971             noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
52972               return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
52973             });
52974             var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
52975               return d.newComment;
52976             }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
52977
52978             if (!commentTextarea.empty() && _newNote) {
52979               // autofocus the comment field for new notes
52980               commentTextarea.node().focus();
52981             } // update
52982
52983
52984             noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
52985
52986             function keydown(d3_event) {
52987               if (!(d3_event.keyCode === 13 && // ↩ Return
52988               d3_event.metaKey)) return;
52989               var osm = services.osm;
52990               if (!osm) return;
52991               var hasAuth = osm.authenticated();
52992               if (!hasAuth) return;
52993               if (!_note.newComment) return;
52994               d3_event.preventDefault();
52995               select(this).on('keydown.note-input', null); // focus on button and submit
52996
52997               window.setTimeout(function () {
52998                 if (_note.isNew()) {
52999                   noteSave.selectAll('.save-button').node().focus();
53000                   clickSave();
53001                 } else {
53002                   noteSave.selectAll('.comment-button').node().focus();
53003                   clickComment();
53004                 }
53005               }, 10);
53006             }
53007
53008             function changeInput() {
53009               var input = select(this);
53010               var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
53011
53012               _note = _note.update({
53013                 newComment: val
53014               });
53015               var osm = services.osm;
53016
53017               if (osm) {
53018                 osm.replaceNote(_note); // update note cache
53019               }
53020
53021               noteSave.call(noteSaveButtons);
53022             }
53023           }
53024
53025           function userDetails(selection) {
53026             var detailSection = selection.selectAll('.detail-section').data([0]);
53027             detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
53028             var osm = services.osm;
53029             if (!osm) return; // Add warning if user is not logged in
53030
53031             var hasAuth = osm.authenticated();
53032             var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
53033             authWarning.exit().transition().duration(200).style('opacity', 0).remove();
53034             var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
53035             authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
53036             authEnter.append('span').html(_t.html('note.login'));
53037             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) {
53038               d3_event.preventDefault();
53039               osm.authenticate();
53040             });
53041             authEnter.transition().duration(200).style('opacity', 1);
53042             var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
53043             prose.exit().remove();
53044             prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
53045             osm.userDetails(function (err, user) {
53046               if (err) return;
53047               var userLink = select(document.createElement('div'));
53048
53049               if (user.image_url) {
53050                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
53051               }
53052
53053               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
53054               prose.html(_t.html('note.upload_explanation_with_user', {
53055                 user: userLink.html()
53056               }));
53057             });
53058           }
53059
53060           function noteSaveButtons(selection) {
53061             var osm = services.osm;
53062             var hasAuth = osm && osm.authenticated();
53063
53064             var isSelected = _note && _note.id === context.selectedNoteID();
53065
53066             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
53067               return d.status + d.id;
53068             }); // exit
53069
53070             buttonSection.exit().remove(); // enter
53071
53072             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
53073
53074             if (_note.isNew()) {
53075               buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
53076               buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
53077             } else {
53078               buttonEnter.append('button').attr('class', 'button status-button action');
53079               buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
53080             } // update
53081
53082
53083             buttonSection = buttonSection.merge(buttonEnter);
53084             buttonSection.select('.cancel-button') // select and propagate data
53085             .on('click.cancel', clickCancel);
53086             buttonSection.select('.save-button') // select and propagate data
53087             .attr('disabled', isSaveDisabled).on('click.save', clickSave);
53088             buttonSection.select('.status-button') // select and propagate data
53089             .attr('disabled', hasAuth ? null : true).html(function (d) {
53090               var action = d.status === 'open' ? 'close' : 'open';
53091               var andComment = d.newComment ? '_comment' : '';
53092               return _t('note.' + action + andComment);
53093             }).on('click.status', clickStatus);
53094             buttonSection.select('.comment-button') // select and propagate data
53095             .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
53096
53097             function isSaveDisabled(d) {
53098               return hasAuth && d.status === 'open' && d.newComment ? null : true;
53099             }
53100           }
53101
53102           function clickCancel(d3_event, d) {
53103             this.blur(); // avoid keeping focus on the button - #4641
53104
53105             var osm = services.osm;
53106
53107             if (osm) {
53108               osm.removeNote(d);
53109             }
53110
53111             context.enter(modeBrowse(context));
53112             dispatch$1.call('change');
53113           }
53114
53115           function clickSave(d3_event, d) {
53116             this.blur(); // avoid keeping focus on the button - #4641
53117
53118             var osm = services.osm;
53119
53120             if (osm) {
53121               osm.postNoteCreate(d, function (err, note) {
53122                 dispatch$1.call('change', note);
53123               });
53124             }
53125           }
53126
53127           function clickStatus(d3_event, d) {
53128             this.blur(); // avoid keeping focus on the button - #4641
53129
53130             var osm = services.osm;
53131
53132             if (osm) {
53133               var setStatus = d.status === 'open' ? 'closed' : 'open';
53134               osm.postNoteUpdate(d, setStatus, function (err, note) {
53135                 dispatch$1.call('change', note);
53136               });
53137             }
53138           }
53139
53140           function clickComment(d3_event, d) {
53141             this.blur(); // avoid keeping focus on the button - #4641
53142
53143             var osm = services.osm;
53144
53145             if (osm) {
53146               osm.postNoteUpdate(d, d.status, function (err, note) {
53147                 dispatch$1.call('change', note);
53148               });
53149             }
53150           }
53151
53152           noteEditor.note = function (val) {
53153             if (!arguments.length) return _note;
53154             _note = val;
53155             return noteEditor;
53156           };
53157
53158           noteEditor.newNote = function (val) {
53159             if (!arguments.length) return _newNote;
53160             _newNote = val;
53161             return noteEditor;
53162           };
53163
53164           return utilRebind(noteEditor, dispatch$1, 'on');
53165         }
53166
53167         function modeSelectNote(context, selectedNoteID) {
53168           var mode = {
53169             id: 'select-note',
53170             button: 'browse'
53171           };
53172
53173           var _keybinding = utilKeybinding('select-note');
53174
53175           var _noteEditor = uiNoteEditor(context).on('change', function () {
53176             context.map().pan([0, 0]); // trigger a redraw
53177
53178             var note = checkSelectedID();
53179             if (!note) return;
53180             context.ui().sidebar.show(_noteEditor.note(note));
53181           });
53182
53183           var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
53184           var _newFeature = false;
53185
53186           function checkSelectedID() {
53187             if (!services.osm) return;
53188             var note = services.osm.getNote(selectedNoteID);
53189
53190             if (!note) {
53191               context.enter(modeBrowse(context));
53192             }
53193
53194             return note;
53195           } // class the note as selected, or return to browse mode if the note is gone
53196
53197
53198           function selectNote(d3_event, drawn) {
53199             if (!checkSelectedID()) return;
53200             var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
53201
53202             if (selection.empty()) {
53203               // Return to browse mode if selected DOM elements have
53204               // disappeared because the user moved them out of view..
53205               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
53206
53207               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
53208                 context.enter(modeBrowse(context));
53209               }
53210             } else {
53211               selection.classed('selected', true);
53212               context.selectedNoteID(selectedNoteID);
53213             }
53214           }
53215
53216           function esc() {
53217             if (context.container().select('.combobox').size()) return;
53218             context.enter(modeBrowse(context));
53219           }
53220
53221           mode.zoomToSelected = function () {
53222             if (!services.osm) return;
53223             var note = services.osm.getNote(selectedNoteID);
53224
53225             if (note) {
53226               context.map().centerZoomEase(note.loc, 20);
53227             }
53228           };
53229
53230           mode.newFeature = function (val) {
53231             if (!arguments.length) return _newFeature;
53232             _newFeature = val;
53233             return mode;
53234           };
53235
53236           mode.enter = function () {
53237             var note = checkSelectedID();
53238             if (!note) return;
53239
53240             _behaviors.forEach(context.install);
53241
53242             _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
53243
53244             select(document).call(_keybinding);
53245             selectNote();
53246             var sidebar = context.ui().sidebar;
53247             sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
53248
53249             sidebar.expand(sidebar.intersects(note.extent()));
53250             context.map().on('drawn.select', selectNote);
53251           };
53252
53253           mode.exit = function () {
53254             _behaviors.forEach(context.uninstall);
53255
53256             select(document).call(_keybinding.unbind);
53257             context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
53258             context.map().on('drawn.select', null);
53259             context.ui().sidebar.hide();
53260             context.selectedNoteID(null);
53261           };
53262
53263           return mode;
53264         }
53265
53266         function modeDragNote(context) {
53267           var mode = {
53268             id: 'drag-note',
53269             button: 'browse'
53270           };
53271           var edit = behaviorEdit(context);
53272
53273           var _nudgeInterval;
53274
53275           var _lastLoc;
53276
53277           var _note; // most current note.. dragged note may have stale datum.
53278
53279
53280           function startNudge(d3_event, nudge) {
53281             if (_nudgeInterval) window.clearInterval(_nudgeInterval);
53282             _nudgeInterval = window.setInterval(function () {
53283               context.map().pan(nudge);
53284               doMove(d3_event, nudge);
53285             }, 50);
53286           }
53287
53288           function stopNudge() {
53289             if (_nudgeInterval) {
53290               window.clearInterval(_nudgeInterval);
53291               _nudgeInterval = null;
53292             }
53293           }
53294
53295           function origin(note) {
53296             return context.projection(note.loc);
53297           }
53298
53299           function start(d3_event, note) {
53300             _note = note;
53301             var osm = services.osm;
53302
53303             if (osm) {
53304               // Get latest note from cache.. The marker may have a stale datum bound to it
53305               // and dragging it around can sometimes delete the users note comment.
53306               _note = osm.getNote(_note.id);
53307             }
53308
53309             context.surface().selectAll('.note-' + _note.id).classed('active', true);
53310             context.perform(actionNoop());
53311             context.enter(mode);
53312             context.selectedNoteID(_note.id);
53313           }
53314
53315           function move(d3_event, entity, point) {
53316             d3_event.stopPropagation();
53317             _lastLoc = context.projection.invert(point);
53318             doMove(d3_event);
53319             var nudge = geoViewportEdge(point, context.map().dimensions());
53320
53321             if (nudge) {
53322               startNudge(d3_event, nudge);
53323             } else {
53324               stopNudge();
53325             }
53326           }
53327
53328           function doMove(d3_event, nudge) {
53329             nudge = nudge || [0, 0];
53330             var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
53331             var currMouse = geoVecSubtract(currPoint, nudge);
53332             var loc = context.projection.invert(currMouse);
53333             _note = _note.move(loc);
53334             var osm = services.osm;
53335
53336             if (osm) {
53337               osm.replaceNote(_note); // update note cache
53338             }
53339
53340             context.replace(actionNoop()); // trigger redraw
53341           }
53342
53343           function end() {
53344             context.replace(actionNoop()); // trigger redraw
53345
53346             context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
53347           }
53348
53349           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);
53350
53351           mode.enter = function () {
53352             context.install(edit);
53353           };
53354
53355           mode.exit = function () {
53356             context.ui().sidebar.hover.cancel();
53357             context.uninstall(edit);
53358             context.surface().selectAll('.active').classed('active', false);
53359             stopNudge();
53360           };
53361
53362           mode.behavior = drag;
53363           return mode;
53364         }
53365
53366         function uiDataHeader() {
53367           var _datum;
53368
53369           function dataHeader(selection) {
53370             var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
53371               return d.__featurehash__;
53372             });
53373             header.exit().remove();
53374             var headerEnter = header.enter().append('div').attr('class', 'data-header');
53375             var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
53376             iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
53377             headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
53378           }
53379
53380           dataHeader.datum = function (val) {
53381             if (!arguments.length) return _datum;
53382             _datum = val;
53383             return this;
53384           };
53385
53386           return dataHeader;
53387         }
53388
53389         // It is keyed on the `value` of the entry. Data should be an array of objects like:
53390         //   [{
53391         //       value:   'string value',  // required
53392         //       display: 'label html'     // optional
53393         //       title:   'hover text'     // optional
53394         //       terms:   ['search terms'] // optional
53395         //   }, ...]
53396
53397         var _comboHideTimerID;
53398
53399         function uiCombobox(context, klass) {
53400           var dispatch$1 = dispatch('accept', 'cancel');
53401           var container = context.container();
53402           var _suggestions = [];
53403           var _data = [];
53404           var _fetched = {};
53405           var _selected = null;
53406           var _canAutocomplete = true;
53407           var _caseSensitive = false;
53408           var _cancelFetch = false;
53409           var _minItems = 2;
53410           var _tDown = 0;
53411
53412           var _mouseEnterHandler, _mouseLeaveHandler;
53413
53414           var _fetcher = function _fetcher(val, cb) {
53415             cb(_data.filter(function (d) {
53416               var terms = d.terms || [];
53417               terms.push(d.value);
53418               return terms.some(function (term) {
53419                 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
53420               });
53421             }));
53422           };
53423
53424           var combobox = function combobox(input, attachTo) {
53425             if (!input || input.empty()) return;
53426             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 () {
53427               var parent = this.parentNode;
53428               var sibling = this.nextSibling;
53429               select(parent).selectAll('.combobox-caret').filter(function (d) {
53430                 return d === input.node();
53431               }).data([input.node()]).enter().insert('div', function () {
53432                 return sibling;
53433               }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
53434                 d3_event.preventDefault(); // don't steal focus from input
53435
53436                 input.node().focus(); // focus the input as if it was clicked
53437
53438                 mousedown(d3_event);
53439               }).on('mouseup.combo-caret', function (d3_event) {
53440                 d3_event.preventDefault(); // don't steal focus from input
53441
53442                 mouseup(d3_event);
53443               });
53444             });
53445
53446             function mousedown(d3_event) {
53447               if (d3_event.button !== 0) return; // left click only
53448
53449               _tDown = +new Date(); // clear selection
53450
53451               var start = input.property('selectionStart');
53452               var end = input.property('selectionEnd');
53453
53454               if (start !== end) {
53455                 var val = utilGetSetValue(input);
53456                 input.node().setSelectionRange(val.length, val.length);
53457                 return;
53458               }
53459
53460               input.on('mouseup.combo-input', mouseup);
53461             }
53462
53463             function mouseup(d3_event) {
53464               input.on('mouseup.combo-input', null);
53465               if (d3_event.button !== 0) return; // left click only
53466
53467               if (input.node() !== document.activeElement) return; // exit if this input is not focused
53468
53469               var start = input.property('selectionStart');
53470               var end = input.property('selectionEnd');
53471               if (start !== end) return; // exit if user is selecting
53472               // not showing or showing for a different field - try to show it.
53473
53474               var combo = container.selectAll('.combobox');
53475
53476               if (combo.empty() || combo.datum() !== input.node()) {
53477                 var tOrig = _tDown;
53478                 window.setTimeout(function () {
53479                   if (tOrig !== _tDown) return; // exit if user double clicked
53480
53481                   fetchComboData('', function () {
53482                     show();
53483                     render();
53484                   });
53485                 }, 250);
53486               } else {
53487                 hide();
53488               }
53489             }
53490
53491             function focus() {
53492               fetchComboData(''); // prefetch values (may warm taginfo cache)
53493             }
53494
53495             function blur() {
53496               _comboHideTimerID = window.setTimeout(hide, 75);
53497             }
53498
53499             function show() {
53500               hide(); // remove any existing
53501
53502               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) {
53503                 // prevent moving focus out of the input field
53504                 d3_event.preventDefault();
53505               });
53506               container.on('scroll.combo-scroll', render, true);
53507             }
53508
53509             function hide() {
53510               if (_comboHideTimerID) {
53511                 window.clearTimeout(_comboHideTimerID);
53512                 _comboHideTimerID = undefined;
53513               }
53514
53515               container.selectAll('.combobox').remove();
53516               container.on('scroll.combo-scroll', null);
53517             }
53518
53519             function keydown(d3_event) {
53520               var shown = !container.selectAll('.combobox').empty();
53521               var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
53522
53523               switch (d3_event.keyCode) {
53524                 case 8: // ⌫ Backspace
53525
53526                 case 46:
53527                   // ⌦ Delete
53528                   d3_event.stopPropagation();
53529                   _selected = null;
53530                   render();
53531                   input.on('input.combo-input', function () {
53532                     var start = input.property('selectionStart');
53533                     input.node().setSelectionRange(start, start);
53534                     input.on('input.combo-input', change);
53535                   });
53536                   break;
53537
53538                 case 9:
53539                   // ⇥ Tab
53540                   accept();
53541                   break;
53542
53543                 case 13:
53544                   // ↩ Return
53545                   d3_event.preventDefault();
53546                   d3_event.stopPropagation();
53547                   break;
53548
53549                 case 38:
53550                   // ↑ Up arrow
53551                   if (tagName === 'textarea' && !shown) return;
53552                   d3_event.preventDefault();
53553
53554                   if (tagName === 'input' && !shown) {
53555                     show();
53556                   }
53557
53558                   nav(-1);
53559                   break;
53560
53561                 case 40:
53562                   // ↓ Down arrow
53563                   if (tagName === 'textarea' && !shown) return;
53564                   d3_event.preventDefault();
53565
53566                   if (tagName === 'input' && !shown) {
53567                     show();
53568                   }
53569
53570                   nav(+1);
53571                   break;
53572               }
53573             }
53574
53575             function keyup(d3_event) {
53576               switch (d3_event.keyCode) {
53577                 case 27:
53578                   // ⎋ Escape
53579                   cancel();
53580                   break;
53581
53582                 case 13:
53583                   // ↩ Return
53584                   accept();
53585                   break;
53586               }
53587             } // Called whenever the input value is changed (e.g. on typing)
53588
53589
53590             function change() {
53591               fetchComboData(value(), function () {
53592                 _selected = null;
53593                 var val = input.property('value');
53594
53595                 if (_suggestions.length) {
53596                   if (input.property('selectionEnd') === val.length) {
53597                     _selected = tryAutocomplete();
53598                   }
53599
53600                   if (!_selected) {
53601                     _selected = val;
53602                   }
53603                 }
53604
53605                 if (val.length) {
53606                   var combo = container.selectAll('.combobox');
53607
53608                   if (combo.empty()) {
53609                     show();
53610                   }
53611                 } else {
53612                   hide();
53613                 }
53614
53615                 render();
53616               });
53617             } // Called when the user presses up/down arrows to navigate the list
53618
53619
53620             function nav(dir) {
53621               if (_suggestions.length) {
53622                 // try to determine previously selected index..
53623                 var index = -1;
53624
53625                 for (var i = 0; i < _suggestions.length; i++) {
53626                   if (_selected && _suggestions[i].value === _selected) {
53627                     index = i;
53628                     break;
53629                   }
53630                 } // pick new _selected
53631
53632
53633                 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
53634                 _selected = _suggestions[index].value;
53635                 input.property('value', _selected);
53636               }
53637
53638               render();
53639               ensureVisible();
53640             }
53641
53642             function ensureVisible() {
53643               var combo = container.selectAll('.combobox');
53644               if (combo.empty()) return;
53645               var containerRect = container.node().getBoundingClientRect();
53646               var comboRect = combo.node().getBoundingClientRect();
53647
53648               if (comboRect.bottom > containerRect.bottom) {
53649                 var node = attachTo ? attachTo.node() : input.node();
53650                 node.scrollIntoView({
53651                   behavior: 'instant',
53652                   block: 'center'
53653                 });
53654                 render();
53655               } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
53656
53657
53658               var selected = combo.selectAll('.combobox-option.selected').node();
53659
53660               if (selected) {
53661                 selected.scrollIntoView({
53662                   behavior: 'smooth',
53663                   block: 'nearest'
53664                 });
53665               }
53666             }
53667
53668             function value() {
53669               var value = input.property('value');
53670               var start = input.property('selectionStart');
53671               var end = input.property('selectionEnd');
53672
53673               if (start && end) {
53674                 value = value.substring(0, start);
53675               }
53676
53677               return value;
53678             }
53679
53680             function fetchComboData(v, cb) {
53681               _cancelFetch = false;
53682
53683               _fetcher.call(input, v, function (results) {
53684                 // already chose a value, don't overwrite or autocomplete it
53685                 if (_cancelFetch) return;
53686                 _suggestions = results;
53687                 results.forEach(function (d) {
53688                   _fetched[d.value] = d;
53689                 });
53690
53691                 if (cb) {
53692                   cb();
53693                 }
53694               });
53695             }
53696
53697             function tryAutocomplete() {
53698               if (!_canAutocomplete) return;
53699               var val = _caseSensitive ? value() : value().toLowerCase();
53700               if (!val) return; // Don't autocomplete if user is typing a number - #4935
53701
53702               if (!isNaN(parseFloat(val)) && isFinite(val)) return;
53703               var bestIndex = -1;
53704
53705               for (var i = 0; i < _suggestions.length; i++) {
53706                 var suggestion = _suggestions[i].value;
53707                 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
53708
53709                 if (compare === val) {
53710                   bestIndex = i;
53711                   break; // otherwise lock in the first result that starts with the search string..
53712                 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
53713                   bestIndex = i;
53714                 }
53715               }
53716
53717               if (bestIndex !== -1) {
53718                 var bestVal = _suggestions[bestIndex].value;
53719                 input.property('value', bestVal);
53720                 input.node().setSelectionRange(val.length, bestVal.length);
53721                 return bestVal;
53722               }
53723             }
53724
53725             function render() {
53726               if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
53727                 hide();
53728                 return;
53729               }
53730
53731               var shown = !container.selectAll('.combobox').empty();
53732               if (!shown) return;
53733               var combo = container.selectAll('.combobox');
53734               var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
53735                 return d.value;
53736               });
53737               options.exit().remove(); // enter/update
53738
53739               options.enter().append('a').attr('class', 'combobox-option').attr('title', function (d) {
53740                 return d.title;
53741               }).html(function (d) {
53742                 return d.display || d.value;
53743               }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
53744                 return d.value === _selected;
53745               }).on('click.combo-option', accept).order();
53746               var node = attachTo ? attachTo.node() : input.node();
53747               var containerRect = container.node().getBoundingClientRect();
53748               var rect = node.getBoundingClientRect();
53749               combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
53750             } // Dispatches an 'accept' event
53751             // Then hides the combobox.
53752
53753
53754             function accept(d3_event, d) {
53755               _cancelFetch = true;
53756               var thiz = input.node();
53757
53758               if (d) {
53759                 // user clicked on a suggestion
53760                 utilGetSetValue(input, d.value); // replace field contents
53761
53762                 utilTriggerEvent(input, 'change');
53763               } // clear (and keep) selection
53764
53765
53766               var val = utilGetSetValue(input);
53767               thiz.setSelectionRange(val.length, val.length);
53768               d = _fetched[val];
53769               dispatch$1.call('accept', thiz, d, val);
53770               hide();
53771             } // Dispatches an 'cancel' event
53772             // Then hides the combobox.
53773
53774
53775             function cancel() {
53776               _cancelFetch = true;
53777               var thiz = input.node(); // clear (and remove) selection, and replace field contents
53778
53779               var val = utilGetSetValue(input);
53780               var start = input.property('selectionStart');
53781               var end = input.property('selectionEnd');
53782               val = val.slice(0, start) + val.slice(end);
53783               utilGetSetValue(input, val);
53784               thiz.setSelectionRange(val.length, val.length);
53785               dispatch$1.call('cancel', thiz);
53786               hide();
53787             }
53788           };
53789
53790           combobox.canAutocomplete = function (val) {
53791             if (!arguments.length) return _canAutocomplete;
53792             _canAutocomplete = val;
53793             return combobox;
53794           };
53795
53796           combobox.caseSensitive = function (val) {
53797             if (!arguments.length) return _caseSensitive;
53798             _caseSensitive = val;
53799             return combobox;
53800           };
53801
53802           combobox.data = function (val) {
53803             if (!arguments.length) return _data;
53804             _data = val;
53805             return combobox;
53806           };
53807
53808           combobox.fetcher = function (val) {
53809             if (!arguments.length) return _fetcher;
53810             _fetcher = val;
53811             return combobox;
53812           };
53813
53814           combobox.minItems = function (val) {
53815             if (!arguments.length) return _minItems;
53816             _minItems = val;
53817             return combobox;
53818           };
53819
53820           combobox.itemsMouseEnter = function (val) {
53821             if (!arguments.length) return _mouseEnterHandler;
53822             _mouseEnterHandler = val;
53823             return combobox;
53824           };
53825
53826           combobox.itemsMouseLeave = function (val) {
53827             if (!arguments.length) return _mouseLeaveHandler;
53828             _mouseLeaveHandler = val;
53829             return combobox;
53830           };
53831
53832           return utilRebind(combobox, dispatch$1, 'on');
53833         }
53834
53835         uiCombobox.off = function (input, context) {
53836           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);
53837           context.container().on('scroll.combo-scroll', null);
53838         };
53839
53840         // hide class, which sets display=none, and a d3 transition for opacity.
53841         // this will cause blinking when called repeatedly, so check that the
53842         // value actually changes between calls.
53843
53844         function uiToggle(show, callback) {
53845           return function (selection) {
53846             selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
53847               select(this).classed('hide', !show).style('opacity', null);
53848               if (callback) callback.apply(this);
53849             });
53850           };
53851         }
53852
53853         function uiDisclosure(context, key, expandedDefault) {
53854           var dispatch$1 = dispatch('toggled');
53855
53856           var _expanded;
53857
53858           var _label = utilFunctor('');
53859
53860           var _updatePreference = true;
53861
53862           var _content = function _content() {};
53863
53864           var disclosure = function disclosure(selection) {
53865             if (_expanded === undefined || _expanded === null) {
53866               // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
53867               var preference = corePreferences('disclosure.' + key + '.expanded');
53868               _expanded = preference === null ? !!expandedDefault : preference === 'true';
53869             }
53870
53871             var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
53872
53873             var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
53874             hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
53875
53876             hideToggle = hideToggleEnter.merge(hideToggle);
53877             hideToggle.on('click', toggle).classed('expanded', _expanded);
53878             hideToggle.selectAll('.hide-toggle-text').html(_label());
53879             hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
53880             var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
53881
53882             wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
53883
53884             if (_expanded) {
53885               wrap.call(_content);
53886             }
53887
53888             function toggle(d3_event) {
53889               d3_event.preventDefault();
53890               _expanded = !_expanded;
53891
53892               if (_updatePreference) {
53893                 corePreferences('disclosure.' + key + '.expanded', _expanded);
53894               }
53895
53896               hideToggle.classed('expanded', _expanded);
53897               hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
53898               wrap.call(uiToggle(_expanded));
53899
53900               if (_expanded) {
53901                 wrap.call(_content);
53902               }
53903
53904               dispatch$1.call('toggled', this, _expanded);
53905             }
53906           };
53907
53908           disclosure.label = function (val) {
53909             if (!arguments.length) return _label;
53910             _label = utilFunctor(val);
53911             return disclosure;
53912           };
53913
53914           disclosure.expanded = function (val) {
53915             if (!arguments.length) return _expanded;
53916             _expanded = val;
53917             return disclosure;
53918           };
53919
53920           disclosure.updatePreference = function (val) {
53921             if (!arguments.length) return _updatePreference;
53922             _updatePreference = val;
53923             return disclosure;
53924           };
53925
53926           disclosure.content = function (val) {
53927             if (!arguments.length) return _content;
53928             _content = val;
53929             return disclosure;
53930           };
53931
53932           return utilRebind(disclosure, dispatch$1, 'on');
53933         }
53934
53935         // Can be labeled and collapsible.
53936
53937         function uiSection(id, context) {
53938           var _classes = utilFunctor('');
53939
53940           var _shouldDisplay;
53941
53942           var _content;
53943
53944           var _disclosure;
53945
53946           var _label;
53947
53948           var _expandedByDefault = utilFunctor(true);
53949
53950           var _disclosureContent;
53951
53952           var _disclosureExpanded;
53953
53954           var _containerSelection = select(null);
53955
53956           var section = {
53957             id: id
53958           };
53959
53960           section.classes = function (val) {
53961             if (!arguments.length) return _classes;
53962             _classes = utilFunctor(val);
53963             return section;
53964           };
53965
53966           section.label = function (val) {
53967             if (!arguments.length) return _label;
53968             _label = utilFunctor(val);
53969             return section;
53970           };
53971
53972           section.expandedByDefault = function (val) {
53973             if (!arguments.length) return _expandedByDefault;
53974             _expandedByDefault = utilFunctor(val);
53975             return section;
53976           };
53977
53978           section.shouldDisplay = function (val) {
53979             if (!arguments.length) return _shouldDisplay;
53980             _shouldDisplay = utilFunctor(val);
53981             return section;
53982           };
53983
53984           section.content = function (val) {
53985             if (!arguments.length) return _content;
53986             _content = val;
53987             return section;
53988           };
53989
53990           section.disclosureContent = function (val) {
53991             if (!arguments.length) return _disclosureContent;
53992             _disclosureContent = val;
53993             return section;
53994           };
53995
53996           section.disclosureExpanded = function (val) {
53997             if (!arguments.length) return _disclosureExpanded;
53998             _disclosureExpanded = val;
53999             return section;
54000           }; // may be called multiple times
54001
54002
54003           section.render = function (selection) {
54004             _containerSelection = selection.selectAll('.section-' + id).data([0]);
54005
54006             var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
54007
54008             _containerSelection = sectionEnter.merge(_containerSelection);
54009
54010             _containerSelection.call(renderContent);
54011           };
54012
54013           section.reRender = function () {
54014             _containerSelection.call(renderContent);
54015           };
54016
54017           section.selection = function () {
54018             return _containerSelection;
54019           };
54020
54021           section.disclosure = function () {
54022             return _disclosure;
54023           }; // may be called multiple times
54024
54025
54026           function renderContent(selection) {
54027             if (_shouldDisplay) {
54028               var shouldDisplay = _shouldDisplay();
54029
54030               selection.classed('hide', !shouldDisplay);
54031
54032               if (!shouldDisplay) {
54033                 selection.html('');
54034                 return;
54035               }
54036             }
54037
54038             if (_disclosureContent) {
54039               if (!_disclosure) {
54040                 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
54041                 /*.on('toggled', function(expanded) {
54042                     if (expanded) { selection.node().parentNode.scrollTop += 200; }
54043                 })*/
54044                 .content(_disclosureContent);
54045               }
54046
54047               if (_disclosureExpanded !== undefined) {
54048                 _disclosure.expanded(_disclosureExpanded);
54049
54050                 _disclosureExpanded = undefined;
54051               }
54052
54053               selection.call(_disclosure);
54054               return;
54055             }
54056
54057             if (_content) {
54058               selection.call(_content);
54059             }
54060           }
54061
54062           return section;
54063         }
54064
54065         // {
54066         //   key: 'string',     // required
54067         //   value: 'string'    // optional
54068         // }
54069         //   -or-
54070         // {
54071         //   qid: 'string'      // brand wikidata  (e.g. 'Q37158')
54072         // }
54073         //
54074
54075         function uiTagReference(what) {
54076           var wikibase = what.qid ? services.wikidata : services.osmWikibase;
54077           var tagReference = {};
54078
54079           var _button = select(null);
54080
54081           var _body = select(null);
54082
54083           var _loaded;
54084
54085           var _showing;
54086
54087           function load() {
54088             if (!wikibase) return;
54089
54090             _button.classed('tag-reference-loading', true);
54091
54092             wikibase.getDocs(what, gotDocs);
54093           }
54094
54095           function gotDocs(err, docs) {
54096             _body.html('');
54097
54098             if (!docs || !docs.title) {
54099               _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
54100
54101               done();
54102               return;
54103             }
54104
54105             if (docs.imageURL) {
54106               _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
54107                 done();
54108               }).on('error', function () {
54109                 select(this).remove();
54110                 done();
54111               });
54112             } else {
54113               done();
54114             }
54115
54116             _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'));
54117
54118             if (docs.wiki) {
54119               _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));
54120             } // Add link to info about "good changeset comments" - #2923
54121
54122
54123             if (what.key === 'comment') {
54124               _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'));
54125             }
54126           }
54127
54128           function done() {
54129             _loaded = true;
54130
54131             _button.classed('tag-reference-loading', false);
54132
54133             _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
54134
54135             _showing = true;
54136
54137             _button.selectAll('svg.icon use').each(function () {
54138               var iconUse = select(this);
54139
54140               if (iconUse.attr('href') === '#iD-icon-info') {
54141                 iconUse.attr('href', '#iD-icon-info-filled');
54142               }
54143             });
54144           }
54145
54146           function hide() {
54147             _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
54148               _body.classed('expanded', false);
54149             });
54150
54151             _showing = false;
54152
54153             _button.selectAll('svg.icon use').each(function () {
54154               var iconUse = select(this);
54155
54156               if (iconUse.attr('href') === '#iD-icon-info-filled') {
54157                 iconUse.attr('href', '#iD-icon-info');
54158               }
54159             });
54160           }
54161
54162           tagReference.button = function (selection, klass, iconName) {
54163             _button = selection.selectAll('.tag-reference-button').data([0]);
54164             _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
54165
54166             _button.on('click', function (d3_event) {
54167               d3_event.stopPropagation();
54168               d3_event.preventDefault();
54169               this.blur(); // avoid keeping focus on the button - #4641
54170
54171               if (_showing) {
54172                 hide();
54173               } else if (_loaded) {
54174                 done();
54175               } else {
54176                 load();
54177               }
54178             });
54179           };
54180
54181           tagReference.body = function (selection) {
54182             var itemID = what.qid || what.key + '-' + (what.value || '');
54183             _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
54184               return d;
54185             });
54186
54187             _body.exit().remove();
54188
54189             _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
54190
54191             if (_showing === false) {
54192               hide();
54193             }
54194           };
54195
54196           tagReference.showing = function (val) {
54197             if (!arguments.length) return _showing;
54198             _showing = val;
54199             return tagReference;
54200           };
54201
54202           return tagReference;
54203         }
54204
54205         function uiSectionRawTagEditor(id, context) {
54206           var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
54207             var count = Object.keys(_tags).filter(function (d) {
54208               return d;
54209             }).length;
54210             return _t('inspector.title_count', {
54211               title: _t.html('inspector.tags'),
54212               count: count
54213             });
54214           }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
54215           var taginfo = services.taginfo;
54216           var dispatch$1 = dispatch('change');
54217           var availableViews = [{
54218             id: 'list',
54219             icon: '#fas-th-list'
54220           }, {
54221             id: 'text',
54222             icon: '#fas-i-cursor'
54223           }];
54224
54225           var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
54226
54227
54228           var _readOnlyTags = []; // the keys in the order we want them to display
54229
54230           var _orderedKeys = [];
54231           var _showBlank = false;
54232           var _pendingChange = null;
54233
54234           var _state;
54235
54236           var _presets;
54237
54238           var _tags;
54239
54240           var _entityIDs;
54241
54242           var _didInteract = false;
54243
54244           function interacted() {
54245             _didInteract = true;
54246           }
54247
54248           function renderDisclosureContent(wrap) {
54249             // remove deleted keys
54250             _orderedKeys = _orderedKeys.filter(function (key) {
54251               return _tags[key] !== undefined;
54252             }); // When switching to a different entity or changing the state (hover/select)
54253             // reorder the keys alphabetically.
54254             // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
54255             // Otherwise leave their order alone - #5857, #5927
54256
54257             var all = Object.keys(_tags).sort();
54258             var missingKeys = utilArrayDifference(all, _orderedKeys);
54259
54260             for (var i in missingKeys) {
54261               _orderedKeys.push(missingKeys[i]);
54262             } // assemble row data
54263
54264
54265             var rowData = _orderedKeys.map(function (key, i) {
54266               return {
54267                 index: i,
54268                 key: key,
54269                 value: _tags[key]
54270               };
54271             }); // append blank row last, if necessary
54272
54273
54274             if (!rowData.length || _showBlank) {
54275               _showBlank = false;
54276               rowData.push({
54277                 index: rowData.length,
54278                 key: '',
54279                 value: ''
54280               });
54281             } // View Options
54282
54283
54284             var options = wrap.selectAll('.raw-tag-options').data([0]);
54285             options.exit().remove();
54286             var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
54287             var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
54288               return d.id;
54289             }).enter();
54290             optionEnter.append('button').attr('class', function (d) {
54291               return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
54292             }).attr('title', function (d) {
54293               return _t('icons.' + d.id);
54294             }).on('click', function (d3_event, d) {
54295               _tagView = d.id;
54296               corePreferences('raw-tag-editor-view', d.id);
54297               wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
54298                 return datum === d;
54299               });
54300               wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
54301               wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
54302             }).each(function (d) {
54303               select(this).call(svgIcon(d.icon));
54304             }); // View as Text
54305
54306             var textData = rowsToText(rowData);
54307             var textarea = wrap.selectAll('.tag-text').data([0]);
54308             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);
54309             textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
54310
54311             var list = wrap.selectAll('.tag-list').data([0]);
54312             list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
54313
54314             var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
54315             addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
54316             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
54317
54318             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
54319             // Tag list items
54320
54321             var items = list.selectAll('.tag-row').data(rowData, function (d) {
54322               return d.key;
54323             });
54324             items.exit().each(unbind).remove(); // Enter
54325
54326             var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
54327             var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
54328             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);
54329             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);
54330             innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
54331
54332             items = items.merge(itemsEnter).sort(function (a, b) {
54333               return a.index - b.index;
54334             });
54335             items.each(function (d) {
54336               var row = select(this);
54337               var key = row.select('input.key'); // propagate bound data
54338
54339               var value = row.select('input.value'); // propagate bound data
54340
54341               if (_entityIDs && taginfo && _state !== 'hover') {
54342                 bindTypeahead(key, value);
54343               }
54344
54345               var referenceOptions = {
54346                 key: d.key
54347               };
54348
54349               if (typeof d.value === 'string') {
54350                 referenceOptions.value = d.value;
54351               }
54352
54353               var reference = uiTagReference(referenceOptions);
54354
54355               if (_state === 'hover') {
54356                 reference.showing(false);
54357               }
54358
54359               row.select('.inner-wrap') // propagate bound data
54360               .call(reference.button);
54361               row.call(reference.body);
54362               row.select('button.remove'); // propagate bound data
54363             });
54364             items.selectAll('input.key').attr('title', function (d) {
54365               return d.key;
54366             }).call(utilGetSetValue, function (d) {
54367               return d.key;
54368             }).attr('readonly', function (d) {
54369               return isReadOnly(d) || typeof d.value !== 'string' || null;
54370             });
54371             items.selectAll('input.value').attr('title', function (d) {
54372               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
54373             }).classed('mixed', function (d) {
54374               return Array.isArray(d.value);
54375             }).attr('placeholder', function (d) {
54376               return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
54377             }).call(utilGetSetValue, function (d) {
54378               return typeof d.value === 'string' ? d.value : '';
54379             }).attr('readonly', function (d) {
54380               return isReadOnly(d) || null;
54381             });
54382             items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
54383           }
54384
54385           function isReadOnly(d) {
54386             for (var i = 0; i < _readOnlyTags.length; i++) {
54387               if (d.key.match(_readOnlyTags[i]) !== null) {
54388                 return true;
54389               }
54390             }
54391
54392             return false;
54393           }
54394
54395           function setTextareaHeight() {
54396             if (_tagView !== 'text') return;
54397             var selection = select(this);
54398             var matches = selection.node().value.match(/\n/g);
54399             var lineCount = 2 + Number(matches && matches.length);
54400             var lineHeight = 20;
54401             selection.style('height', lineCount * lineHeight + 'px');
54402           }
54403
54404           function stringify(s) {
54405             return JSON.stringify(s).slice(1, -1); // without leading/trailing "
54406           }
54407
54408           function unstringify(s) {
54409             var leading = '';
54410             var trailing = '';
54411
54412             if (s.length < 1 || s.charAt(0) !== '"') {
54413               leading = '"';
54414             }
54415
54416             if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
54417               trailing = '"';
54418             }
54419
54420             return JSON.parse(leading + s + trailing);
54421           }
54422
54423           function rowsToText(rows) {
54424             var str = rows.filter(function (row) {
54425               return row.key && row.key.trim() !== '';
54426             }).map(function (row) {
54427               var rawVal = row.value;
54428               if (typeof rawVal !== 'string') rawVal = '*';
54429               var val = rawVal ? stringify(rawVal) : '';
54430               return stringify(row.key) + '=' + val;
54431             }).join('\n');
54432
54433             if (_state !== 'hover' && str.length) {
54434               return str + '\n';
54435             }
54436
54437             return str;
54438           }
54439
54440           function textChanged() {
54441             var newText = this.value.trim();
54442             var newTags = {};
54443             newText.split('\n').forEach(function (row) {
54444               var m = row.match(/^\s*([^=]+)=(.*)$/);
54445
54446               if (m !== null) {
54447                 var k = context.cleanTagKey(unstringify(m[1].trim()));
54448                 var v = context.cleanTagValue(unstringify(m[2].trim()));
54449                 newTags[k] = v;
54450               }
54451             });
54452             var tagDiff = utilTagDiff(_tags, newTags);
54453             if (!tagDiff.length) return;
54454             _pendingChange = _pendingChange || {};
54455             tagDiff.forEach(function (change) {
54456               if (isReadOnly({
54457                 key: change.key
54458               })) return; // skip unchanged multiselection placeholders
54459
54460               if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
54461
54462               if (change.type === '-') {
54463                 _pendingChange[change.key] = undefined;
54464               } else if (change.type === '+') {
54465                 _pendingChange[change.key] = change.newVal || '';
54466               }
54467             });
54468
54469             if (Object.keys(_pendingChange).length === 0) {
54470               _pendingChange = null;
54471               return;
54472             }
54473
54474             scheduleChange();
54475           }
54476
54477           function pushMore(d3_event) {
54478             // if pressing Tab on the last value field with content, add a blank row
54479             if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
54480               addTag();
54481             }
54482           }
54483
54484           function bindTypeahead(key, value) {
54485             if (isReadOnly(key.datum())) return;
54486
54487             if (Array.isArray(value.datum().value)) {
54488               value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
54489                 var keyString = utilGetSetValue(key);
54490                 if (!_tags[keyString]) return;
54491
54492                 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
54493                   return {
54494                     value: tagValue,
54495                     title: tagValue
54496                   };
54497                 });
54498
54499                 callback(data);
54500               }));
54501               return;
54502             }
54503
54504             var geometry = context.graph().geometry(_entityIDs[0]);
54505             key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
54506               taginfo.keys({
54507                 debounce: true,
54508                 geometry: geometry,
54509                 query: value
54510               }, function (err, data) {
54511                 if (!err) {
54512                   var filtered = data.filter(function (d) {
54513                     return _tags[d.value] === undefined;
54514                   });
54515                   callback(sort(value, filtered));
54516                 }
54517               });
54518             }));
54519             value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
54520               taginfo.values({
54521                 debounce: true,
54522                 key: utilGetSetValue(key),
54523                 geometry: geometry,
54524                 query: value
54525               }, function (err, data) {
54526                 if (!err) callback(sort(value, data));
54527               });
54528             }));
54529
54530             function sort(value, data) {
54531               var sameletter = [];
54532               var other = [];
54533
54534               for (var i = 0; i < data.length; i++) {
54535                 if (data[i].value.substring(0, value.length) === value) {
54536                   sameletter.push(data[i]);
54537                 } else {
54538                   other.push(data[i]);
54539                 }
54540               }
54541
54542               return sameletter.concat(other);
54543             }
54544           }
54545
54546           function unbind() {
54547             var row = select(this);
54548             row.selectAll('input.key').call(uiCombobox.off, context);
54549             row.selectAll('input.value').call(uiCombobox.off, context);
54550           }
54551
54552           function keyChange(d3_event, d) {
54553             if (select(this).attr('readonly')) return;
54554             var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
54555
54556             if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
54557             var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
54558
54559             if (isReadOnly({
54560               key: kNew
54561             })) {
54562               this.value = kOld;
54563               return;
54564             }
54565
54566             if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
54567               // new key is already in use, switch focus to the existing row
54568               this.value = kOld; // reset the key
54569
54570               section.selection().selectAll('.tag-list input.value').each(function (d) {
54571                 if (d.key === kNew) {
54572                   // send focus to that other value combo instead
54573                   var input = select(this).node();
54574                   input.focus();
54575                   input.select();
54576                 }
54577               });
54578               return;
54579             }
54580
54581             var row = this.parentNode.parentNode;
54582             var inputVal = select(row).selectAll('input.value');
54583             var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
54584             _pendingChange = _pendingChange || {};
54585
54586             if (kOld) {
54587               _pendingChange[kOld] = undefined;
54588             }
54589
54590             _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
54591
54592             var existingKeyIndex = _orderedKeys.indexOf(kOld);
54593
54594             if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
54595             d.key = kNew; // update datum to avoid exit/enter on tag update
54596
54597             d.value = vNew;
54598             this.value = kNew;
54599             utilGetSetValue(inputVal, vNew);
54600             scheduleChange();
54601           }
54602
54603           function valueChange(d3_event, d) {
54604             if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
54605
54606             if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
54607
54608             if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
54609             _pendingChange = _pendingChange || {};
54610             _pendingChange[d.key] = context.cleanTagValue(this.value);
54611             scheduleChange();
54612           }
54613
54614           function removeTag(d3_event, d) {
54615             if (isReadOnly(d)) return;
54616
54617             if (d.key === '') {
54618               // removing the blank row
54619               _showBlank = false;
54620               section.reRender();
54621             } else {
54622               // remove the key from the ordered key index
54623               _orderedKeys = _orderedKeys.filter(function (key) {
54624                 return key !== d.key;
54625               });
54626               _pendingChange = _pendingChange || {};
54627               _pendingChange[d.key] = undefined;
54628               scheduleChange();
54629             }
54630           }
54631
54632           function addTag() {
54633             // Delay render in case this click is blurring an edited combo.
54634             // Without the setTimeout, the `content` render would wipe out the pending tag change.
54635             window.setTimeout(function () {
54636               _showBlank = true;
54637               section.reRender();
54638               section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
54639             }, 20);
54640           }
54641
54642           function scheduleChange() {
54643             // Cache IDs in case the editor is reloaded before the change event is called. - #6028
54644             var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
54645
54646             window.setTimeout(function () {
54647               if (!_pendingChange) return;
54648               dispatch$1.call('change', this, entityIDs, _pendingChange);
54649               _pendingChange = null;
54650             }, 10);
54651           }
54652
54653           section.state = function (val) {
54654             if (!arguments.length) return _state;
54655
54656             if (_state !== val) {
54657               _orderedKeys = [];
54658               _state = val;
54659             }
54660
54661             return section;
54662           };
54663
54664           section.presets = function (val) {
54665             if (!arguments.length) return _presets;
54666             _presets = val;
54667
54668             if (_presets && _presets.length && _presets[0].isFallback()) {
54669               section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
54670             } else if (!_didInteract) {
54671               section.disclosureExpanded(null);
54672             }
54673
54674             return section;
54675           };
54676
54677           section.tags = function (val) {
54678             if (!arguments.length) return _tags;
54679             _tags = val;
54680             return section;
54681           };
54682
54683           section.entityIDs = function (val) {
54684             if (!arguments.length) return _entityIDs;
54685
54686             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
54687               _entityIDs = val;
54688               _orderedKeys = [];
54689             }
54690
54691             return section;
54692           }; // pass an array of regular expressions to test against the tag key
54693
54694
54695           section.readOnlyTags = function (val) {
54696             if (!arguments.length) return _readOnlyTags;
54697             _readOnlyTags = val;
54698             return section;
54699           };
54700
54701           return utilRebind(section, dispatch$1, 'on');
54702         }
54703
54704         function uiDataEditor(context) {
54705           var dataHeader = uiDataHeader();
54706           var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
54707
54708           var _datum;
54709
54710           function dataEditor(selection) {
54711             var header = selection.selectAll('.header').data([0]);
54712             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
54713             headerEnter.append('button').attr('class', 'close').on('click', function () {
54714               context.enter(modeBrowse(context));
54715             }).call(svgIcon('#iD-icon-close'));
54716             headerEnter.append('h3').html(_t.html('map_data.title'));
54717             var body = selection.selectAll('.body').data([0]);
54718             body = body.enter().append('div').attr('class', 'body').merge(body);
54719             var editor = body.selectAll('.data-editor').data([0]); // enter/update
54720
54721             editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
54722             var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
54723
54724             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);
54725           }
54726
54727           dataEditor.datum = function (val) {
54728             if (!arguments.length) return _datum;
54729             _datum = val;
54730             return this;
54731           };
54732
54733           return dataEditor;
54734         }
54735
54736         function modeSelectData(context, selectedDatum) {
54737           var mode = {
54738             id: 'select-data',
54739             button: 'browse'
54740           };
54741           var keybinding = utilKeybinding('select-data');
54742           var dataEditor = uiDataEditor(context);
54743           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
54744
54745           function selectData(d3_event, drawn) {
54746             var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
54747
54748             if (selection.empty()) {
54749               // Return to browse mode if selected DOM elements have
54750               // disappeared because the user moved them out of view..
54751               var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
54752
54753               if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
54754                 context.enter(modeBrowse(context));
54755               }
54756             } else {
54757               selection.classed('selected', true);
54758             }
54759           }
54760
54761           function esc() {
54762             if (context.container().select('.combobox').size()) return;
54763             context.enter(modeBrowse(context));
54764           }
54765
54766           mode.zoomToSelected = function () {
54767             var extent = geoExtent(d3_geoBounds(selectedDatum));
54768             context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
54769           };
54770
54771           mode.enter = function () {
54772             behaviors.forEach(context.install);
54773             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
54774             select(document).call(keybinding);
54775             selectData();
54776             var sidebar = context.ui().sidebar;
54777             sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
54778
54779             var extent = geoExtent(d3_geoBounds(selectedDatum));
54780             sidebar.expand(sidebar.intersects(extent));
54781             context.map().on('drawn.select-data', selectData);
54782           };
54783
54784           mode.exit = function () {
54785             behaviors.forEach(context.uninstall);
54786             select(document).call(keybinding.unbind);
54787             context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
54788             context.map().on('drawn.select-data', null);
54789             context.ui().sidebar.hide();
54790           };
54791
54792           return mode;
54793         }
54794
54795         function uiImproveOsmComments() {
54796           var _qaItem;
54797
54798           function issueComments(selection) {
54799             // make the div immediately so it appears above the buttons
54800             var comments = selection.selectAll('.comments-container').data([0]);
54801             comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
54802
54803             services.improveOSM.getComments(_qaItem).then(function (d) {
54804               if (!d.comments) return; // nothing to do here
54805
54806               var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
54807               commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
54808               var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
54809               var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
54810               metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
54811                 var osm = services.osm;
54812                 var selection = select(this);
54813
54814                 if (osm && d.username) {
54815                   selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
54816                 }
54817
54818                 selection.html(function (d) {
54819                   return d.username;
54820                 });
54821               });
54822               metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
54823                 return _t.html('note.status.commented', {
54824                   when: localeDateString(d.timestamp)
54825                 });
54826               });
54827               mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
54828                 return d.text;
54829               });
54830             })["catch"](function (err) {
54831               console.log(err); // eslint-disable-line no-console
54832             });
54833           }
54834
54835           function localeDateString(s) {
54836             if (!s) return null;
54837             var options = {
54838               day: 'numeric',
54839               month: 'short',
54840               year: 'numeric'
54841             };
54842             var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
54843
54844             if (isNaN(d.getTime())) return null;
54845             return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
54846           }
54847
54848           issueComments.issue = function (val) {
54849             if (!arguments.length) return _qaItem;
54850             _qaItem = val;
54851             return issueComments;
54852           };
54853
54854           return issueComments;
54855         }
54856
54857         function uiImproveOsmDetails(context) {
54858           var _qaItem;
54859
54860           function issueDetail(d) {
54861             if (d.desc) return d.desc;
54862             var issueKey = d.issueKey;
54863             d.replacements = d.replacements || {};
54864             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
54865
54866             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
54867           }
54868
54869           function improveOsmDetails(selection) {
54870             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
54871               return "".concat(d.id, "-").concat(d.status || 0);
54872             });
54873             details.exit().remove();
54874             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
54875
54876             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
54877             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
54878             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
54879
54880             var relatedEntities = [];
54881             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
54882               var link = select(this);
54883               var isObjectLink = link.classed('error_object_link');
54884               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
54885               var entity = context.hasEntity(entityID);
54886               relatedEntities.push(entityID); // Add click handler
54887
54888               link.on('mouseenter', function () {
54889                 utilHighlightEntities([entityID], true, context);
54890               }).on('mouseleave', function () {
54891                 utilHighlightEntities([entityID], false, context);
54892               }).on('click', function (d3_event) {
54893                 d3_event.preventDefault();
54894                 utilHighlightEntities([entityID], false, context);
54895                 var osmlayer = context.layers().layer('osm');
54896
54897                 if (!osmlayer.enabled()) {
54898                   osmlayer.enabled(true);
54899                 }
54900
54901                 context.map().centerZoom(_qaItem.loc, 20);
54902
54903                 if (entity) {
54904                   context.enter(modeSelect(context, [entityID]));
54905                 } else {
54906                   context.loadEntity(entityID, function () {
54907                     context.enter(modeSelect(context, [entityID]));
54908                   });
54909                 }
54910               }); // Replace with friendly name if possible
54911               // (The entity may not yet be loaded into the graph)
54912
54913               if (entity) {
54914                 var name = utilDisplayName(entity); // try to use common name
54915
54916                 if (!name && !isObjectLink) {
54917                   var preset = _mainPresetIndex.match(entity, context.graph());
54918                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
54919                 }
54920
54921                 if (name) {
54922                   this.innerText = name;
54923                 }
54924               }
54925             }); // Don't hide entities related to this error - #5880
54926
54927             context.features().forceVisible(relatedEntities);
54928             context.map().pan([0, 0]); // trigger a redraw
54929           }
54930
54931           improveOsmDetails.issue = function (val) {
54932             if (!arguments.length) return _qaItem;
54933             _qaItem = val;
54934             return improveOsmDetails;
54935           };
54936
54937           return improveOsmDetails;
54938         }
54939
54940         function uiImproveOsmHeader() {
54941           var _qaItem;
54942
54943           function issueTitle(d) {
54944             var issueKey = d.issueKey;
54945             d.replacements = d.replacements || {};
54946             d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
54947
54948             return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
54949           }
54950
54951           function improveOsmHeader(selection) {
54952             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
54953               return "".concat(d.id, "-").concat(d.status || 0);
54954             });
54955             header.exit().remove();
54956             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
54957             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
54958               return d.id < 0;
54959             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
54960               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
54961             });
54962             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');
54963             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
54964               var picon = d.icon;
54965
54966               if (!picon) {
54967                 return '';
54968               } else {
54969                 var isMaki = /^maki-/.test(picon);
54970                 return "#".concat(picon).concat(isMaki ? '-11' : '');
54971               }
54972             });
54973             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
54974           }
54975
54976           improveOsmHeader.issue = function (val) {
54977             if (!arguments.length) return _qaItem;
54978             _qaItem = val;
54979             return improveOsmHeader;
54980           };
54981
54982           return improveOsmHeader;
54983         }
54984
54985         function uiImproveOsmEditor(context) {
54986           var dispatch$1 = dispatch('change');
54987           var qaDetails = uiImproveOsmDetails(context);
54988           var qaComments = uiImproveOsmComments();
54989           var qaHeader = uiImproveOsmHeader();
54990
54991           var _qaItem;
54992
54993           function improveOsmEditor(selection) {
54994             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
54995             headerEnter.append('button').attr('class', 'close').on('click', function () {
54996               return context.enter(modeBrowse(context));
54997             }).call(svgIcon('#iD-icon-close'));
54998             headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
54999             var body = selection.selectAll('.body').data([0]);
55000             body = body.enter().append('div').attr('class', 'body').merge(body);
55001             var editor = body.selectAll('.qa-editor').data([0]);
55002             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);
55003           }
55004
55005           function improveOsmSaveSection(selection) {
55006             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55007
55008             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
55009             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55010               return "".concat(d.id, "-").concat(d.status || 0);
55011             }); // exit
55012
55013             saveSection.exit().remove(); // enter
55014
55015             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
55016             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
55017             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
55018               return d.newComment;
55019             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
55020
55021             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55022
55023             function changeInput() {
55024               var input = select(this);
55025               var val = input.property('value').trim();
55026
55027               if (val === '') {
55028                 val = undefined;
55029               } // store the unsaved comment with the issue itself
55030
55031
55032               _qaItem = _qaItem.update({
55033                 newComment: val
55034               });
55035               var qaService = services.improveOSM;
55036
55037               if (qaService) {
55038                 qaService.replaceItem(_qaItem);
55039               }
55040
55041               saveSection.call(qaSaveButtons);
55042             }
55043           }
55044
55045           function qaSaveButtons(selection) {
55046             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55047
55048             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55049               return d.status + d.id;
55050             }); // exit
55051
55052             buttonSection.exit().remove(); // enter
55053
55054             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55055             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
55056             buttonEnter.append('button').attr('class', 'button close-button action');
55057             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55058
55059             buttonSection = buttonSection.merge(buttonEnter);
55060             buttonSection.select('.comment-button').attr('disabled', function (d) {
55061               return d.newComment ? null : true;
55062             }).on('click.comment', function (d3_event, d) {
55063               this.blur(); // avoid keeping focus on the button - #4641
55064
55065               var qaService = services.improveOSM;
55066
55067               if (qaService) {
55068                 qaService.postUpdate(d, function (err, item) {
55069                   return dispatch$1.call('change', item);
55070                 });
55071               }
55072             });
55073             buttonSection.select('.close-button').html(function (d) {
55074               var andComment = d.newComment ? '_comment' : '';
55075               return _t.html("QA.keepRight.close".concat(andComment));
55076             }).on('click.close', function (d3_event, d) {
55077               this.blur(); // avoid keeping focus on the button - #4641
55078
55079               var qaService = services.improveOSM;
55080
55081               if (qaService) {
55082                 d.newStatus = 'SOLVED';
55083                 qaService.postUpdate(d, function (err, item) {
55084                   return dispatch$1.call('change', item);
55085                 });
55086               }
55087             });
55088             buttonSection.select('.ignore-button').html(function (d) {
55089               var andComment = d.newComment ? '_comment' : '';
55090               return _t.html("QA.keepRight.ignore".concat(andComment));
55091             }).on('click.ignore', function (d3_event, d) {
55092               this.blur(); // avoid keeping focus on the button - #4641
55093
55094               var qaService = services.improveOSM;
55095
55096               if (qaService) {
55097                 d.newStatus = 'INVALID';
55098                 qaService.postUpdate(d, function (err, item) {
55099                   return dispatch$1.call('change', item);
55100                 });
55101               }
55102             });
55103           } // NOTE: Don't change method name until UI v3 is merged
55104
55105
55106           improveOsmEditor.error = function (val) {
55107             if (!arguments.length) return _qaItem;
55108             _qaItem = val;
55109             return improveOsmEditor;
55110           };
55111
55112           return utilRebind(improveOsmEditor, dispatch$1, 'on');
55113         }
55114
55115         function uiKeepRightDetails(context) {
55116           var _qaItem;
55117
55118           function issueDetail(d) {
55119             var itemType = d.itemType,
55120                 parentIssueType = d.parentIssueType;
55121             var unknown = _t.html('inspector.unknown');
55122             var replacements = d.replacements || {};
55123             replacements["default"] = unknown; // special key `default` works as a fallback string
55124
55125             var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
55126
55127             if (detail === unknown) {
55128               detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
55129             }
55130
55131             return detail;
55132           }
55133
55134           function keepRightDetails(selection) {
55135             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
55136               return "".concat(d.id, "-").concat(d.status || 0);
55137             });
55138             details.exit().remove();
55139             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
55140
55141             var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55142             descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
55143             descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
55144
55145             var relatedEntities = [];
55146             descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
55147               var link = select(this);
55148               var isObjectLink = link.classed('error_object_link');
55149               var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
55150               var entity = context.hasEntity(entityID);
55151               relatedEntities.push(entityID); // Add click handler
55152
55153               link.on('mouseenter', function () {
55154                 utilHighlightEntities([entityID], true, context);
55155               }).on('mouseleave', function () {
55156                 utilHighlightEntities([entityID], false, context);
55157               }).on('click', function (d3_event) {
55158                 d3_event.preventDefault();
55159                 utilHighlightEntities([entityID], false, context);
55160                 var osmlayer = context.layers().layer('osm');
55161
55162                 if (!osmlayer.enabled()) {
55163                   osmlayer.enabled(true);
55164                 }
55165
55166                 context.map().centerZoomEase(_qaItem.loc, 20);
55167
55168                 if (entity) {
55169                   context.enter(modeSelect(context, [entityID]));
55170                 } else {
55171                   context.loadEntity(entityID, function () {
55172                     context.enter(modeSelect(context, [entityID]));
55173                   });
55174                 }
55175               }); // Replace with friendly name if possible
55176               // (The entity may not yet be loaded into the graph)
55177
55178               if (entity) {
55179                 var name = utilDisplayName(entity); // try to use common name
55180
55181                 if (!name && !isObjectLink) {
55182                   var preset = _mainPresetIndex.match(entity, context.graph());
55183                   name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
55184                 }
55185
55186                 if (name) {
55187                   this.innerText = name;
55188                 }
55189               }
55190             }); // Don't hide entities related to this issue - #5880
55191
55192             context.features().forceVisible(relatedEntities);
55193             context.map().pan([0, 0]); // trigger a redraw
55194           }
55195
55196           keepRightDetails.issue = function (val) {
55197             if (!arguments.length) return _qaItem;
55198             _qaItem = val;
55199             return keepRightDetails;
55200           };
55201
55202           return keepRightDetails;
55203         }
55204
55205         function uiKeepRightHeader() {
55206           var _qaItem;
55207
55208           function issueTitle(d) {
55209             var itemType = d.itemType,
55210                 parentIssueType = d.parentIssueType;
55211             var unknown = _t.html('inspector.unknown');
55212             var replacements = d.replacements || {};
55213             replacements["default"] = unknown; // special key `default` works as a fallback string
55214
55215             var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
55216
55217             if (title === unknown) {
55218               title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
55219             }
55220
55221             return title;
55222           }
55223
55224           function keepRightHeader(selection) {
55225             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
55226               return "".concat(d.id, "-").concat(d.status || 0);
55227             });
55228             header.exit().remove();
55229             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
55230             var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
55231               return d.id < 0;
55232             });
55233             iconEnter.append('div').attr('class', function (d) {
55234               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
55235             }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
55236             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
55237           }
55238
55239           keepRightHeader.issue = function (val) {
55240             if (!arguments.length) return _qaItem;
55241             _qaItem = val;
55242             return keepRightHeader;
55243           };
55244
55245           return keepRightHeader;
55246         }
55247
55248         function uiViewOnKeepRight() {
55249           var _qaItem;
55250
55251           function viewOnKeepRight(selection) {
55252             var url;
55253
55254             if (services.keepRight && _qaItem instanceof QAItem) {
55255               url = services.keepRight.issueURL(_qaItem);
55256             }
55257
55258             var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
55259
55260             link.exit().remove(); // enter
55261
55262             var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
55263             .attr('href', function (d) {
55264               return d;
55265             }).call(svgIcon('#iD-icon-out-link', 'inline'));
55266             linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
55267           }
55268
55269           viewOnKeepRight.what = function (val) {
55270             if (!arguments.length) return _qaItem;
55271             _qaItem = val;
55272             return viewOnKeepRight;
55273           };
55274
55275           return viewOnKeepRight;
55276         }
55277
55278         function uiKeepRightEditor(context) {
55279           var dispatch$1 = dispatch('change');
55280           var qaDetails = uiKeepRightDetails(context);
55281           var qaHeader = uiKeepRightHeader();
55282
55283           var _qaItem;
55284
55285           function keepRightEditor(selection) {
55286             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
55287             headerEnter.append('button').attr('class', 'close').on('click', function () {
55288               return context.enter(modeBrowse(context));
55289             }).call(svgIcon('#iD-icon-close'));
55290             headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
55291             var body = selection.selectAll('.body').data([0]);
55292             body = body.enter().append('div').attr('class', 'body').merge(body);
55293             var editor = body.selectAll('.qa-editor').data([0]);
55294             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
55295             var footer = selection.selectAll('.footer').data([0]);
55296             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
55297           }
55298
55299           function keepRightSaveSection(selection) {
55300             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55301
55302             var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
55303             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55304               return "".concat(d.id, "-").concat(d.status || 0);
55305             }); // exit
55306
55307             saveSection.exit().remove(); // enter
55308
55309             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
55310             saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
55311             saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
55312               return d.newComment || d.comment;
55313             }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
55314
55315             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55316
55317             function changeInput() {
55318               var input = select(this);
55319               var val = input.property('value').trim();
55320
55321               if (val === _qaItem.comment) {
55322                 val = undefined;
55323               } // store the unsaved comment with the issue itself
55324
55325
55326               _qaItem = _qaItem.update({
55327                 newComment: val
55328               });
55329               var qaService = services.keepRight;
55330
55331               if (qaService) {
55332                 qaService.replaceItem(_qaItem); // update keepright cache
55333               }
55334
55335               saveSection.call(qaSaveButtons);
55336             }
55337           }
55338
55339           function qaSaveButtons(selection) {
55340             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55341
55342             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55343               return d.status + d.id;
55344             }); // exit
55345
55346             buttonSection.exit().remove(); // enter
55347
55348             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55349             buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
55350             buttonEnter.append('button').attr('class', 'button close-button action');
55351             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55352
55353             buttonSection = buttonSection.merge(buttonEnter);
55354             buttonSection.select('.comment-button') // select and propagate data
55355             .attr('disabled', function (d) {
55356               return d.newComment ? null : true;
55357             }).on('click.comment', function (d3_event, d) {
55358               this.blur(); // avoid keeping focus on the button - #4641
55359
55360               var qaService = services.keepRight;
55361
55362               if (qaService) {
55363                 qaService.postUpdate(d, function (err, item) {
55364                   return dispatch$1.call('change', item);
55365                 });
55366               }
55367             });
55368             buttonSection.select('.close-button') // select and propagate data
55369             .html(function (d) {
55370               var andComment = d.newComment ? '_comment' : '';
55371               return _t.html("QA.keepRight.close".concat(andComment));
55372             }).on('click.close', function (d3_event, d) {
55373               this.blur(); // avoid keeping focus on the button - #4641
55374
55375               var qaService = services.keepRight;
55376
55377               if (qaService) {
55378                 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
55379
55380                 qaService.postUpdate(d, function (err, item) {
55381                   return dispatch$1.call('change', item);
55382                 });
55383               }
55384             });
55385             buttonSection.select('.ignore-button') // select and propagate data
55386             .html(function (d) {
55387               var andComment = d.newComment ? '_comment' : '';
55388               return _t.html("QA.keepRight.ignore".concat(andComment));
55389             }).on('click.ignore', function (d3_event, d) {
55390               this.blur(); // avoid keeping focus on the button - #4641
55391
55392               var qaService = services.keepRight;
55393
55394               if (qaService) {
55395                 d.newStatus = 'ignore'; // ignore permanently (false positive)
55396
55397                 qaService.postUpdate(d, function (err, item) {
55398                   return dispatch$1.call('change', item);
55399                 });
55400               }
55401             });
55402           } // NOTE: Don't change method name until UI v3 is merged
55403
55404
55405           keepRightEditor.error = function (val) {
55406             if (!arguments.length) return _qaItem;
55407             _qaItem = val;
55408             return keepRightEditor;
55409           };
55410
55411           return utilRebind(keepRightEditor, dispatch$1, 'on');
55412         }
55413
55414         function uiOsmoseDetails(context) {
55415           var _qaItem;
55416
55417           function issueString(d, type) {
55418             if (!d) return ''; // Issue strings are cached from Osmose API
55419
55420             var s = services.osmose.getStrings(d.itemType);
55421             return type in s ? s[type] : '';
55422           }
55423
55424           function osmoseDetails(selection) {
55425             var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
55426               return "".concat(d.id, "-").concat(d.status || 0);
55427             });
55428             details.exit().remove();
55429             var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
55430
55431             if (issueString(_qaItem, 'detail')) {
55432               var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55433               div.append('h4').html(_t.html('QA.keepRight.detail_description'));
55434               div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
55435                 return issueString(d, 'detail');
55436               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55437             } // Elements (populated later as data is requested)
55438
55439
55440             var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55441             var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
55442
55443             if (issueString(_qaItem, 'fix')) {
55444               var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55445
55446               _div.append('h4').html(_t.html('QA.osmose.fix_title'));
55447
55448               _div.append('p').html(function (d) {
55449                 return issueString(d, 'fix');
55450               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55451             } // Common Pitfalls (mustn't exist for every issue type)
55452
55453
55454             if (issueString(_qaItem, 'trap')) {
55455               var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
55456
55457               _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
55458
55459               _div2.append('p').html(function (d) {
55460                 return issueString(d, 'trap');
55461               }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55462             } // Save current item to check if UI changed by time request resolves
55463
55464
55465             var thisItem = _qaItem;
55466             services.osmose.loadIssueDetail(_qaItem).then(function (d) {
55467               // No details to add if there are no associated issue elements
55468               if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
55469
55470               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
55471
55472               if (d.detail) {
55473                 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
55474                 detailsDiv.append('p').html(function (d) {
55475                   return d.detail;
55476                 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
55477               } // Create list of linked issue elements
55478
55479
55480               elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
55481               elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
55482                 return d;
55483               }).each(function () {
55484                 var link = select(this);
55485                 var entityID = this.textContent;
55486                 var entity = context.hasEntity(entityID); // Add click handler
55487
55488                 link.on('mouseenter', function () {
55489                   utilHighlightEntities([entityID], true, context);
55490                 }).on('mouseleave', function () {
55491                   utilHighlightEntities([entityID], false, context);
55492                 }).on('click', function (d3_event) {
55493                   d3_event.preventDefault();
55494                   utilHighlightEntities([entityID], false, context);
55495                   var osmlayer = context.layers().layer('osm');
55496
55497                   if (!osmlayer.enabled()) {
55498                     osmlayer.enabled(true);
55499                   }
55500
55501                   context.map().centerZoom(d.loc, 20);
55502
55503                   if (entity) {
55504                     context.enter(modeSelect(context, [entityID]));
55505                   } else {
55506                     context.loadEntity(entityID, function () {
55507                       context.enter(modeSelect(context, [entityID]));
55508                     });
55509                   }
55510                 }); // Replace with friendly name if possible
55511                 // (The entity may not yet be loaded into the graph)
55512
55513                 if (entity) {
55514                   var name = utilDisplayName(entity); // try to use common name
55515
55516                   if (!name) {
55517                     var preset = _mainPresetIndex.match(entity, context.graph());
55518                     name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
55519                   }
55520
55521                   if (name) {
55522                     this.innerText = name;
55523                   }
55524                 }
55525               }); // Don't hide entities related to this issue - #5880
55526
55527               context.features().forceVisible(d.elems);
55528               context.map().pan([0, 0]); // trigger a redraw
55529             })["catch"](function (err) {
55530               console.log(err); // eslint-disable-line no-console
55531             });
55532           }
55533
55534           osmoseDetails.issue = function (val) {
55535             if (!arguments.length) return _qaItem;
55536             _qaItem = val;
55537             return osmoseDetails;
55538           };
55539
55540           return osmoseDetails;
55541         }
55542
55543         function uiOsmoseHeader() {
55544           var _qaItem;
55545
55546           function issueTitle(d) {
55547             var unknown = _t('inspector.unknown');
55548             if (!d) return unknown; // Issue titles supplied by Osmose
55549
55550             var s = services.osmose.getStrings(d.itemType);
55551             return 'title' in s ? s.title : unknown;
55552           }
55553
55554           function osmoseHeader(selection) {
55555             var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
55556               return "".concat(d.id, "-").concat(d.status || 0);
55557             });
55558             header.exit().remove();
55559             var headerEnter = header.enter().append('div').attr('class', 'qa-header');
55560             var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
55561               return d.id < 0;
55562             }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
55563               return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
55564             });
55565             svgEnter.append('polygon').attr('fill', function (d) {
55566               return services.osmose.getColor(d.item);
55567             }).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');
55568             svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
55569               var picon = d.icon;
55570
55571               if (!picon) {
55572                 return '';
55573               } else {
55574                 var isMaki = /^maki-/.test(picon);
55575                 return "#".concat(picon).concat(isMaki ? '-11' : '');
55576               }
55577             });
55578             headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
55579           }
55580
55581           osmoseHeader.issue = function (val) {
55582             if (!arguments.length) return _qaItem;
55583             _qaItem = val;
55584             return osmoseHeader;
55585           };
55586
55587           return osmoseHeader;
55588         }
55589
55590         function uiViewOnOsmose() {
55591           var _qaItem;
55592
55593           function viewOnOsmose(selection) {
55594             var url;
55595
55596             if (services.osmose && _qaItem instanceof QAItem) {
55597               url = services.osmose.itemURL(_qaItem);
55598             }
55599
55600             var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
55601
55602             link.exit().remove(); // enter
55603
55604             var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
55605             .attr('href', function (d) {
55606               return d;
55607             }).call(svgIcon('#iD-icon-out-link', 'inline'));
55608             linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
55609           }
55610
55611           viewOnOsmose.what = function (val) {
55612             if (!arguments.length) return _qaItem;
55613             _qaItem = val;
55614             return viewOnOsmose;
55615           };
55616
55617           return viewOnOsmose;
55618         }
55619
55620         function uiOsmoseEditor(context) {
55621           var dispatch$1 = dispatch('change');
55622           var qaDetails = uiOsmoseDetails(context);
55623           var qaHeader = uiOsmoseHeader();
55624
55625           var _qaItem;
55626
55627           function osmoseEditor(selection) {
55628             var header = selection.selectAll('.header').data([0]);
55629             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
55630             headerEnter.append('button').attr('class', 'close').on('click', function () {
55631               return context.enter(modeBrowse(context));
55632             }).call(svgIcon('#iD-icon-close'));
55633             headerEnter.append('h3').html(_t.html('QA.osmose.title'));
55634             var body = selection.selectAll('.body').data([0]);
55635             body = body.enter().append('div').attr('class', 'body').merge(body);
55636             var editor = body.selectAll('.qa-editor').data([0]);
55637             editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
55638             var footer = selection.selectAll('.footer').data([0]);
55639             footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
55640           }
55641
55642           function osmoseSaveSection(selection) {
55643             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55644
55645             var isShown = _qaItem && isSelected;
55646             var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
55647               return "".concat(d.id, "-").concat(d.status || 0);
55648             }); // exit
55649
55650             saveSection.exit().remove(); // enter
55651
55652             var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
55653
55654             saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
55655           }
55656
55657           function qaSaveButtons(selection) {
55658             var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
55659
55660             var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
55661               return d.status + d.id;
55662             }); // exit
55663
55664             buttonSection.exit().remove(); // enter
55665
55666             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
55667             buttonEnter.append('button').attr('class', 'button close-button action');
55668             buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
55669
55670             buttonSection = buttonSection.merge(buttonEnter);
55671             buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
55672               this.blur(); // avoid keeping focus on the button - #4641
55673
55674               var qaService = services.osmose;
55675
55676               if (qaService) {
55677                 d.newStatus = 'done';
55678                 qaService.postUpdate(d, function (err, item) {
55679                   return dispatch$1.call('change', item);
55680                 });
55681               }
55682             });
55683             buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
55684               this.blur(); // avoid keeping focus on the button - #4641
55685
55686               var qaService = services.osmose;
55687
55688               if (qaService) {
55689                 d.newStatus = 'false';
55690                 qaService.postUpdate(d, function (err, item) {
55691                   return dispatch$1.call('change', item);
55692                 });
55693               }
55694             });
55695           } // NOTE: Don't change method name until UI v3 is merged
55696
55697
55698           osmoseEditor.error = function (val) {
55699             if (!arguments.length) return _qaItem;
55700             _qaItem = val;
55701             return osmoseEditor;
55702           };
55703
55704           return utilRebind(osmoseEditor, dispatch$1, 'on');
55705         }
55706
55707         function modeSelectError(context, selectedErrorID, selectedErrorService) {
55708           var mode = {
55709             id: 'select-error',
55710             button: 'browse'
55711           };
55712           var keybinding = utilKeybinding('select-error');
55713           var errorService = services[selectedErrorService];
55714           var errorEditor;
55715
55716           switch (selectedErrorService) {
55717             case 'improveOSM':
55718               errorEditor = uiImproveOsmEditor(context).on('change', function () {
55719                 context.map().pan([0, 0]); // trigger a redraw
55720
55721                 var error = checkSelectedID();
55722                 if (!error) return;
55723                 context.ui().sidebar.show(errorEditor.error(error));
55724               });
55725               break;
55726
55727             case 'keepRight':
55728               errorEditor = uiKeepRightEditor(context).on('change', function () {
55729                 context.map().pan([0, 0]); // trigger a redraw
55730
55731                 var error = checkSelectedID();
55732                 if (!error) return;
55733                 context.ui().sidebar.show(errorEditor.error(error));
55734               });
55735               break;
55736
55737             case 'osmose':
55738               errorEditor = uiOsmoseEditor(context).on('change', function () {
55739                 context.map().pan([0, 0]); // trigger a redraw
55740
55741                 var error = checkSelectedID();
55742                 if (!error) return;
55743                 context.ui().sidebar.show(errorEditor.error(error));
55744               });
55745               break;
55746           }
55747
55748           var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
55749
55750           function checkSelectedID() {
55751             if (!errorService) return;
55752             var error = errorService.getError(selectedErrorID);
55753
55754             if (!error) {
55755               context.enter(modeBrowse(context));
55756             }
55757
55758             return error;
55759           }
55760
55761           mode.zoomToSelected = function () {
55762             if (!errorService) return;
55763             var error = errorService.getError(selectedErrorID);
55764
55765             if (error) {
55766               context.map().centerZoomEase(error.loc, 20);
55767             }
55768           };
55769
55770           mode.enter = function () {
55771             var error = checkSelectedID();
55772             if (!error) return;
55773             behaviors.forEach(context.install);
55774             keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
55775             select(document).call(keybinding);
55776             selectError();
55777             var sidebar = context.ui().sidebar;
55778             sidebar.show(errorEditor.error(error));
55779             context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
55780
55781             function selectError(d3_event, drawn) {
55782               if (!checkSelectedID()) return;
55783               var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
55784
55785               if (selection.empty()) {
55786                 // Return to browse mode if selected DOM elements have
55787                 // disappeared because the user moved them out of view..
55788                 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
55789
55790                 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
55791                   context.enter(modeBrowse(context));
55792                 }
55793               } else {
55794                 selection.classed('selected', true);
55795                 context.selectedErrorID(selectedErrorID);
55796               }
55797             }
55798
55799             function esc() {
55800               if (context.container().select('.combobox').size()) return;
55801               context.enter(modeBrowse(context));
55802             }
55803           };
55804
55805           mode.exit = function () {
55806             behaviors.forEach(context.uninstall);
55807             select(document).call(keybinding.unbind);
55808             context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
55809             context.map().on('drawn.select-error', null);
55810             context.ui().sidebar.hide();
55811             context.selectedErrorID(null);
55812             context.features().forceVisible([]);
55813           };
55814
55815           return mode;
55816         }
55817
55818         function behaviorSelect(context) {
55819           var _tolerancePx = 4; // see also behaviorDrag
55820
55821           var _lastMouseEvent = null;
55822           var _showMenu = false;
55823           var _downPointers = {};
55824           var _longPressTimeout = null;
55825           var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
55826
55827           var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
55828
55829           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
55830
55831           function keydown(d3_event) {
55832             if (d3_event.keyCode === 32) {
55833               // don't react to spacebar events during text input
55834               var activeNode = document.activeElement;
55835               if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
55836             }
55837
55838             if (d3_event.keyCode === 93 || // context menu key
55839             d3_event.keyCode === 32) {
55840               // spacebar
55841               d3_event.preventDefault();
55842             }
55843
55844             if (d3_event.repeat) return; // ignore repeated events for held keys
55845             // if any key is pressed the user is probably doing something other than long-pressing
55846
55847             cancelLongPress();
55848
55849             if (d3_event.shiftKey) {
55850               context.surface().classed('behavior-multiselect', true);
55851             }
55852
55853             if (d3_event.keyCode === 32) {
55854               // spacebar
55855               if (!_downPointers.spacebar && _lastMouseEvent) {
55856                 cancelLongPress();
55857                 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
55858                 _downPointers.spacebar = {
55859                   firstEvent: _lastMouseEvent,
55860                   lastEvent: _lastMouseEvent
55861                 };
55862               }
55863             }
55864           }
55865
55866           function keyup(d3_event) {
55867             cancelLongPress();
55868
55869             if (!d3_event.shiftKey) {
55870               context.surface().classed('behavior-multiselect', false);
55871             }
55872
55873             if (d3_event.keyCode === 93) {
55874               // context menu key
55875               d3_event.preventDefault();
55876               _lastInteractionType = 'menukey';
55877               contextmenu(d3_event);
55878             } else if (d3_event.keyCode === 32) {
55879               // spacebar
55880               var pointer = _downPointers.spacebar;
55881
55882               if (pointer) {
55883                 delete _downPointers.spacebar;
55884                 if (pointer.done) return;
55885                 d3_event.preventDefault();
55886                 _lastInteractionType = 'spacebar';
55887                 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
55888               }
55889             }
55890           }
55891
55892           function pointerdown(d3_event) {
55893             var id = (d3_event.pointerId || 'mouse').toString();
55894             cancelLongPress();
55895             if (d3_event.buttons && d3_event.buttons !== 1) return;
55896             context.ui().closeEditMenu();
55897             _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
55898             _downPointers[id] = {
55899               firstEvent: d3_event,
55900               lastEvent: d3_event
55901             };
55902           }
55903
55904           function didLongPress(id, interactionType) {
55905             var pointer = _downPointers[id];
55906             if (!pointer) return;
55907
55908             for (var i in _downPointers) {
55909               // don't allow this or any currently down pointer to trigger another click
55910               _downPointers[i].done = true;
55911             } // treat long presses like right-clicks
55912
55913
55914             _longPressTimeout = null;
55915             _lastInteractionType = interactionType;
55916             _showMenu = true;
55917             click(pointer.firstEvent, pointer.lastEvent, id);
55918           }
55919
55920           function pointermove(d3_event) {
55921             var id = (d3_event.pointerId || 'mouse').toString();
55922
55923             if (_downPointers[id]) {
55924               _downPointers[id].lastEvent = d3_event;
55925             }
55926
55927             if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
55928               _lastMouseEvent = d3_event;
55929
55930               if (_downPointers.spacebar) {
55931                 _downPointers.spacebar.lastEvent = d3_event;
55932               }
55933             }
55934           }
55935
55936           function pointerup(d3_event) {
55937             var id = (d3_event.pointerId || 'mouse').toString();
55938             var pointer = _downPointers[id];
55939             if (!pointer) return;
55940             delete _downPointers[id];
55941
55942             if (_multiselectionPointerId === id) {
55943               _multiselectionPointerId = null;
55944             }
55945
55946             if (pointer.done) return;
55947             click(pointer.firstEvent, d3_event, id);
55948           }
55949
55950           function pointercancel(d3_event) {
55951             var id = (d3_event.pointerId || 'mouse').toString();
55952             if (!_downPointers[id]) return;
55953             delete _downPointers[id];
55954
55955             if (_multiselectionPointerId === id) {
55956               _multiselectionPointerId = null;
55957             }
55958           }
55959
55960           function contextmenu(d3_event) {
55961             d3_event.preventDefault();
55962
55963             if (!+d3_event.clientX && !+d3_event.clientY) {
55964               if (_lastMouseEvent) {
55965                 d3_event.sourceEvent = _lastMouseEvent;
55966               } else {
55967                 return;
55968               }
55969             } else {
55970               _lastMouseEvent = d3_event;
55971               _lastInteractionType = 'rightclick';
55972             }
55973
55974             _showMenu = true;
55975             click(d3_event, d3_event);
55976           }
55977
55978           function click(firstEvent, lastEvent, pointerId) {
55979             cancelLongPress();
55980             var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
55981             // are transformed when drag-panning.
55982
55983             var pointGetter = utilFastMouse(mapNode);
55984             var p1 = pointGetter(firstEvent);
55985             var p2 = pointGetter(lastEvent);
55986             var dist = geoVecLength(p1, p2);
55987
55988             if (dist > _tolerancePx || !mapContains(lastEvent)) {
55989               resetProperties();
55990               return;
55991             }
55992
55993             var targetDatum = lastEvent.target.__data__;
55994             var multiselectEntityId;
55995
55996             if (!_multiselectionPointerId) {
55997               // If a different pointer than the one triggering this click is down on a
55998               // feature, treat this and all future clicks as multiselection until that
55999               // pointer is raised.
56000               var selectPointerInfo = pointerDownOnSelection(pointerId);
56001
56002               if (selectPointerInfo) {
56003                 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
56004
56005                 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
56006                 _downPointers[selectPointerInfo.pointerId].done = true;
56007               }
56008             } // support multiselect if data is already selected
56009
56010
56011             var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
56012             lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
56013             context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
56014             _multiselectionPointerId && !multiselectEntityId);
56015
56016             processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
56017
56018             function mapContains(event) {
56019               var rect = mapNode.getBoundingClientRect();
56020               return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
56021             }
56022
56023             function pointerDownOnSelection(skipPointerId) {
56024               var mode = context.mode();
56025               var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
56026
56027               for (var pointerId in _downPointers) {
56028                 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
56029                 var pointerInfo = _downPointers[pointerId];
56030                 var p1 = pointGetter(pointerInfo.firstEvent);
56031                 var p2 = pointGetter(pointerInfo.lastEvent);
56032                 if (geoVecLength(p1, p2) > _tolerancePx) continue;
56033                 var datum = pointerInfo.firstEvent.target.__data__;
56034                 var entity = datum && datum.properties && datum.properties.entity || datum;
56035                 if (context.graph().hasEntity(entity.id)) return {
56036                   pointerId: pointerId,
56037                   entityId: entity.id,
56038                   selected: selectedIDs.indexOf(entity.id) !== -1
56039                 };
56040               }
56041
56042               return null;
56043             }
56044           }
56045
56046           function processClick(datum, isMultiselect, point, alsoSelectId) {
56047             var mode = context.mode();
56048             var showMenu = _showMenu;
56049             var interactionType = _lastInteractionType;
56050             var entity = datum && datum.properties && datum.properties.entity;
56051             if (entity) datum = entity;
56052
56053             if (datum && datum.type === 'midpoint') {
56054               // treat targeting midpoints as if targeting the parent way
56055               datum = datum.parents[0];
56056             }
56057
56058             var newMode;
56059
56060             if (datum instanceof osmEntity) {
56061               // targeting an entity
56062               var selectedIDs = context.selectedIDs();
56063               context.selectedNoteID(null);
56064               context.selectedErrorID(null);
56065
56066               if (!isMultiselect) {
56067                 // don't change the selection if we're toggling the menu atop a multiselection
56068                 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
56069                   if (alsoSelectId === datum.id) alsoSelectId = null;
56070                   selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
56071                   // selected since listeners may expect `context.enter` events,
56072                   // e.g. in the walkthrough
56073
56074                   newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
56075                   context.enter(newMode);
56076                 }
56077               } else {
56078                 if (selectedIDs.indexOf(datum.id) !== -1) {
56079                   // clicked entity is already in the selectedIDs list..
56080                   if (!showMenu) {
56081                     // deselect clicked entity, then reenter select mode or return to browse mode..
56082                     selectedIDs = selectedIDs.filter(function (id) {
56083                       return id !== datum.id;
56084                     });
56085                     newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
56086                     context.enter(newMode);
56087                   }
56088                 } else {
56089                   // clicked entity is not in the selected list, add it..
56090                   selectedIDs = selectedIDs.concat([datum.id]);
56091                   newMode = mode.selectedIDs(selectedIDs);
56092                   context.enter(newMode);
56093                 }
56094               }
56095             } else if (datum && datum.__featurehash__ && !isMultiselect) {
56096               // targeting custom data
56097               context.selectedNoteID(null).enter(modeSelectData(context, datum));
56098             } else if (datum instanceof osmNote && !isMultiselect) {
56099               // targeting a note
56100               context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
56101             } else if (datum instanceof QAItem & !isMultiselect) {
56102               // targeting an external QA issue
56103               context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
56104             } else {
56105               // targeting nothing
56106               context.selectedNoteID(null);
56107               context.selectedErrorID(null);
56108
56109               if (!isMultiselect && mode.id !== 'browse') {
56110                 context.enter(modeBrowse(context));
56111               }
56112             }
56113
56114             context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
56115
56116             if (showMenu) context.ui().showEditMenu(point, interactionType);
56117             resetProperties();
56118           }
56119
56120           function cancelLongPress() {
56121             if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
56122             _longPressTimeout = null;
56123           }
56124
56125           function resetProperties() {
56126             cancelLongPress();
56127             _showMenu = false;
56128             _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
56129           }
56130
56131           function behavior(selection) {
56132             resetProperties();
56133             _lastMouseEvent = context.map().lastPointerEvent();
56134             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) {
56135               // Edge and IE really like to show the contextmenu on the
56136               // menubar when user presses a keyboard menu button
56137               // even after we've already preventdefaulted the key event.
56138               var e = d3_event;
56139
56140               if (+e.clientX === 0 && +e.clientY === 0) {
56141                 d3_event.preventDefault();
56142               }
56143             });
56144             selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
56145             /*if (d3_event && d3_event.shiftKey) {
56146                 context.surface()
56147                     .classed('behavior-multiselect', true);
56148             }*/
56149           }
56150
56151           behavior.off = function (selection) {
56152             cancelLongPress();
56153             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);
56154             selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
56155             context.surface().classed('behavior-multiselect', false);
56156           };
56157
56158           return behavior;
56159         }
56160
56161         function behaviorDrawWay(context, wayID, mode, startGraph) {
56162           var dispatch$1 = dispatch('rejectedSelfIntersection');
56163           var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
56164
56165           var _nodeIndex;
56166
56167           var _origWay;
56168
56169           var _wayGeometry;
56170
56171           var _headNodeID;
56172
56173           var _annotation;
56174
56175           var _pointerHasMoved = false; // The osmNode to be placed.
56176           // This is temporary and just follows the mouse cursor until an "add" event occurs.
56177
56178           var _drawNode;
56179
56180           var _didResolveTempEdit = false;
56181
56182           function createDrawNode(loc) {
56183             // don't make the draw node until we actually need it
56184             _drawNode = osmNode({
56185               loc: loc
56186             });
56187             context.pauseChangeDispatch();
56188             context.replace(function actionAddDrawNode(graph) {
56189               // add the draw node to the graph and insert it into the way
56190               var way = graph.entity(wayID);
56191               return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
56192             }, _annotation);
56193             context.resumeChangeDispatch();
56194             setActiveElements();
56195           }
56196
56197           function removeDrawNode() {
56198             context.pauseChangeDispatch();
56199             context.replace(function actionDeleteDrawNode(graph) {
56200               var way = graph.entity(wayID);
56201               return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
56202             }, _annotation);
56203             _drawNode = undefined;
56204             context.resumeChangeDispatch();
56205           }
56206
56207           function keydown(d3_event) {
56208             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56209               if (context.surface().classed('nope')) {
56210                 context.surface().classed('nope-suppressed', true);
56211               }
56212
56213               context.surface().classed('nope', false).classed('nope-disabled', true);
56214             }
56215           }
56216
56217           function keyup(d3_event) {
56218             if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56219               if (context.surface().classed('nope-suppressed')) {
56220                 context.surface().classed('nope', true);
56221               }
56222
56223               context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
56224             }
56225           }
56226
56227           function allowsVertex(d) {
56228             return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
56229           } // related code
56230           // - `mode/drag_node.js`     `doMove()`
56231           // - `behavior/draw.js`      `click()`
56232           // - `behavior/draw_way.js`  `move()`
56233
56234
56235           function move(d3_event, datum) {
56236             var loc = context.map().mouseCoordinates();
56237             if (!_drawNode) createDrawNode(loc);
56238             context.surface().classed('nope-disabled', d3_event.altKey);
56239             var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
56240             var targetNodes = datum && datum.properties && datum.properties.nodes;
56241
56242             if (targetLoc) {
56243               // snap to node/vertex - a point target with `.loc`
56244               loc = targetLoc;
56245             } else if (targetNodes) {
56246               // snap to way - a line target with `.nodes`
56247               var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
56248
56249               if (choice) {
56250                 loc = choice.loc;
56251               }
56252             }
56253
56254             context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56255             _drawNode = context.entity(_drawNode.id);
56256             checkGeometry(true
56257             /* includeDrawNode */
56258             );
56259           } // Check whether this edit causes the geometry to break.
56260           // If so, class the surface with a nope cursor.
56261           // `includeDrawNode` - Only check the relevant line segments if finishing drawing
56262
56263
56264           function checkGeometry(includeDrawNode) {
56265             var nopeDisabled = context.surface().classed('nope-disabled');
56266             var isInvalid = isInvalidGeometry(includeDrawNode);
56267
56268             if (nopeDisabled) {
56269               context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
56270             } else {
56271               context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
56272             }
56273           }
56274
56275           function isInvalidGeometry(includeDrawNode) {
56276             var testNode = _drawNode; // we only need to test the single way we're drawing
56277
56278             var parentWay = context.graph().entity(wayID);
56279             var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
56280
56281             if (includeDrawNode) {
56282               if (parentWay.isClosed()) {
56283                 // don't test the last segment for closed ways - #4655
56284                 // (still test the first segment)
56285                 nodes.pop();
56286               }
56287             } else {
56288               // discount the draw node
56289               if (parentWay.isClosed()) {
56290                 if (nodes.length < 3) return false;
56291                 if (_drawNode) nodes.splice(-2, 1);
56292                 testNode = nodes[nodes.length - 2];
56293               } else {
56294                 // there's nothing we need to test if we ignore the draw node on open ways
56295                 return false;
56296               }
56297             }
56298
56299             return testNode && geoHasSelfIntersections(nodes, testNode.id);
56300           }
56301
56302           function undone() {
56303             // undoing removed the temp edit
56304             _didResolveTempEdit = true;
56305             context.pauseChangeDispatch();
56306             var nextMode;
56307
56308             if (context.graph() === startGraph) {
56309               // We've undone back to the initial state before we started drawing.
56310               // Just exit the draw mode without undoing whatever we did before
56311               // we entered the draw mode.
56312               nextMode = modeSelect(context, [wayID]);
56313             } else {
56314               // The `undo` only removed the temporary edit, so here we have to
56315               // manually undo to actually remove the last node we added. We can't
56316               // use the `undo` function since the initial "add" graph doesn't have
56317               // an annotation and so cannot be undone to.
56318               context.pop(1); // continue drawing
56319
56320               nextMode = mode;
56321             } // clear the redo stack by adding and removing a blank edit
56322
56323
56324             context.perform(actionNoop());
56325             context.pop(1);
56326             context.resumeChangeDispatch();
56327             context.enter(nextMode);
56328           }
56329
56330           function setActiveElements() {
56331             if (!_drawNode) return;
56332             context.surface().selectAll('.' + _drawNode.id).classed('active', true);
56333           }
56334
56335           function resetToStartGraph() {
56336             while (context.graph() !== startGraph) {
56337               context.pop();
56338             }
56339           }
56340
56341           var drawWay = function drawWay(surface) {
56342             _drawNode = undefined;
56343             _didResolveTempEdit = false;
56344             _origWay = context.entity(wayID);
56345             _headNodeID = typeof _nodeIndex === 'number' ? _origWay.nodes[_nodeIndex] : _origWay.isClosed() ? _origWay.nodes[_origWay.nodes.length - 2] : _origWay.nodes[_origWay.nodes.length - 1];
56346             _wayGeometry = _origWay.geometry(context.graph());
56347             _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
56348             _pointerHasMoved = false; // Push an annotated state for undo to return back to.
56349             // We must make sure to replace or remove it later.
56350
56351             context.pauseChangeDispatch();
56352             context.perform(actionNoop(), _annotation);
56353             context.resumeChangeDispatch();
56354             behavior.hover().initialNodeID(_headNodeID);
56355             behavior.on('move', function () {
56356               _pointerHasMoved = true;
56357               move.apply(this, arguments);
56358             }).on('down', function () {
56359               move.apply(this, arguments);
56360             }).on('downcancel', function () {
56361               if (_drawNode) removeDrawNode();
56362             }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
56363             select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
56364             context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
56365             setActiveElements();
56366             surface.call(behavior);
56367             context.history().on('undone.draw', undone);
56368           };
56369
56370           drawWay.off = function (surface) {
56371             if (!_didResolveTempEdit) {
56372               // Drawing was interrupted unexpectedly.
56373               // This can happen if the user changes modes,
56374               // clicks geolocate button, a hashchange event occurs, etc.
56375               context.pauseChangeDispatch();
56376               resetToStartGraph();
56377               context.resumeChangeDispatch();
56378             }
56379
56380             _drawNode = undefined;
56381             _nodeIndex = undefined;
56382             context.map().on('drawn.draw', null);
56383             surface.call(behavior.off).selectAll('.active').classed('active', false);
56384             surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
56385             select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
56386             context.history().on('undone.draw', null);
56387           };
56388
56389           function attemptAdd(d, loc, doAdd) {
56390             if (_drawNode) {
56391               // move the node to the final loc in case move wasn't called
56392               // consistently (e.g. on touch devices)
56393               context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
56394               _drawNode = context.entity(_drawNode.id);
56395             } else {
56396               createDrawNode(loc);
56397             }
56398
56399             checkGeometry(true
56400             /* includeDrawNode */
56401             );
56402
56403             if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
56404               if (!_pointerHasMoved) {
56405                 // prevent the temporary draw node from appearing on touch devices
56406                 removeDrawNode();
56407               }
56408
56409               dispatch$1.call('rejectedSelfIntersection', this);
56410               return; // can't click here
56411             }
56412
56413             context.pauseChangeDispatch();
56414             doAdd(); // we just replaced the temporary edit with the real one
56415
56416             _didResolveTempEdit = true;
56417             context.resumeChangeDispatch();
56418             context.enter(mode);
56419           } // Accept the current position of the drawing node
56420
56421
56422           drawWay.add = function (loc, d) {
56423             attemptAdd(d, loc, function () {// don't need to do anything extra
56424             });
56425           }; // Connect the way to an existing way
56426
56427
56428           drawWay.addWay = function (loc, edge, d) {
56429             attemptAdd(d, loc, function () {
56430               context.replace(actionAddMidpoint({
56431                 loc: loc,
56432                 edge: edge
56433               }, _drawNode), _annotation);
56434             });
56435           }; // Connect the way to an existing node
56436
56437
56438           drawWay.addNode = function (node, d) {
56439             // finish drawing if the mapper targets the prior node
56440             if (node.id === _headNodeID || // or the first node when drawing an area
56441             _origWay.isClosed() && node.id === _origWay.first()) {
56442               drawWay.finish();
56443               return;
56444             }
56445
56446             attemptAdd(d, node.loc, function () {
56447               context.replace(function actionReplaceDrawNode(graph) {
56448                 // remove the temporary draw node and insert the existing node
56449                 // at the same index
56450                 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
56451                 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
56452               }, _annotation);
56453             });
56454           }; // Finish the draw operation, removing the temporary edit.
56455           // If the way has enough nodes to be valid, it's selected.
56456           // Otherwise, delete everything and return to browse mode.
56457
56458
56459           drawWay.finish = function () {
56460             checkGeometry(false
56461             /* includeDrawNode */
56462             );
56463
56464             if (context.surface().classed('nope')) {
56465               dispatch$1.call('rejectedSelfIntersection', this);
56466               return; // can't click here
56467             }
56468
56469             context.pauseChangeDispatch(); // remove the temporary edit
56470
56471             context.pop(1);
56472             _didResolveTempEdit = true;
56473             context.resumeChangeDispatch();
56474             var way = context.hasEntity(wayID);
56475
56476             if (!way || way.isDegenerate()) {
56477               drawWay.cancel();
56478               return;
56479             }
56480
56481             window.setTimeout(function () {
56482               context.map().dblclickZoomEnable(true);
56483             }, 1000);
56484             var isNewFeature = !mode.isContinuing;
56485             context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
56486           }; // Cancel the draw operation, delete everything, and return to browse mode.
56487
56488
56489           drawWay.cancel = function () {
56490             context.pauseChangeDispatch();
56491             resetToStartGraph();
56492             context.resumeChangeDispatch();
56493             window.setTimeout(function () {
56494               context.map().dblclickZoomEnable(true);
56495             }, 1000);
56496             context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
56497             context.enter(modeBrowse(context));
56498           };
56499
56500           drawWay.nodeIndex = function (val) {
56501             if (!arguments.length) return _nodeIndex;
56502             _nodeIndex = val;
56503             return drawWay;
56504           };
56505
56506           drawWay.activeID = function () {
56507             if (!arguments.length) return _drawNode && _drawNode.id; // no assign
56508
56509             return drawWay;
56510           };
56511
56512           return utilRebind(drawWay, dispatch$1, 'on');
56513         }
56514
56515         function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
56516           var mode = {
56517             button: button,
56518             id: 'draw-line'
56519           };
56520           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
56521             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
56522           });
56523           mode.wayID = wayID;
56524           mode.isContinuing = continuing;
56525
56526           mode.enter = function () {
56527             behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
56528             context.install(behavior);
56529           };
56530
56531           mode.exit = function () {
56532             context.uninstall(behavior);
56533           };
56534
56535           mode.selectedIDs = function () {
56536             return [wayID];
56537           };
56538
56539           mode.activeID = function () {
56540             return behavior && behavior.activeID() || [];
56541           };
56542
56543           return mode;
56544         }
56545
56546         function operationContinue(context, selectedIDs) {
56547           var _entities = selectedIDs.map(function (id) {
56548             return context.graph().entity(id);
56549           });
56550
56551           var _geometries = Object.assign({
56552             line: [],
56553             vertex: []
56554           }, utilArrayGroupBy(_entities, function (entity) {
56555             return entity.geometry(context.graph());
56556           }));
56557
56558           var _vertex = _geometries.vertex.length && _geometries.vertex[0];
56559
56560           function candidateWays() {
56561             return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
56562               return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
56563             }) : [];
56564           }
56565
56566           var _candidates = candidateWays();
56567
56568           var operation = function operation() {
56569             var candidate = _candidates[0];
56570             context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
56571           };
56572
56573           operation.relatedEntityIds = function () {
56574             return _candidates.length ? [_candidates[0].id] : [];
56575           };
56576
56577           operation.available = function () {
56578             return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
56579           };
56580
56581           operation.disabled = function () {
56582             if (_candidates.length === 0) {
56583               return 'not_eligible';
56584             } else if (_candidates.length > 1) {
56585               return 'multiple';
56586             }
56587
56588             return false;
56589           };
56590
56591           operation.tooltip = function () {
56592             var disable = operation.disabled();
56593             return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
56594           };
56595
56596           operation.annotation = function () {
56597             return _t('operations.continue.annotation.line');
56598           };
56599
56600           operation.id = 'continue';
56601           operation.keys = [_t('operations.continue.key')];
56602           operation.title = _t('operations.continue.title');
56603           operation.behavior = behaviorOperation(context).which(operation);
56604           return operation;
56605         }
56606
56607         function operationCopy(context, selectedIDs) {
56608           function getFilteredIdsToCopy() {
56609             return selectedIDs.filter(function (selectedID) {
56610               var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
56611
56612               return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
56613             });
56614           }
56615
56616           var operation = function operation() {
56617             var graph = context.graph();
56618             var selected = groupEntities(getFilteredIdsToCopy(), graph);
56619             var canCopy = [];
56620             var skip = {};
56621             var entity;
56622             var i;
56623
56624             for (i = 0; i < selected.relation.length; i++) {
56625               entity = selected.relation[i];
56626
56627               if (!skip[entity.id] && entity.isComplete(graph)) {
56628                 canCopy.push(entity.id);
56629                 skip = getDescendants(entity.id, graph, skip);
56630               }
56631             }
56632
56633             for (i = 0; i < selected.way.length; i++) {
56634               entity = selected.way[i];
56635
56636               if (!skip[entity.id]) {
56637                 canCopy.push(entity.id);
56638                 skip = getDescendants(entity.id, graph, skip);
56639               }
56640             }
56641
56642             for (i = 0; i < selected.node.length; i++) {
56643               entity = selected.node[i];
56644
56645               if (!skip[entity.id]) {
56646                 canCopy.push(entity.id);
56647               }
56648             }
56649
56650             context.copyIDs(canCopy);
56651
56652             if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
56653               // store the anchor coordinates if copying more than a single node
56654               context.copyLonLat(context.projection.invert(_point));
56655             } else {
56656               context.copyLonLat(null);
56657             }
56658           };
56659
56660           function groupEntities(ids, graph) {
56661             var entities = ids.map(function (id) {
56662               return graph.entity(id);
56663             });
56664             return Object.assign({
56665               relation: [],
56666               way: [],
56667               node: []
56668             }, utilArrayGroupBy(entities, 'type'));
56669           }
56670
56671           function getDescendants(id, graph, descendants) {
56672             var entity = graph.entity(id);
56673             var children;
56674             descendants = descendants || {};
56675
56676             if (entity.type === 'relation') {
56677               children = entity.members.map(function (m) {
56678                 return m.id;
56679               });
56680             } else if (entity.type === 'way') {
56681               children = entity.nodes;
56682             } else {
56683               children = [];
56684             }
56685
56686             for (var i = 0; i < children.length; i++) {
56687               if (!descendants[children[i]]) {
56688                 descendants[children[i]] = true;
56689                 descendants = getDescendants(children[i], graph, descendants);
56690               }
56691             }
56692
56693             return descendants;
56694           }
56695
56696           operation.available = function () {
56697             return getFilteredIdsToCopy().length > 0;
56698           };
56699
56700           operation.disabled = function () {
56701             var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
56702
56703             if (extent.percentContainedIn(context.map().extent()) < 0.8) {
56704               return 'too_large';
56705             }
56706
56707             return false;
56708           };
56709
56710           operation.availableForKeypress = function () {
56711             var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
56712
56713             return !selection || !selection.toString();
56714           };
56715
56716           operation.tooltip = function () {
56717             var disable = operation.disabled();
56718             return disable ? _t('operations.copy.' + disable, {
56719               n: selectedIDs.length
56720             }) : _t('operations.copy.description', {
56721               n: selectedIDs.length
56722             });
56723           };
56724
56725           operation.annotation = function () {
56726             return _t('operations.copy.annotation', {
56727               n: selectedIDs.length
56728             });
56729           };
56730
56731           var _point;
56732
56733           operation.point = function (val) {
56734             _point = val;
56735             return operation;
56736           };
56737
56738           operation.id = 'copy';
56739           operation.keys = [uiCmd('⌘C')];
56740           operation.title = _t('operations.copy.title');
56741           operation.behavior = behaviorOperation(context).which(operation);
56742           return operation;
56743         }
56744
56745         function operationDisconnect(context, selectedIDs) {
56746           var _vertexIDs = [];
56747           var _wayIDs = [];
56748           var _otherIDs = [];
56749           var _actions = [];
56750           selectedIDs.forEach(function (id) {
56751             var entity = context.entity(id);
56752
56753             if (entity.type === 'way') {
56754               _wayIDs.push(id);
56755             } else if (entity.geometry(context.graph()) === 'vertex') {
56756               _vertexIDs.push(id);
56757             } else {
56758               _otherIDs.push(id);
56759             }
56760           });
56761
56762           var _coords,
56763               _descriptionID = '',
56764               _annotationID = 'features';
56765
56766           var _disconnectingVertexIds = [];
56767           var _disconnectingWayIds = [];
56768
56769           if (_vertexIDs.length > 0) {
56770             // At the selected vertices, disconnect the selected ways, if any, else
56771             // disconnect all connected ways
56772             _disconnectingVertexIds = _vertexIDs;
56773
56774             _vertexIDs.forEach(function (vertexID) {
56775               var action = actionDisconnect(vertexID);
56776
56777               if (_wayIDs.length > 0) {
56778                 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
56779                   var way = context.entity(wayID);
56780                   return way.nodes.indexOf(vertexID) !== -1;
56781                 });
56782
56783                 action.limitWays(waysIDsForVertex);
56784               }
56785
56786               _actions.push(action);
56787
56788               _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
56789                 return d.id;
56790               }));
56791             });
56792
56793             _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
56794               return _wayIDs.indexOf(id) === -1;
56795             });
56796             _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
56797
56798             if (_wayIDs.length === 1) {
56799               _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
56800             } else {
56801               _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
56802             }
56803           } else if (_wayIDs.length > 0) {
56804             // Disconnect the selected ways from each other, if they're connected,
56805             // else disconnect them from all connected ways
56806             var ways = _wayIDs.map(function (id) {
56807               return context.entity(id);
56808             });
56809
56810             var nodes = utilGetAllNodes(_wayIDs, context.graph());
56811             _coords = nodes.map(function (n) {
56812               return n.loc;
56813             }); // actions for connected nodes shared by at least two selected ways
56814
56815             var sharedActions = [];
56816             var sharedNodes = []; // actions for connected nodes
56817
56818             var unsharedActions = [];
56819             var unsharedNodes = [];
56820             nodes.forEach(function (node) {
56821               var action = actionDisconnect(node.id).limitWays(_wayIDs);
56822
56823               if (action.disabled(context.graph()) !== 'not_connected') {
56824                 var count = 0;
56825
56826                 for (var i in ways) {
56827                   var way = ways[i];
56828
56829                   if (way.nodes.indexOf(node.id) !== -1) {
56830                     count += 1;
56831                   }
56832
56833                   if (count > 1) break;
56834                 }
56835
56836                 if (count > 1) {
56837                   sharedActions.push(action);
56838                   sharedNodes.push(node);
56839                 } else {
56840                   unsharedActions.push(action);
56841                   unsharedNodes.push(node);
56842                 }
56843               }
56844             });
56845             _descriptionID += 'no_points.';
56846             _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
56847
56848             if (sharedActions.length) {
56849               // if any nodes are shared, only disconnect the selected ways from each other
56850               _actions = sharedActions;
56851               _disconnectingVertexIds = sharedNodes.map(function (node) {
56852                 return node.id;
56853               });
56854               _descriptionID += 'conjoined';
56855               _annotationID = 'from_each_other';
56856             } else {
56857               // if no nodes are shared, disconnect the selected ways from all connected ways
56858               _actions = unsharedActions;
56859               _disconnectingVertexIds = unsharedNodes.map(function (node) {
56860                 return node.id;
56861               });
56862
56863               if (_wayIDs.length === 1) {
56864                 _descriptionID += context.graph().geometry(_wayIDs[0]);
56865               } else {
56866                 _descriptionID += 'separate';
56867               }
56868             }
56869           }
56870
56871           var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
56872
56873           var operation = function operation() {
56874             context.perform(function (graph) {
56875               return _actions.reduce(function (graph, action) {
56876                 return action(graph);
56877               }, graph);
56878             }, operation.annotation());
56879             context.validator().validate();
56880           };
56881
56882           operation.relatedEntityIds = function () {
56883             if (_vertexIDs.length) {
56884               return _disconnectingWayIds;
56885             }
56886
56887             return _disconnectingVertexIds;
56888           };
56889
56890           operation.available = function () {
56891             if (_actions.length === 0) return false;
56892             if (_otherIDs.length !== 0) return false;
56893             if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
56894               return _vertexIDs.some(function (vertexID) {
56895                 var way = context.entity(wayID);
56896                 return way.nodes.indexOf(vertexID) !== -1;
56897               });
56898             })) return false;
56899             return true;
56900           };
56901
56902           operation.disabled = function () {
56903             var reason;
56904
56905             for (var actionIndex in _actions) {
56906               reason = _actions[actionIndex].disabled(context.graph());
56907               if (reason) return reason;
56908             }
56909
56910             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
56911               return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
56912             } else if (_coords && someMissing()) {
56913               return 'not_downloaded';
56914             } else if (selectedIDs.some(context.hasHiddenConnections)) {
56915               return 'connected_to_hidden';
56916             }
56917
56918             return false;
56919
56920             function someMissing() {
56921               if (context.inIntro()) return false;
56922               var osm = context.connection();
56923
56924               if (osm) {
56925                 var missing = _coords.filter(function (loc) {
56926                   return !osm.isDataLoaded(loc);
56927                 });
56928
56929                 if (missing.length) {
56930                   missing.forEach(function (loc) {
56931                     context.loadTileAtLoc(loc);
56932                   });
56933                   return true;
56934                 }
56935               }
56936
56937               return false;
56938             }
56939           };
56940
56941           operation.tooltip = function () {
56942             var disable = operation.disabled();
56943
56944             if (disable) {
56945               return _t('operations.disconnect.' + disable);
56946             }
56947
56948             return _t('operations.disconnect.description.' + _descriptionID);
56949           };
56950
56951           operation.annotation = function () {
56952             return _t('operations.disconnect.annotation.' + _annotationID);
56953           };
56954
56955           operation.id = 'disconnect';
56956           operation.keys = [_t('operations.disconnect.key')];
56957           operation.title = _t('operations.disconnect.title');
56958           operation.behavior = behaviorOperation(context).which(operation);
56959           return operation;
56960         }
56961
56962         function operationDowngrade(context, selectedIDs) {
56963           var _affectedFeatureCount = 0;
56964
56965           var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
56966
56967           var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
56968
56969           function downgradeTypeForEntityIDs(entityIds) {
56970             var downgradeType;
56971             _affectedFeatureCount = 0;
56972
56973             for (var i in entityIds) {
56974               var entityID = entityIds[i];
56975               var type = downgradeTypeForEntityID(entityID);
56976
56977               if (type) {
56978                 _affectedFeatureCount += 1;
56979
56980                 if (downgradeType && type !== downgradeType) {
56981                   if (downgradeType !== 'generic' && type !== 'generic') {
56982                     downgradeType = 'building_address';
56983                   } else {
56984                     downgradeType = 'generic';
56985                   }
56986                 } else {
56987                   downgradeType = type;
56988                 }
56989               }
56990             }
56991
56992             return downgradeType;
56993           }
56994
56995           function downgradeTypeForEntityID(entityID) {
56996             var graph = context.graph();
56997             var entity = graph.entity(entityID);
56998             var preset = _mainPresetIndex.match(entity, graph);
56999             if (!preset || preset.isFallback()) return null;
57000
57001             if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
57002               return key.match(/^addr:.{1,}/);
57003             })) {
57004               return 'address';
57005             }
57006
57007             var geometry = entity.geometry(graph);
57008
57009             if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
57010               return 'building';
57011             }
57012
57013             if (geometry === 'vertex' && Object.keys(entity.tags).length) {
57014               return 'generic';
57015             }
57016
57017             return null;
57018           }
57019
57020           var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
57021           var addressKeysToKeep = ['source'];
57022
57023           var operation = function operation() {
57024             context.perform(function (graph) {
57025               for (var i in selectedIDs) {
57026                 var entityID = selectedIDs[i];
57027                 var type = downgradeTypeForEntityID(entityID);
57028                 if (!type) continue;
57029                 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
57030
57031                 for (var key in tags) {
57032                   if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
57033
57034                   if (type === 'building') {
57035                     if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
57036                   }
57037
57038                   if (type !== 'generic') {
57039                     if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
57040                   }
57041
57042                   delete tags[key];
57043                 }
57044
57045                 graph = actionChangeTags(entityID, tags)(graph);
57046               }
57047
57048               return graph;
57049             }, operation.annotation());
57050             context.validator().validate(); // refresh the select mode to enable the delete operation
57051
57052             context.enter(modeSelect(context, selectedIDs));
57053           };
57054
57055           operation.available = function () {
57056             return _downgradeType;
57057           };
57058
57059           operation.disabled = function () {
57060             if (selectedIDs.some(hasWikidataTag)) {
57061               return 'has_wikidata_tag';
57062             }
57063
57064             return false;
57065
57066             function hasWikidataTag(id) {
57067               var entity = context.entity(id);
57068               return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
57069             }
57070           };
57071
57072           operation.tooltip = function () {
57073             var disable = operation.disabled();
57074             return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
57075           };
57076
57077           operation.annotation = function () {
57078             var suffix;
57079
57080             if (_downgradeType === 'building_address') {
57081               suffix = 'generic';
57082             } else {
57083               suffix = _downgradeType;
57084             }
57085
57086             return _t('operations.downgrade.annotation.' + suffix, {
57087               n: _affectedFeatureCount
57088             });
57089           };
57090
57091           operation.id = 'downgrade';
57092           operation.keys = [uiCmd('⌫')];
57093           operation.title = _t('operations.downgrade.title');
57094           operation.behavior = behaviorOperation(context).which(operation);
57095           return operation;
57096         }
57097
57098         function operationExtract(context, selectedIDs) {
57099           var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
57100
57101           var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
57102             return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
57103           }).filter(Boolean));
57104
57105           var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
57106
57107           var _extent;
57108
57109           var _actions = selectedIDs.map(function (entityID) {
57110             var graph = context.graph();
57111             var entity = graph.hasEntity(entityID);
57112             if (!entity || !entity.hasInterestingTags()) return null;
57113             if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
57114
57115             if (entity.type !== 'node') {
57116               var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
57117
57118               if (preset.geometry.indexOf('point') === -1) return null;
57119             }
57120
57121             _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
57122             return actionExtract(entityID);
57123           }).filter(Boolean);
57124
57125           var operation = function operation() {
57126             var combinedAction = function combinedAction(graph) {
57127               _actions.forEach(function (action) {
57128                 graph = action(graph);
57129               });
57130
57131               return graph;
57132             };
57133
57134             context.perform(combinedAction, operation.annotation()); // do the extract
57135
57136             var extractedNodeIDs = _actions.map(function (action) {
57137               return action.getExtractedNodeID();
57138             });
57139
57140             context.enter(modeSelect(context, extractedNodeIDs));
57141           };
57142
57143           operation.available = function () {
57144             return _actions.length && selectedIDs.length === _actions.length;
57145           };
57146
57147           operation.disabled = function () {
57148             if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
57149               return 'too_large';
57150             } else if (selectedIDs.some(function (entityID) {
57151               return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
57152             })) {
57153               return 'connected_to_hidden';
57154             }
57155
57156             return false;
57157           };
57158
57159           operation.tooltip = function () {
57160             var disableReason = operation.disabled();
57161
57162             if (disableReason) {
57163               return _t('operations.extract.' + disableReason + '.' + _amount);
57164             } else {
57165               return _t('operations.extract.description.' + _geometryID + '.' + _amount);
57166             }
57167           };
57168
57169           operation.annotation = function () {
57170             return _t('operations.extract.annotation', {
57171               n: selectedIDs.length
57172             });
57173           };
57174
57175           operation.id = 'extract';
57176           operation.keys = [_t('operations.extract.key')];
57177           operation.title = _t('operations.extract.title');
57178           operation.behavior = behaviorOperation(context).which(operation);
57179           return operation;
57180         }
57181
57182         function operationMerge(context, selectedIDs) {
57183           var _action = getAction();
57184
57185           function getAction() {
57186             // prefer a non-disabled action first
57187             var join = actionJoin(selectedIDs);
57188             if (!join.disabled(context.graph())) return join;
57189             var merge = actionMerge(selectedIDs);
57190             if (!merge.disabled(context.graph())) return merge;
57191             var mergePolygon = actionMergePolygon(selectedIDs);
57192             if (!mergePolygon.disabled(context.graph())) return mergePolygon;
57193             var mergeNodes = actionMergeNodes(selectedIDs);
57194             if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
57195
57196             if (join.disabled(context.graph()) !== 'not_eligible') return join;
57197             if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
57198             if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
57199             return mergeNodes;
57200           }
57201
57202           var operation = function operation() {
57203             if (operation.disabled()) return;
57204             context.perform(_action, operation.annotation());
57205             context.validator().validate();
57206             var resultIDs = selectedIDs.filter(context.hasEntity);
57207
57208             if (resultIDs.length > 1) {
57209               var interestingIDs = resultIDs.filter(function (id) {
57210                 return context.entity(id).hasInterestingTags();
57211               });
57212               if (interestingIDs.length) resultIDs = interestingIDs;
57213             }
57214
57215             context.enter(modeSelect(context, resultIDs));
57216           };
57217
57218           operation.available = function () {
57219             return selectedIDs.length >= 2;
57220           };
57221
57222           operation.disabled = function () {
57223             var actionDisabled = _action.disabled(context.graph());
57224
57225             if (actionDisabled) return actionDisabled;
57226             var osm = context.connection();
57227
57228             if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
57229               return 'too_many_vertices';
57230             }
57231
57232             return false;
57233           };
57234
57235           operation.tooltip = function () {
57236             var disabled = operation.disabled();
57237
57238             if (disabled) {
57239               if (disabled === 'restriction') {
57240                 return _t('operations.merge.restriction', {
57241                   relation: _mainPresetIndex.item('type/restriction').name()
57242                 });
57243               }
57244
57245               return _t('operations.merge.' + disabled);
57246             }
57247
57248             return _t('operations.merge.description');
57249           };
57250
57251           operation.annotation = function () {
57252             return _t('operations.merge.annotation', {
57253               n: selectedIDs.length
57254             });
57255           };
57256
57257           operation.id = 'merge';
57258           operation.keys = [_t('operations.merge.key')];
57259           operation.title = _t('operations.merge.title');
57260           operation.behavior = behaviorOperation(context).which(operation);
57261           return operation;
57262         }
57263
57264         function operationPaste(context) {
57265           var _pastePoint;
57266
57267           var operation = function operation() {
57268             if (!_pastePoint) return;
57269             var oldIDs = context.copyIDs();
57270             if (!oldIDs.length) return;
57271             var projection = context.projection;
57272             var extent = geoExtent();
57273             var oldGraph = context.copyGraph();
57274             var newIDs = [];
57275             var action = actionCopyEntities(oldIDs, oldGraph);
57276             context.perform(action);
57277             var copies = action.copies();
57278             var originals = new Set();
57279             Object.values(copies).forEach(function (entity) {
57280               originals.add(entity.id);
57281             });
57282
57283             for (var id in copies) {
57284               var oldEntity = oldGraph.entity(id);
57285               var newEntity = copies[id];
57286
57287               extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
57288
57289
57290               var parents = context.graph().parentWays(newEntity);
57291               var parentCopied = parents.some(function (parent) {
57292                 return originals.has(parent.id);
57293               });
57294
57295               if (!parentCopied) {
57296                 newIDs.push(newEntity.id);
57297               }
57298             } // Use the location of the copy operation to offset the paste location,
57299             // or else use the center of the pasted extent
57300
57301
57302             var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
57303             var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
57304
57305             context.replace(actionMove(newIDs, delta, projection), operation.annotation());
57306             context.enter(modeSelect(context, newIDs));
57307           };
57308
57309           operation.point = function (val) {
57310             _pastePoint = val;
57311             return operation;
57312           };
57313
57314           operation.available = function () {
57315             return context.mode().id === 'browse';
57316           };
57317
57318           operation.disabled = function () {
57319             return !context.copyIDs().length;
57320           };
57321
57322           operation.tooltip = function () {
57323             var oldGraph = context.copyGraph();
57324             var ids = context.copyIDs();
57325
57326             if (!ids.length) {
57327               return _t('operations.paste.nothing_copied');
57328             }
57329
57330             return _t('operations.paste.description', {
57331               feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
57332               n: ids.length
57333             });
57334           };
57335
57336           operation.annotation = function () {
57337             var ids = context.copyIDs();
57338             return _t('operations.paste.annotation', {
57339               n: ids.length
57340             });
57341           };
57342
57343           operation.id = 'paste';
57344           operation.keys = [uiCmd('⌘V')];
57345           operation.title = _t('operations.paste.title');
57346           return operation;
57347         }
57348
57349         function operationReverse(context, selectedIDs) {
57350           var operation = function operation() {
57351             context.perform(function combinedReverseAction(graph) {
57352               actions().forEach(function (action) {
57353                 graph = action(graph);
57354               });
57355               return graph;
57356             }, operation.annotation());
57357             context.validator().validate();
57358           };
57359
57360           function actions(situation) {
57361             return selectedIDs.map(function (entityID) {
57362               var entity = context.hasEntity(entityID);
57363               if (!entity) return null;
57364
57365               if (situation === 'toolbar') {
57366                 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
57367               }
57368
57369               var geometry = entity.geometry(context.graph());
57370               if (entity.type !== 'node' && geometry !== 'line') return null;
57371               var action = actionReverse(entityID);
57372               if (action.disabled(context.graph())) return null;
57373               return action;
57374             }).filter(Boolean);
57375           }
57376
57377           function reverseTypeID() {
57378             var acts = actions();
57379             var nodeActionCount = acts.filter(function (act) {
57380               var entity = context.hasEntity(act.entityID());
57381               return entity && entity.type === 'node';
57382             }).length;
57383             if (nodeActionCount === 0) return 'line';
57384             if (nodeActionCount === acts.length) return 'point';
57385             return 'feature';
57386           }
57387
57388           operation.available = function (situation) {
57389             return actions(situation).length > 0;
57390           };
57391
57392           operation.disabled = function () {
57393             return false;
57394           };
57395
57396           operation.tooltip = function () {
57397             return _t('operations.reverse.description.' + reverseTypeID());
57398           };
57399
57400           operation.annotation = function () {
57401             var acts = actions();
57402             return _t('operations.reverse.annotation.' + reverseTypeID(), {
57403               n: acts.length
57404             });
57405           };
57406
57407           operation.id = 'reverse';
57408           operation.keys = [_t('operations.reverse.key')];
57409           operation.title = _t('operations.reverse.title');
57410           operation.behavior = behaviorOperation(context).which(operation);
57411           return operation;
57412         }
57413
57414         function operationSplit(context, selectedIDs) {
57415           var _vertexIds = selectedIDs.filter(function (id) {
57416             return context.graph().geometry(id) === 'vertex';
57417           });
57418
57419           var _selectedWayIds = selectedIDs.filter(function (id) {
57420             var entity = context.graph().hasEntity(id);
57421             return entity && entity.type === 'way';
57422           });
57423
57424           var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
57425
57426           var _action = actionSplit(_vertexIds);
57427
57428           var _ways = [];
57429           var _geometry = 'feature';
57430           var _waysAmount = 'single';
57431
57432           var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
57433
57434           if (_isAvailable) {
57435             if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
57436             _ways = _action.ways(context.graph());
57437             var geometries = {};
57438
57439             _ways.forEach(function (way) {
57440               geometries[way.geometry(context.graph())] = true;
57441             });
57442
57443             if (Object.keys(geometries).length === 1) {
57444               _geometry = Object.keys(geometries)[0];
57445             }
57446
57447             _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
57448           }
57449
57450           var operation = function operation() {
57451             var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
57452
57453             var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
57454               // filter out relations that may have had member additions
57455               return context.entity(id).type === 'way';
57456             }));
57457
57458             context.enter(modeSelect(context, idsToSelect));
57459           };
57460
57461           operation.relatedEntityIds = function () {
57462             return _selectedWayIds.length ? [] : _ways.map(function (way) {
57463               return way.id;
57464             });
57465           };
57466
57467           operation.available = function () {
57468             return _isAvailable;
57469           };
57470
57471           operation.disabled = function () {
57472             var reason = _action.disabled(context.graph());
57473
57474             if (reason) {
57475               return reason;
57476             } else if (selectedIDs.some(context.hasHiddenConnections)) {
57477               return 'connected_to_hidden';
57478             }
57479
57480             return false;
57481           };
57482
57483           operation.tooltip = function () {
57484             var disable = operation.disabled();
57485             if (disable) return _t('operations.split.' + disable);
57486             return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
57487           };
57488
57489           operation.annotation = function () {
57490             return _t('operations.split.annotation.' + _geometry, {
57491               n: _ways.length
57492             });
57493           };
57494
57495           operation.id = 'split';
57496           operation.keys = [_t('operations.split.key')];
57497           operation.title = _t('operations.split.title');
57498           operation.behavior = behaviorOperation(context).which(operation);
57499           return operation;
57500         }
57501
57502         function operationStraighten(context, selectedIDs) {
57503           var _wayIDs = selectedIDs.filter(function (id) {
57504             return id.charAt(0) === 'w';
57505           });
57506
57507           var _nodeIDs = selectedIDs.filter(function (id) {
57508             return id.charAt(0) === 'n';
57509           });
57510
57511           var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
57512
57513           var _nodes = utilGetAllNodes(selectedIDs, context.graph());
57514
57515           var _coords = _nodes.map(function (n) {
57516             return n.loc;
57517           });
57518
57519           var _extent = utilTotalExtent(selectedIDs, context.graph());
57520
57521           var _action = chooseAction();
57522
57523           var _geometry;
57524
57525           function chooseAction() {
57526             // straighten selected nodes
57527             if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
57528               _geometry = 'point';
57529               return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
57530             } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
57531               var startNodeIDs = [];
57532               var endNodeIDs = [];
57533
57534               for (var i = 0; i < selectedIDs.length; i++) {
57535                 var entity = context.entity(selectedIDs[i]);
57536
57537                 if (entity.type === 'node') {
57538                   continue;
57539                 } else if (entity.type !== 'way' || entity.isClosed()) {
57540                   return null; // exit early, can't straighten these
57541                 }
57542
57543                 startNodeIDs.push(entity.first());
57544                 endNodeIDs.push(entity.last());
57545               } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
57546
57547
57548               startNodeIDs = startNodeIDs.filter(function (n) {
57549                 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
57550               });
57551               endNodeIDs = endNodeIDs.filter(function (n) {
57552                 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
57553               }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
57554
57555               if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
57556
57557               var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
57558                 return node.id;
57559               });
57560               if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
57561
57562               if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
57563
57564               if (_nodeIDs.length) {
57565                 // If we're only straightenting between two points, we only need that extent visible
57566                 _extent = utilTotalExtent(_nodeIDs, context.graph());
57567               }
57568
57569               _geometry = 'line';
57570               return actionStraightenWay(selectedIDs, context.projection);
57571             }
57572
57573             return null;
57574           }
57575
57576           function operation() {
57577             if (!_action) return;
57578             context.perform(_action, operation.annotation());
57579             window.setTimeout(function () {
57580               context.validator().validate();
57581             }, 300); // after any transition
57582           }
57583
57584           operation.available = function () {
57585             return Boolean(_action);
57586           };
57587
57588           operation.disabled = function () {
57589             var reason = _action.disabled(context.graph());
57590
57591             if (reason) {
57592               return reason;
57593             } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
57594               return 'too_large';
57595             } else if (someMissing()) {
57596               return 'not_downloaded';
57597             } else if (selectedIDs.some(context.hasHiddenConnections)) {
57598               return 'connected_to_hidden';
57599             }
57600
57601             return false;
57602
57603             function someMissing() {
57604               if (context.inIntro()) return false;
57605               var osm = context.connection();
57606
57607               if (osm) {
57608                 var missing = _coords.filter(function (loc) {
57609                   return !osm.isDataLoaded(loc);
57610                 });
57611
57612                 if (missing.length) {
57613                   missing.forEach(function (loc) {
57614                     context.loadTileAtLoc(loc);
57615                   });
57616                   return true;
57617                 }
57618               }
57619
57620               return false;
57621             }
57622           };
57623
57624           operation.tooltip = function () {
57625             var disable = operation.disabled();
57626             return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
57627           };
57628
57629           operation.annotation = function () {
57630             return _t('operations.straighten.annotation.' + _geometry, {
57631               n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
57632             });
57633           };
57634
57635           operation.id = 'straighten';
57636           operation.keys = [_t('operations.straighten.key')];
57637           operation.title = _t('operations.straighten.title');
57638           operation.behavior = behaviorOperation(context).which(operation);
57639           return operation;
57640         }
57641
57642         var Operations = /*#__PURE__*/Object.freeze({
57643                 __proto__: null,
57644                 operationCircularize: operationCircularize,
57645                 operationContinue: operationContinue,
57646                 operationCopy: operationCopy,
57647                 operationDelete: operationDelete,
57648                 operationDisconnect: operationDisconnect,
57649                 operationDowngrade: operationDowngrade,
57650                 operationExtract: operationExtract,
57651                 operationMerge: operationMerge,
57652                 operationMove: operationMove,
57653                 operationOrthogonalize: operationOrthogonalize,
57654                 operationPaste: operationPaste,
57655                 operationReflectShort: operationReflectShort,
57656                 operationReflectLong: operationReflectLong,
57657                 operationReverse: operationReverse,
57658                 operationRotate: operationRotate,
57659                 operationSplit: operationSplit,
57660                 operationStraighten: operationStraighten
57661         });
57662
57663         var _relatedParent;
57664
57665         function modeSelect(context, selectedIDs) {
57666           var mode = {
57667             id: 'select',
57668             button: 'browse'
57669           };
57670           var keybinding = utilKeybinding('select');
57671
57672           var _breatheBehavior = behaviorBreathe();
57673
57674           var _modeDragNode = modeDragNode(context);
57675
57676           var _selectBehavior;
57677
57678           var _behaviors = [];
57679           var _operations = [];
57680           var _newFeature = false;
57681           var _follow = false;
57682
57683           function singular() {
57684             if (selectedIDs && selectedIDs.length === 1) {
57685               return context.hasEntity(selectedIDs[0]);
57686             }
57687           }
57688
57689           function selectedEntities() {
57690             return selectedIDs.map(function (id) {
57691               return context.hasEntity(id);
57692             }).filter(Boolean);
57693           }
57694
57695           function checkSelectedIDs() {
57696             var ids = [];
57697
57698             if (Array.isArray(selectedIDs)) {
57699               ids = selectedIDs.filter(function (id) {
57700                 return context.hasEntity(id);
57701               });
57702             }
57703
57704             if (!ids.length) {
57705               context.enter(modeBrowse(context));
57706               return false;
57707             } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
57708               // switch between single- and multi-select UI
57709               context.enter(modeSelect(context, ids));
57710               return false;
57711             }
57712
57713             selectedIDs = ids;
57714             return true;
57715           } // find the common parent ways for nextVertex, previousVertex
57716
57717
57718           function commonParents() {
57719             var graph = context.graph();
57720             var commonParents = [];
57721
57722             for (var i = 0; i < selectedIDs.length; i++) {
57723               var entity = context.hasEntity(selectedIDs[i]);
57724
57725               if (!entity || entity.geometry(graph) !== 'vertex') {
57726                 return []; // selection includes some not vertices
57727               }
57728
57729               var currParents = graph.parentWays(entity).map(function (w) {
57730                 return w.id;
57731               });
57732
57733               if (!commonParents.length) {
57734                 commonParents = currParents;
57735                 continue;
57736               }
57737
57738               commonParents = utilArrayIntersection(commonParents, currParents);
57739
57740               if (!commonParents.length) {
57741                 return [];
57742               }
57743             }
57744
57745             return commonParents;
57746           }
57747
57748           function singularParent() {
57749             var parents = commonParents();
57750
57751             if (!parents || parents.length === 0) {
57752               _relatedParent = null;
57753               return null;
57754             } // relatedParent is used when we visit a vertex with multiple
57755             // parents, and we want to remember which parent line we started on.
57756
57757
57758             if (parents.length === 1) {
57759               _relatedParent = parents[0]; // remember this parent for later
57760
57761               return _relatedParent;
57762             }
57763
57764             if (parents.indexOf(_relatedParent) !== -1) {
57765               return _relatedParent; // prefer the previously seen parent
57766             }
57767
57768             return parents[0];
57769           }
57770
57771           mode.selectedIDs = function (val) {
57772             if (!arguments.length) return selectedIDs;
57773             selectedIDs = val;
57774             return mode;
57775           };
57776
57777           mode.zoomToSelected = function () {
57778             context.map().zoomToEase(selectedEntities());
57779           };
57780
57781           mode.newFeature = function (val) {
57782             if (!arguments.length) return _newFeature;
57783             _newFeature = val;
57784             return mode;
57785           };
57786
57787           mode.selectBehavior = function (val) {
57788             if (!arguments.length) return _selectBehavior;
57789             _selectBehavior = val;
57790             return mode;
57791           };
57792
57793           mode.follow = function (val) {
57794             if (!arguments.length) return _follow;
57795             _follow = val;
57796             return mode;
57797           };
57798
57799           function loadOperations() {
57800             _operations.forEach(function (operation) {
57801               if (operation.behavior) {
57802                 context.uninstall(operation.behavior);
57803               }
57804             });
57805
57806             _operations = Object.values(Operations).map(function (o) {
57807               return o(context, selectedIDs);
57808             }).filter(function (o) {
57809               return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
57810             }).concat([// group copy/downgrade/delete operation together at the end of the list
57811             operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
57812               return operation.available();
57813             });
57814
57815             _operations.forEach(function (operation) {
57816               if (operation.behavior) {
57817                 context.install(operation.behavior);
57818               }
57819             }); // remove any displayed menu
57820
57821
57822             context.ui().closeEditMenu();
57823           }
57824
57825           mode.operations = function () {
57826             return _operations;
57827           };
57828
57829           mode.enter = function () {
57830             if (!checkSelectedIDs()) return;
57831             context.features().forceVisible(selectedIDs);
57832
57833             _modeDragNode.restoreSelectedIDs(selectedIDs);
57834
57835             loadOperations();
57836
57837             if (!_behaviors.length) {
57838               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
57839               _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
57840             }
57841
57842             _behaviors.forEach(context.install);
57843
57844             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) {
57845               return uiCmd('⇧' + key);
57846             }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
57847               return uiCmd('⇧⌥' + key);
57848             }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
57849               return uiCmd('⇧' + key);
57850             }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
57851               return uiCmd('⇧⌥' + key);
57852             }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], nextParent).on('⎋', esc, true);
57853             select(document).call(keybinding);
57854             context.ui().sidebar.select(selectedIDs, _newFeature);
57855             context.history().on('change.select', function () {
57856               loadOperations(); // reselect after change in case relation members were removed or added
57857
57858               selectElements();
57859             }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
57860             context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
57861               selectElements();
57862
57863               _breatheBehavior.restartIfNeeded(context.surface());
57864             });
57865             context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
57866             selectElements();
57867
57868             if (_follow) {
57869               var extent = geoExtent();
57870               var graph = context.graph();
57871               selectedIDs.forEach(function (id) {
57872                 var entity = context.entity(id);
57873
57874                 extent._extend(entity.extent(graph));
57875               });
57876               var loc = extent.center();
57877               context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
57878
57879               _follow = false;
57880             }
57881
57882             function nudgeSelection(delta) {
57883               return function () {
57884                 // prevent nudging during low zoom selection
57885                 if (!context.map().withinEditableZoom()) return;
57886                 var moveOp = operationMove(context, selectedIDs);
57887
57888                 if (moveOp.disabled()) {
57889                   context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
57890                 } else {
57891                   context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
57892                   context.validator().validate();
57893                 }
57894               };
57895             }
57896
57897             function scaleSelection(factor) {
57898               return function () {
57899                 // prevent scaling during low zoom selection
57900                 if (!context.map().withinEditableZoom()) return;
57901                 var nodes = utilGetAllNodes(selectedIDs, context.graph());
57902                 var isUp = factor > 1; // can only scale if multiple nodes are selected
57903
57904                 if (nodes.length <= 1) return;
57905                 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
57906                 // object, but we don't want an actual scale operation at this point.
57907
57908                 function scalingDisabled() {
57909                   if (tooSmall()) {
57910                     return 'too_small';
57911                   } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
57912                     return 'too_large';
57913                   } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
57914                     return 'not_downloaded';
57915                   } else if (selectedIDs.some(context.hasHiddenConnections)) {
57916                     return 'connected_to_hidden';
57917                   }
57918
57919                   return false;
57920
57921                   function tooSmall() {
57922                     if (isUp) return false;
57923                     var dLon = Math.abs(extent[1][0] - extent[0][0]);
57924                     var dLat = Math.abs(extent[1][1] - extent[0][1]);
57925                     return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
57926                   }
57927
57928                   function someMissing() {
57929                     if (context.inIntro()) return false;
57930                     var osm = context.connection();
57931
57932                     if (osm) {
57933                       var missing = nodes.filter(function (n) {
57934                         return !osm.isDataLoaded(n.loc);
57935                       });
57936
57937                       if (missing.length) {
57938                         missing.forEach(function (loc) {
57939                           context.loadTileAtLoc(loc);
57940                         });
57941                         return true;
57942                       }
57943                     }
57944
57945                     return false;
57946                   }
57947
57948                   function incompleteRelation(id) {
57949                     var entity = context.entity(id);
57950                     return entity.type === 'relation' && !entity.isComplete(context.graph());
57951                   }
57952                 }
57953
57954                 var disabled = scalingDisabled();
57955
57956                 if (disabled) {
57957                   var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
57958                   context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
57959                 } else {
57960                   var pivot = context.projection(extent.center());
57961                   var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
57962                     n: selectedIDs.length
57963                   });
57964                   context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
57965                   context.validator().validate();
57966                 }
57967               };
57968             }
57969
57970             function didDoubleUp(d3_event, loc) {
57971               if (!context.map().withinEditableZoom()) return;
57972               var target = select(d3_event.target);
57973               var datum = target.datum();
57974               var entity = datum && datum.properties && datum.properties.entity;
57975               if (!entity) return;
57976
57977               if (entity instanceof osmWay && target.classed('target')) {
57978                 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
57979                 var prev = entity.nodes[choice.index - 1];
57980                 var next = entity.nodes[choice.index];
57981                 context.perform(actionAddMidpoint({
57982                   loc: choice.loc,
57983                   edge: [prev, next]
57984                 }, osmNode()), _t('operations.add.annotation.vertex'));
57985               } else if (entity.type === 'midpoint') {
57986                 context.perform(actionAddMidpoint({
57987                   loc: entity.loc,
57988                   edge: entity.edge
57989                 }, osmNode()), _t('operations.add.annotation.vertex'));
57990               }
57991             }
57992
57993             function selectElements() {
57994               if (!checkSelectedIDs()) return;
57995               var surface = context.surface();
57996               surface.selectAll('.selected-member').classed('selected-member', false);
57997               surface.selectAll('.selected').classed('selected', false);
57998               surface.selectAll('.related').classed('related', false);
57999               singularParent();
58000
58001               if (_relatedParent) {
58002                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
58003               }
58004
58005               if (context.map().withinEditableZoom()) {
58006                 // Apply selection styling if not in wide selection
58007                 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
58008                 /* skipMultipolgonMembers */
58009                 )).classed('selected-member', true);
58010                 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
58011               }
58012             }
58013
58014             function esc() {
58015               if (context.container().select('.combobox').size()) return;
58016               context.enter(modeBrowse(context));
58017             }
58018
58019             function firstVertex(d3_event) {
58020               d3_event.preventDefault();
58021               var entity = singular();
58022               var parent = singularParent();
58023               var way;
58024
58025               if (entity && entity.type === 'way') {
58026                 way = entity;
58027               } else if (parent) {
58028                 way = context.entity(parent);
58029               }
58030
58031               if (way) {
58032                 context.enter(modeSelect(context, [way.first()]).follow(true));
58033               }
58034             }
58035
58036             function lastVertex(d3_event) {
58037               d3_event.preventDefault();
58038               var entity = singular();
58039               var parent = singularParent();
58040               var way;
58041
58042               if (entity && entity.type === 'way') {
58043                 way = entity;
58044               } else if (parent) {
58045                 way = context.entity(parent);
58046               }
58047
58048               if (way) {
58049                 context.enter(modeSelect(context, [way.last()]).follow(true));
58050               }
58051             }
58052
58053             function previousVertex(d3_event) {
58054               d3_event.preventDefault();
58055               var parent = singularParent();
58056               if (!parent) return;
58057               var way = context.entity(parent);
58058               var length = way.nodes.length;
58059               var curr = way.nodes.indexOf(selectedIDs[0]);
58060               var index = -1;
58061
58062               if (curr > 0) {
58063                 index = curr - 1;
58064               } else if (way.isClosed()) {
58065                 index = length - 2;
58066               }
58067
58068               if (index !== -1) {
58069                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
58070               }
58071             }
58072
58073             function nextVertex(d3_event) {
58074               d3_event.preventDefault();
58075               var parent = singularParent();
58076               if (!parent) return;
58077               var way = context.entity(parent);
58078               var length = way.nodes.length;
58079               var curr = way.nodes.indexOf(selectedIDs[0]);
58080               var index = -1;
58081
58082               if (curr < length - 1) {
58083                 index = curr + 1;
58084               } else if (way.isClosed()) {
58085                 index = 0;
58086               }
58087
58088               if (index !== -1) {
58089                 context.enter(modeSelect(context, [way.nodes[index]]).follow(true));
58090               }
58091             }
58092
58093             function nextParent(d3_event) {
58094               d3_event.preventDefault();
58095               var parents = commonParents();
58096               if (!parents || parents.length < 2) return;
58097               var index = parents.indexOf(_relatedParent);
58098
58099               if (index < 0 || index > parents.length - 2) {
58100                 _relatedParent = parents[0];
58101               } else {
58102                 _relatedParent = parents[index + 1];
58103               }
58104
58105               var surface = context.surface();
58106               surface.selectAll('.related').classed('related', false);
58107
58108               if (_relatedParent) {
58109                 surface.selectAll(utilEntitySelector([_relatedParent])).classed('related', true);
58110               }
58111             }
58112           };
58113
58114           mode.exit = function () {
58115             _newFeature = false;
58116
58117             _operations.forEach(function (operation) {
58118               if (operation.behavior) {
58119                 context.uninstall(operation.behavior);
58120               }
58121             });
58122
58123             _operations = [];
58124
58125             _behaviors.forEach(context.uninstall);
58126
58127             select(document).call(keybinding.unbind);
58128             context.ui().closeEditMenu();
58129             context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
58130             var surface = context.surface();
58131             surface.selectAll('.selected-member').classed('selected-member', false);
58132             surface.selectAll('.selected').classed('selected', false);
58133             surface.selectAll('.highlighted').classed('highlighted', false);
58134             surface.selectAll('.related').classed('related', false);
58135             context.map().on('drawn.select', null);
58136             context.ui().sidebar.hide();
58137             context.features().forceVisible([]);
58138             var entity = singular();
58139
58140             if (_newFeature && entity && entity.type === 'relation' && // no tags
58141             Object.keys(entity.tags).length === 0 && // no parent relations
58142             context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
58143             entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
58144               // the user added this relation but didn't edit it at all, so just delete it
58145               var deleteAction = actionDeleteRelation(entity.id, true
58146               /* don't delete untagged members */
58147               );
58148               context.perform(deleteAction, _t('operations.delete.annotation.relation'));
58149             }
58150           };
58151
58152           return mode;
58153         }
58154
58155         function uiLasso(context) {
58156           var group, polygon;
58157           lasso.coordinates = [];
58158
58159           function lasso(selection) {
58160             context.container().classed('lasso', true);
58161             group = selection.append('g').attr('class', 'lasso hide');
58162             polygon = group.append('path').attr('class', 'lasso-path');
58163             group.call(uiToggle(true));
58164           }
58165
58166           function draw() {
58167             if (polygon) {
58168               polygon.data([lasso.coordinates]).attr('d', function (d) {
58169                 return 'M' + d.join(' L') + ' Z';
58170               });
58171             }
58172           }
58173
58174           lasso.extent = function () {
58175             return lasso.coordinates.reduce(function (extent, point) {
58176               return extent.extend(geoExtent(point));
58177             }, geoExtent());
58178           };
58179
58180           lasso.p = function (_) {
58181             if (!arguments.length) return lasso;
58182             lasso.coordinates.push(_);
58183             draw();
58184             return lasso;
58185           };
58186
58187           lasso.close = function () {
58188             if (group) {
58189               group.call(uiToggle(false, function () {
58190                 select(this).remove();
58191               }));
58192             }
58193
58194             context.container().classed('lasso', false);
58195           };
58196
58197           return lasso;
58198         }
58199
58200         function behaviorLasso(context) {
58201           // use pointer events on supported platforms; fallback to mouse events
58202           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
58203
58204           var behavior = function behavior(selection) {
58205             var lasso;
58206
58207             function pointerdown(d3_event) {
58208               var button = 0; // left
58209
58210               if (d3_event.button === button && d3_event.shiftKey === true) {
58211                 lasso = null;
58212                 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
58213                 d3_event.stopPropagation();
58214               }
58215             }
58216
58217             function pointermove() {
58218               if (!lasso) {
58219                 lasso = uiLasso(context);
58220                 context.surface().call(lasso);
58221               }
58222
58223               lasso.p(context.map().mouse());
58224             }
58225
58226             function normalize(a, b) {
58227               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])]];
58228             }
58229
58230             function lassoed() {
58231               if (!lasso) return [];
58232               var graph = context.graph();
58233               var limitToNodes;
58234
58235               if (context.map().editableDataEnabled(true
58236               /* skipZoomCheck */
58237               ) && context.map().isInWideSelection()) {
58238                 // only select from the visible nodes
58239                 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
58240               } else if (!context.map().editableDataEnabled()) {
58241                 return [];
58242               }
58243
58244               var bounds = lasso.extent().map(context.projection.invert);
58245               var extent = geoExtent(normalize(bounds[0], bounds[1]));
58246               var intersects = context.history().intersects(extent).filter(function (entity) {
58247                 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
58248               }); // sort the lassoed nodes as best we can
58249
58250               intersects.sort(function (node1, node2) {
58251                 var parents1 = graph.parentWays(node1);
58252                 var parents2 = graph.parentWays(node2);
58253
58254                 if (parents1.length && parents2.length) {
58255                   // both nodes are vertices
58256                   var sharedParents = utilArrayIntersection(parents1, parents2);
58257
58258                   if (sharedParents.length) {
58259                     var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
58260
58261                     return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
58262                   } else {
58263                     // vertices do not share a way; group them by their respective parent ways
58264                     return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
58265                   }
58266                 } else if (parents1.length || parents2.length) {
58267                   // only one node is a vertex; sort standalone points before vertices
58268                   return parents1.length - parents2.length;
58269                 } // both nodes are standalone points; sort left to right
58270
58271
58272                 return node1.loc[0] - node2.loc[0];
58273               });
58274               return intersects.map(function (entity) {
58275                 return entity.id;
58276               });
58277             }
58278
58279             function pointerup() {
58280               select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
58281               if (!lasso) return;
58282               var ids = lassoed();
58283               lasso.close();
58284
58285               if (ids.length) {
58286                 context.enter(modeSelect(context, ids));
58287               }
58288             }
58289
58290             selection.on(_pointerPrefix + 'down.lasso', pointerdown);
58291           };
58292
58293           behavior.off = function (selection) {
58294             selection.on(_pointerPrefix + 'down.lasso', null);
58295           };
58296
58297           return behavior;
58298         }
58299
58300         function modeBrowse(context) {
58301           var mode = {
58302             button: 'browse',
58303             id: 'browse',
58304             title: _t('modes.browse.title'),
58305             description: _t('modes.browse.description')
58306           };
58307           var sidebar;
58308
58309           var _selectBehavior;
58310
58311           var _behaviors = [];
58312
58313           mode.selectBehavior = function (val) {
58314             if (!arguments.length) return _selectBehavior;
58315             _selectBehavior = val;
58316             return mode;
58317           };
58318
58319           mode.enter = function () {
58320             if (!_behaviors.length) {
58321               if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
58322               _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
58323             }
58324
58325             _behaviors.forEach(context.install); // Get focus on the body.
58326
58327
58328             if (document.activeElement && document.activeElement.blur) {
58329               document.activeElement.blur();
58330             }
58331
58332             if (sidebar) {
58333               context.ui().sidebar.show(sidebar);
58334             } else {
58335               context.ui().sidebar.select(null);
58336             }
58337           };
58338
58339           mode.exit = function () {
58340             context.ui().sidebar.hover.cancel();
58341
58342             _behaviors.forEach(context.uninstall);
58343
58344             if (sidebar) {
58345               context.ui().sidebar.hide();
58346             }
58347           };
58348
58349           mode.sidebar = function (_) {
58350             if (!arguments.length) return sidebar;
58351             sidebar = _;
58352             return mode;
58353           };
58354
58355           mode.operations = function () {
58356             return [operationPaste(context)];
58357           };
58358
58359           return mode;
58360         }
58361
58362         function behaviorAddWay(context) {
58363           var dispatch$1 = dispatch('start', 'startFromWay', 'startFromNode');
58364           var draw = behaviorDraw(context);
58365
58366           function behavior(surface) {
58367             draw.on('click', function () {
58368               dispatch$1.apply('start', this, arguments);
58369             }).on('clickWay', function () {
58370               dispatch$1.apply('startFromWay', this, arguments);
58371             }).on('clickNode', function () {
58372               dispatch$1.apply('startFromNode', this, arguments);
58373             }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
58374             context.map().dblclickZoomEnable(false);
58375             surface.call(draw);
58376           }
58377
58378           behavior.off = function (surface) {
58379             surface.call(draw.off);
58380           };
58381
58382           behavior.cancel = function () {
58383             window.setTimeout(function () {
58384               context.map().dblclickZoomEnable(true);
58385             }, 1000);
58386             context.enter(modeBrowse(context));
58387           };
58388
58389           return utilRebind(behavior, dispatch$1, 'on');
58390         }
58391
58392         function behaviorHash(context) {
58393           // cached window.location.hash
58394           var _cachedHash = null; // allowable latitude range
58395
58396           var _latitudeLimit = 90 - 1e-8;
58397
58398           function computedHashParameters() {
58399             var map = context.map();
58400             var center = map.center();
58401             var zoom = map.zoom();
58402             var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
58403             var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
58404             var newParams = {};
58405             delete oldParams.id;
58406             var selected = context.selectedIDs().filter(function (id) {
58407               return context.hasEntity(id);
58408             });
58409
58410             if (selected.length) {
58411               newParams.id = selected.join(',');
58412             }
58413
58414             newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
58415             return Object.assign(oldParams, newParams);
58416           }
58417
58418           function computedHash() {
58419             return '#' + utilQsString(computedHashParameters(), true);
58420           }
58421
58422           function computedTitle(includeChangeCount) {
58423             var baseTitle = context.documentTitleBase() || 'iD';
58424             var contextual;
58425             var changeCount;
58426             var titleID;
58427             var selected = context.selectedIDs().filter(function (id) {
58428               return context.hasEntity(id);
58429             });
58430
58431             if (selected.length) {
58432               var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
58433
58434               if (selected.length > 1) {
58435                 contextual = _t('title.labeled_and_more', {
58436                   labeled: firstLabel,
58437                   count: selected.length - 1
58438                 });
58439               } else {
58440                 contextual = firstLabel;
58441               }
58442
58443               titleID = 'context';
58444             }
58445
58446             if (includeChangeCount) {
58447               changeCount = context.history().difference().summary().length;
58448
58449               if (changeCount > 0) {
58450                 titleID = contextual ? 'changes_context' : 'changes';
58451               }
58452             }
58453
58454             if (titleID) {
58455               return _t('title.format.' + titleID, {
58456                 changes: changeCount,
58457                 base: baseTitle,
58458                 context: contextual
58459               });
58460             }
58461
58462             return baseTitle;
58463           }
58464
58465           function updateTitle(includeChangeCount) {
58466             if (!context.setsDocumentTitle()) return;
58467             var newTitle = computedTitle(includeChangeCount);
58468
58469             if (document.title !== newTitle) {
58470               document.title = newTitle;
58471             }
58472           }
58473
58474           function updateHashIfNeeded() {
58475             if (context.inIntro()) return;
58476             var latestHash = computedHash();
58477
58478             if (_cachedHash !== latestHash) {
58479               _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
58480               // though unavoidably creating a browser history entry
58481
58482               window.history.replaceState(null, computedTitle(false
58483               /* includeChangeCount */
58484               ), latestHash); // set the title we want displayed for the browser tab/window
58485
58486               updateTitle(true
58487               /* includeChangeCount */
58488               );
58489             }
58490           }
58491
58492           var _throttledUpdate = throttle(updateHashIfNeeded, 500);
58493
58494           var _throttledUpdateTitle = throttle(function () {
58495             updateTitle(true
58496             /* includeChangeCount */
58497             );
58498           }, 500);
58499
58500           function hashchange() {
58501             // ignore spurious hashchange events
58502             if (window.location.hash === _cachedHash) return;
58503             _cachedHash = window.location.hash;
58504             var q = utilStringQs(_cachedHash);
58505             var mapArgs = (q.map || '').split('/').map(Number);
58506
58507             if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
58508               // replace bogus hash
58509               updateHashIfNeeded();
58510             } else {
58511               // don't update if the new hash already reflects the state of iD
58512               if (_cachedHash === computedHash()) return;
58513               var mode = context.mode();
58514               context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
58515
58516               if (q.id && mode) {
58517                 var ids = q.id.split(',').filter(function (id) {
58518                   return context.hasEntity(id);
58519                 });
58520
58521                 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
58522                   context.enter(modeSelect(context, ids));
58523                   return;
58524                 }
58525               }
58526
58527               var center = context.map().center();
58528               var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
58529               var maxdist = 500; // Don't allow the hash location to change too much while drawing
58530               // This can happen if the user accidentally hit the back button.  #3996
58531
58532               if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
58533                 context.enter(modeBrowse(context));
58534                 return;
58535               }
58536             }
58537           }
58538
58539           function behavior() {
58540             context.map().on('move.behaviorHash', _throttledUpdate);
58541             context.history().on('change.behaviorHash', _throttledUpdateTitle);
58542             context.on('enter.behaviorHash', _throttledUpdate);
58543             select(window).on('hashchange.behaviorHash', hashchange);
58544
58545             if (window.location.hash) {
58546               var q = utilStringQs(window.location.hash);
58547
58548               if (q.id) {
58549                 //if (!context.history().hasRestorableChanges()) {
58550                 // targeting specific features: download, select, and zoom to them
58551                 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
58552               }
58553
58554               if (q.walkthrough === 'true') {
58555                 behavior.startWalkthrough = true;
58556               }
58557
58558               if (q.map) {
58559                 behavior.hadHash = true;
58560               }
58561
58562               hashchange();
58563               updateTitle(false);
58564             }
58565           }
58566
58567           behavior.off = function () {
58568             _throttledUpdate.cancel();
58569
58570             _throttledUpdateTitle.cancel();
58571
58572             context.map().on('move.behaviorHash', null);
58573             context.on('enter.behaviorHash', null);
58574             select(window).on('hashchange.behaviorHash', null);
58575             window.location.hash = '';
58576           };
58577
58578           return behavior;
58579         }
58580
58581         /*
58582             iD.coreDifference represents the difference between two graphs.
58583             It knows how to calculate the set of entities that were
58584             created, modified, or deleted, and also contains the logic
58585             for recursively extending a difference to the complete set
58586             of entities that will require a redraw, taking into account
58587             child and parent relationships.
58588          */
58589
58590         function coreDifference(base, head) {
58591           var _changes = {};
58592           var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
58593
58594           var _diff = {};
58595
58596           function checkEntityID(id) {
58597             var h = head.entities[id];
58598             var b = base.entities[id];
58599             if (h === b) return;
58600             if (_changes[id]) return;
58601
58602             if (!h && b) {
58603               _changes[id] = {
58604                 base: b,
58605                 head: h
58606               };
58607               _didChange.deletion = true;
58608               return;
58609             }
58610
58611             if (h && !b) {
58612               _changes[id] = {
58613                 base: b,
58614                 head: h
58615               };
58616               _didChange.addition = true;
58617               return;
58618             }
58619
58620             if (h && b) {
58621               if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
58622                 _changes[id] = {
58623                   base: b,
58624                   head: h
58625                 };
58626                 _didChange.geometry = true;
58627                 _didChange.properties = true;
58628                 return;
58629               }
58630
58631               if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
58632                 _changes[id] = {
58633                   base: b,
58634                   head: h
58635                 };
58636                 _didChange.geometry = true;
58637               }
58638
58639               if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
58640                 _changes[id] = {
58641                   base: b,
58642                   head: h
58643                 };
58644                 _didChange.geometry = true;
58645               }
58646
58647               if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
58648                 _changes[id] = {
58649                   base: b,
58650                   head: h
58651                 };
58652                 _didChange.properties = true;
58653               }
58654             }
58655           }
58656
58657           function load() {
58658             // HOT CODE: there can be many thousands of downloaded entities, so looping
58659             // through them all can become a performance bottleneck. Optimize by
58660             // resolving duplicates and using a basic `for` loop
58661             var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
58662
58663             for (var i = 0; i < ids.length; i++) {
58664               checkEntityID(ids[i]);
58665             }
58666           }
58667
58668           load();
58669
58670           _diff.length = function length() {
58671             return Object.keys(_changes).length;
58672           };
58673
58674           _diff.changes = function changes() {
58675             return _changes;
58676           };
58677
58678           _diff.didChange = _didChange; // pass true to include affected relation members
58679
58680           _diff.extantIDs = function extantIDs(includeRelMembers) {
58681             var result = new Set();
58682             Object.keys(_changes).forEach(function (id) {
58683               if (_changes[id].head) {
58684                 result.add(id);
58685               }
58686
58687               var h = _changes[id].head;
58688               var b = _changes[id].base;
58689               var entity = h || b;
58690
58691               if (includeRelMembers && entity.type === 'relation') {
58692                 var mh = h ? h.members.map(function (m) {
58693                   return m.id;
58694                 }) : [];
58695                 var mb = b ? b.members.map(function (m) {
58696                   return m.id;
58697                 }) : [];
58698                 utilArrayUnion(mh, mb).forEach(function (memberID) {
58699                   if (head.hasEntity(memberID)) {
58700                     result.add(memberID);
58701                   }
58702                 });
58703               }
58704             });
58705             return Array.from(result);
58706           };
58707
58708           _diff.modified = function modified() {
58709             var result = [];
58710             Object.values(_changes).forEach(function (change) {
58711               if (change.base && change.head) {
58712                 result.push(change.head);
58713               }
58714             });
58715             return result;
58716           };
58717
58718           _diff.created = function created() {
58719             var result = [];
58720             Object.values(_changes).forEach(function (change) {
58721               if (!change.base && change.head) {
58722                 result.push(change.head);
58723               }
58724             });
58725             return result;
58726           };
58727
58728           _diff.deleted = function deleted() {
58729             var result = [];
58730             Object.values(_changes).forEach(function (change) {
58731               if (change.base && !change.head) {
58732                 result.push(change.base);
58733               }
58734             });
58735             return result;
58736           };
58737
58738           _diff.summary = function summary() {
58739             var relevant = {};
58740             var keys = Object.keys(_changes);
58741
58742             for (var i = 0; i < keys.length; i++) {
58743               var change = _changes[keys[i]];
58744
58745               if (change.head && change.head.geometry(head) !== 'vertex') {
58746                 addEntity(change.head, head, change.base ? 'modified' : 'created');
58747               } else if (change.base && change.base.geometry(base) !== 'vertex') {
58748                 addEntity(change.base, base, 'deleted');
58749               } else if (change.base && change.head) {
58750                 // modified vertex
58751                 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
58752                 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
58753
58754                 if (moved) {
58755                   addParents(change.head);
58756                 }
58757
58758                 if (retagged || moved && change.head.hasInterestingTags()) {
58759                   addEntity(change.head, head, 'modified');
58760                 }
58761               } else if (change.head && change.head.hasInterestingTags()) {
58762                 // created vertex
58763                 addEntity(change.head, head, 'created');
58764               } else if (change.base && change.base.hasInterestingTags()) {
58765                 // deleted vertex
58766                 addEntity(change.base, base, 'deleted');
58767               }
58768             }
58769
58770             return Object.values(relevant);
58771
58772             function addEntity(entity, graph, changeType) {
58773               relevant[entity.id] = {
58774                 entity: entity,
58775                 graph: graph,
58776                 changeType: changeType
58777               };
58778             }
58779
58780             function addParents(entity) {
58781               var parents = head.parentWays(entity);
58782
58783               for (var j = parents.length - 1; j >= 0; j--) {
58784                 var parent = parents[j];
58785
58786                 if (!(parent.id in relevant)) {
58787                   addEntity(parent, head, 'modified');
58788                 }
58789               }
58790             }
58791           }; // returns complete set of entities that require a redraw
58792           //  (optionally within given `extent`)
58793
58794
58795           _diff.complete = function complete(extent) {
58796             var result = {};
58797             var id, change;
58798
58799             for (id in _changes) {
58800               change = _changes[id];
58801               var h = change.head;
58802               var b = change.base;
58803               var entity = h || b;
58804               var i;
58805               if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) continue;
58806               result[id] = h;
58807
58808               if (entity.type === 'way') {
58809                 var nh = h ? h.nodes : [];
58810                 var nb = b ? b.nodes : [];
58811                 var diff;
58812                 diff = utilArrayDifference(nh, nb);
58813
58814                 for (i = 0; i < diff.length; i++) {
58815                   result[diff[i]] = head.hasEntity(diff[i]);
58816                 }
58817
58818                 diff = utilArrayDifference(nb, nh);
58819
58820                 for (i = 0; i < diff.length; i++) {
58821                   result[diff[i]] = head.hasEntity(diff[i]);
58822                 }
58823               }
58824
58825               if (entity.type === 'relation' && entity.isMultipolygon()) {
58826                 var mh = h ? h.members.map(function (m) {
58827                   return m.id;
58828                 }) : [];
58829                 var mb = b ? b.members.map(function (m) {
58830                   return m.id;
58831                 }) : [];
58832                 var ids = utilArrayUnion(mh, mb);
58833
58834                 for (i = 0; i < ids.length; i++) {
58835                   var member = head.hasEntity(ids[i]);
58836                   if (!member) continue; // not downloaded
58837
58838                   if (extent && !member.intersects(extent, head)) continue; // not visible
58839
58840                   result[ids[i]] = member;
58841                 }
58842               }
58843
58844               addParents(head.parentWays(entity), result);
58845               addParents(head.parentRelations(entity), result);
58846             }
58847
58848             return result;
58849
58850             function addParents(parents, result) {
58851               for (var i = 0; i < parents.length; i++) {
58852                 var parent = parents[i];
58853                 if (parent.id in result) continue;
58854                 result[parent.id] = parent;
58855                 addParents(head.parentRelations(parent), result);
58856               }
58857             }
58858           };
58859
58860           return _diff;
58861         }
58862
58863         function coreTree(head) {
58864           // tree for entities
58865           var _rtree = new RBush();
58866
58867           var _bboxes = {}; // maintain a separate tree for granular way segments
58868
58869           var _segmentsRTree = new RBush();
58870
58871           var _segmentsBBoxes = {};
58872           var _segmentsByWayId = {};
58873           var tree = {};
58874
58875           function entityBBox(entity) {
58876             var bbox = entity.extent(head).bbox();
58877             bbox.id = entity.id;
58878             _bboxes[entity.id] = bbox;
58879             return bbox;
58880           }
58881
58882           function segmentBBox(segment) {
58883             var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
58884
58885             if (!extent) return null;
58886             var bbox = extent.bbox();
58887             bbox.segment = segment;
58888             _segmentsBBoxes[segment.id] = bbox;
58889             return bbox;
58890           }
58891
58892           function removeEntity(entity) {
58893             _rtree.remove(_bboxes[entity.id]);
58894
58895             delete _bboxes[entity.id];
58896
58897             if (_segmentsByWayId[entity.id]) {
58898               _segmentsByWayId[entity.id].forEach(function (segment) {
58899                 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
58900
58901                 delete _segmentsBBoxes[segment.id];
58902               });
58903
58904               delete _segmentsByWayId[entity.id];
58905             }
58906           }
58907
58908           function loadEntities(entities) {
58909             _rtree.load(entities.map(entityBBox));
58910
58911             var segments = [];
58912             entities.forEach(function (entity) {
58913               if (entity.segments) {
58914                 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
58915
58916                 _segmentsByWayId[entity.id] = entitySegments;
58917                 segments = segments.concat(entitySegments);
58918               }
58919             });
58920             if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
58921           }
58922
58923           function updateParents(entity, insertions, memo) {
58924             head.parentWays(entity).forEach(function (way) {
58925               if (_bboxes[way.id]) {
58926                 removeEntity(way);
58927                 insertions[way.id] = way;
58928               }
58929
58930               updateParents(way, insertions, memo);
58931             });
58932             head.parentRelations(entity).forEach(function (relation) {
58933               if (memo[entity.id]) return;
58934               memo[entity.id] = true;
58935
58936               if (_bboxes[relation.id]) {
58937                 removeEntity(relation);
58938                 insertions[relation.id] = relation;
58939               }
58940
58941               updateParents(relation, insertions, memo);
58942             });
58943           }
58944
58945           tree.rebase = function (entities, force) {
58946             var insertions = {};
58947
58948             for (var i = 0; i < entities.length; i++) {
58949               var entity = entities[i];
58950               if (!entity.visible) continue;
58951
58952               if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
58953                 if (!force) {
58954                   continue;
58955                 } else if (_bboxes[entity.id]) {
58956                   removeEntity(entity);
58957                 }
58958               }
58959
58960               insertions[entity.id] = entity;
58961               updateParents(entity, insertions, {});
58962             }
58963
58964             loadEntities(Object.values(insertions));
58965             return tree;
58966           };
58967
58968           function updateToGraph(graph) {
58969             if (graph === head) return;
58970             var diff = coreDifference(head, graph);
58971             head = graph;
58972             var changed = diff.didChange;
58973             if (!changed.addition && !changed.deletion && !changed.geometry) return;
58974             var insertions = {};
58975
58976             if (changed.deletion) {
58977               diff.deleted().forEach(function (entity) {
58978                 removeEntity(entity);
58979               });
58980             }
58981
58982             if (changed.geometry) {
58983               diff.modified().forEach(function (entity) {
58984                 removeEntity(entity);
58985                 insertions[entity.id] = entity;
58986                 updateParents(entity, insertions, {});
58987               });
58988             }
58989
58990             if (changed.addition) {
58991               diff.created().forEach(function (entity) {
58992                 insertions[entity.id] = entity;
58993               });
58994             }
58995
58996             loadEntities(Object.values(insertions));
58997           } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
58998
58999
59000           tree.intersects = function (extent, graph) {
59001             updateToGraph(graph);
59002             return _rtree.search(extent.bbox()).map(function (bbox) {
59003               return graph.entity(bbox.id);
59004             });
59005           }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
59006
59007
59008           tree.waySegments = function (extent, graph) {
59009             updateToGraph(graph);
59010             return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
59011               return bbox.segment;
59012             });
59013           };
59014
59015           return tree;
59016         }
59017
59018         function uiModal(selection, blocking) {
59019           var _this = this;
59020
59021           var keybinding = utilKeybinding('modal');
59022           var previous = selection.select('div.modal');
59023           var animate = previous.empty();
59024           previous.transition().duration(200).style('opacity', 0).remove();
59025           var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
59026
59027           shaded.close = function () {
59028             shaded.transition().duration(200).style('opacity', 0).remove();
59029             modal.transition().duration(200).style('top', '0px');
59030             select(document).call(keybinding.unbind);
59031           };
59032
59033           var modal = shaded.append('div').attr('class', 'modal fillL');
59034           modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
59035
59036           if (!blocking) {
59037             shaded.on('click.remove-modal', function (d3_event) {
59038               if (d3_event.target === _this) {
59039                 shaded.close();
59040               }
59041             });
59042             modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
59043             keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
59044             select(document).call(keybinding);
59045           }
59046
59047           modal.append('div').attr('class', 'content');
59048           modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
59049
59050           if (animate) {
59051             shaded.transition().style('opacity', 1);
59052           } else {
59053             shaded.style('opacity', 1);
59054           }
59055
59056           return shaded;
59057
59058           function moveFocusToFirst() {
59059             var node = modal // there are additional rules about what's focusable, but this suits our purposes
59060             .select('a, button, input:not(.keytrap), select, textarea').node();
59061
59062             if (node) {
59063               node.focus();
59064             } else {
59065               select(this).node().blur();
59066             }
59067           }
59068
59069           function moveFocusToLast() {
59070             var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
59071
59072             if (nodes.length) {
59073               nodes[nodes.length - 1].focus();
59074             } else {
59075               select(this).node().blur();
59076             }
59077           }
59078         }
59079
59080         function uiLoading(context) {
59081           var _modalSelection = select(null);
59082
59083           var _message = '';
59084           var _blocking = false;
59085
59086           var loading = function loading(selection) {
59087             _modalSelection = uiModal(selection, _blocking);
59088
59089             var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
59090
59091             loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
59092             loadertext.append('h3').html(_message);
59093
59094             _modalSelection.select('button.close').attr('class', 'hide');
59095
59096             return loading;
59097           };
59098
59099           loading.message = function (val) {
59100             if (!arguments.length) return _message;
59101             _message = val;
59102             return loading;
59103           };
59104
59105           loading.blocking = function (val) {
59106             if (!arguments.length) return _blocking;
59107             _blocking = val;
59108             return loading;
59109           };
59110
59111           loading.close = function () {
59112             _modalSelection.remove();
59113           };
59114
59115           loading.isShown = function () {
59116             return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
59117           };
59118
59119           return loading;
59120         }
59121
59122         function coreHistory(context) {
59123           var dispatch$1 = dispatch('reset', 'change', 'merge', 'restore', 'undone', 'redone');
59124
59125           var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
59126
59127
59128           var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
59129
59130           var duration = 150;
59131           var _imageryUsed = [];
59132           var _photoOverlaysUsed = [];
59133           var _checkpoints = {};
59134
59135           var _pausedGraph;
59136
59137           var _stack;
59138
59139           var _index;
59140
59141           var _tree; // internal _act, accepts list of actions and eased time
59142
59143
59144           function _act(actions, t) {
59145             actions = Array.prototype.slice.call(actions);
59146             var annotation;
59147
59148             if (typeof actions[actions.length - 1] !== 'function') {
59149               annotation = actions.pop();
59150             }
59151
59152             var graph = _stack[_index].graph;
59153
59154             for (var i = 0; i < actions.length; i++) {
59155               graph = actions[i](graph, t);
59156             }
59157
59158             return {
59159               graph: graph,
59160               annotation: annotation,
59161               imageryUsed: _imageryUsed,
59162               photoOverlaysUsed: _photoOverlaysUsed,
59163               transform: context.projection.transform(),
59164               selectedIDs: context.selectedIDs()
59165             };
59166           } // internal _perform with eased time
59167
59168
59169           function _perform(args, t) {
59170             var previous = _stack[_index].graph;
59171             _stack = _stack.slice(0, _index + 1);
59172
59173             var actionResult = _act(args, t);
59174
59175             _stack.push(actionResult);
59176
59177             _index++;
59178             return change(previous);
59179           } // internal _replace with eased time
59180
59181
59182           function _replace(args, t) {
59183             var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
59184
59185             var actionResult = _act(args, t);
59186
59187             _stack[_index] = actionResult;
59188             return change(previous);
59189           } // internal _overwrite with eased time
59190
59191
59192           function _overwrite(args, t) {
59193             var previous = _stack[_index].graph;
59194
59195             if (_index > 0) {
59196               _index--;
59197
59198               _stack.pop();
59199             }
59200
59201             _stack = _stack.slice(0, _index + 1);
59202
59203             var actionResult = _act(args, t);
59204
59205             _stack.push(actionResult);
59206
59207             _index++;
59208             return change(previous);
59209           } // determine difference and dispatch a change event
59210
59211
59212           function change(previous) {
59213             var difference = coreDifference(previous, history.graph());
59214
59215             if (!_pausedGraph) {
59216               dispatch$1.call('change', this, difference);
59217             }
59218
59219             return difference;
59220           } // iD uses namespaced keys so multiple installations do not conflict
59221
59222
59223           function getKey(n) {
59224             return 'iD_' + window.location.origin + '_' + n;
59225           }
59226
59227           var history = {
59228             graph: function graph() {
59229               return _stack[_index].graph;
59230             },
59231             tree: function tree() {
59232               return _tree;
59233             },
59234             base: function base() {
59235               return _stack[0].graph;
59236             },
59237             merge: function merge(entities
59238             /*, extent*/
59239             ) {
59240               var stack = _stack.map(function (state) {
59241                 return state.graph;
59242               });
59243
59244               _stack[0].graph.rebase(entities, stack, false);
59245
59246               _tree.rebase(entities, false);
59247
59248               dispatch$1.call('merge', this, entities);
59249             },
59250             perform: function perform() {
59251               // complete any transition already in progress
59252               select(document).interrupt('history.perform');
59253               var transitionable = false;
59254               var action0 = arguments[0];
59255
59256               if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
59257                 transitionable = !!action0.transitionable;
59258               }
59259
59260               if (transitionable) {
59261                 var origArguments = arguments;
59262                 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
59263                   return function (t) {
59264                     if (t < 1) _overwrite([action0], t);
59265                   };
59266                 }).on('start', function () {
59267                   _perform([action0], 0);
59268                 }).on('end interrupt', function () {
59269                   _overwrite(origArguments, 1);
59270                 });
59271               } else {
59272                 return _perform(arguments);
59273               }
59274             },
59275             replace: function replace() {
59276               select(document).interrupt('history.perform');
59277               return _replace(arguments, 1);
59278             },
59279             // Same as calling pop and then perform
59280             overwrite: function overwrite() {
59281               select(document).interrupt('history.perform');
59282               return _overwrite(arguments, 1);
59283             },
59284             pop: function pop(n) {
59285               select(document).interrupt('history.perform');
59286               var previous = _stack[_index].graph;
59287
59288               if (isNaN(+n) || +n < 0) {
59289                 n = 1;
59290               }
59291
59292               while (n-- > 0 && _index > 0) {
59293                 _index--;
59294
59295                 _stack.pop();
59296               }
59297
59298               return change(previous);
59299             },
59300             // Back to the previous annotated state or _index = 0.
59301             undo: function undo() {
59302               select(document).interrupt('history.perform');
59303               var previousStack = _stack[_index];
59304               var previous = previousStack.graph;
59305
59306               while (_index > 0) {
59307                 _index--;
59308                 if (_stack[_index].annotation) break;
59309               }
59310
59311               dispatch$1.call('undone', this, _stack[_index], previousStack);
59312               return change(previous);
59313             },
59314             // Forward to the next annotated state.
59315             redo: function redo() {
59316               select(document).interrupt('history.perform');
59317               var previousStack = _stack[_index];
59318               var previous = previousStack.graph;
59319               var tryIndex = _index;
59320
59321               while (tryIndex < _stack.length - 1) {
59322                 tryIndex++;
59323
59324                 if (_stack[tryIndex].annotation) {
59325                   _index = tryIndex;
59326                   dispatch$1.call('redone', this, _stack[_index], previousStack);
59327                   break;
59328                 }
59329               }
59330
59331               return change(previous);
59332             },
59333             pauseChangeDispatch: function pauseChangeDispatch() {
59334               if (!_pausedGraph) {
59335                 _pausedGraph = _stack[_index].graph;
59336               }
59337             },
59338             resumeChangeDispatch: function resumeChangeDispatch() {
59339               if (_pausedGraph) {
59340                 var previous = _pausedGraph;
59341                 _pausedGraph = null;
59342                 return change(previous);
59343               }
59344             },
59345             undoAnnotation: function undoAnnotation() {
59346               var i = _index;
59347
59348               while (i >= 0) {
59349                 if (_stack[i].annotation) return _stack[i].annotation;
59350                 i--;
59351               }
59352             },
59353             redoAnnotation: function redoAnnotation() {
59354               var i = _index + 1;
59355
59356               while (i <= _stack.length - 1) {
59357                 if (_stack[i].annotation) return _stack[i].annotation;
59358                 i++;
59359               }
59360             },
59361             // Returns the entities from the active graph with bounding boxes
59362             // overlapping the given `extent`.
59363             intersects: function intersects(extent) {
59364               return _tree.intersects(extent, _stack[_index].graph);
59365             },
59366             difference: function difference() {
59367               var base = _stack[0].graph;
59368               var head = _stack[_index].graph;
59369               return coreDifference(base, head);
59370             },
59371             changes: function changes(action) {
59372               var base = _stack[0].graph;
59373               var head = _stack[_index].graph;
59374
59375               if (action) {
59376                 head = action(head);
59377               }
59378
59379               var difference = coreDifference(base, head);
59380               return {
59381                 modified: difference.modified(),
59382                 created: difference.created(),
59383                 deleted: difference.deleted()
59384               };
59385             },
59386             hasChanges: function hasChanges() {
59387               return this.difference().length() > 0;
59388             },
59389             imageryUsed: function imageryUsed(sources) {
59390               if (sources) {
59391                 _imageryUsed = sources;
59392                 return history;
59393               } else {
59394                 var s = new Set();
59395
59396                 _stack.slice(1, _index + 1).forEach(function (state) {
59397                   state.imageryUsed.forEach(function (source) {
59398                     if (source !== 'Custom') {
59399                       s.add(source);
59400                     }
59401                   });
59402                 });
59403
59404                 return Array.from(s);
59405               }
59406             },
59407             photoOverlaysUsed: function photoOverlaysUsed(sources) {
59408               if (sources) {
59409                 _photoOverlaysUsed = sources;
59410                 return history;
59411               } else {
59412                 var s = new Set();
59413
59414                 _stack.slice(1, _index + 1).forEach(function (state) {
59415                   if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
59416                     state.photoOverlaysUsed.forEach(function (photoOverlay) {
59417                       s.add(photoOverlay);
59418                     });
59419                   }
59420                 });
59421
59422                 return Array.from(s);
59423               }
59424             },
59425             // save the current history state
59426             checkpoint: function checkpoint(key) {
59427               _checkpoints[key] = {
59428                 stack: _stack,
59429                 index: _index
59430               };
59431               return history;
59432             },
59433             // restore history state to a given checkpoint or reset completely
59434             reset: function reset(key) {
59435               if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
59436                 _stack = _checkpoints[key].stack;
59437                 _index = _checkpoints[key].index;
59438               } else {
59439                 _stack = [{
59440                   graph: coreGraph()
59441                 }];
59442                 _index = 0;
59443                 _tree = coreTree(_stack[0].graph);
59444                 _checkpoints = {};
59445               }
59446
59447               dispatch$1.call('reset');
59448               dispatch$1.call('change');
59449               return history;
59450             },
59451             // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
59452             //
59453             // To use it:
59454             //  1. Start the walkthrough.
59455             //  2. Get to a "free editing" tutorial step
59456             //  3. Make your edits to the walkthrough map
59457             //  4. In your browser dev console run:
59458             //        `id.history().toIntroGraph()`
59459             //  5. This outputs stringified JSON to the browser console
59460             //  6. Copy it to `data/intro_graph.json` and prettify it in your code editor
59461             toIntroGraph: function toIntroGraph() {
59462               var nextID = {
59463                 n: 0,
59464                 r: 0,
59465                 w: 0
59466               };
59467               var permIDs = {};
59468               var graph = this.graph();
59469               var baseEntities = {}; // clone base entities..
59470
59471               Object.values(graph.base().entities).forEach(function (entity) {
59472                 var copy = copyIntroEntity(entity);
59473                 baseEntities[copy.id] = copy;
59474               }); // replace base entities with head entities..
59475
59476               Object.keys(graph.entities).forEach(function (id) {
59477                 var entity = graph.entities[id];
59478
59479                 if (entity) {
59480                   var copy = copyIntroEntity(entity);
59481                   baseEntities[copy.id] = copy;
59482                 } else {
59483                   delete baseEntities[id];
59484                 }
59485               }); // swap temporary for permanent ids..
59486
59487               Object.values(baseEntities).forEach(function (entity) {
59488                 if (Array.isArray(entity.nodes)) {
59489                   entity.nodes = entity.nodes.map(function (node) {
59490                     return permIDs[node] || node;
59491                   });
59492                 }
59493
59494                 if (Array.isArray(entity.members)) {
59495                   entity.members = entity.members.map(function (member) {
59496                     member.id = permIDs[member.id] || member.id;
59497                     return member;
59498                   });
59499                 }
59500               });
59501               return JSON.stringify({
59502                 dataIntroGraph: baseEntities
59503               });
59504
59505               function copyIntroEntity(source) {
59506                 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
59507
59508                 if (copy.tags && !Object.keys(copy.tags)) {
59509                   delete copy.tags;
59510                 }
59511
59512                 if (Array.isArray(copy.loc)) {
59513                   copy.loc[0] = +copy.loc[0].toFixed(6);
59514                   copy.loc[1] = +copy.loc[1].toFixed(6);
59515                 }
59516
59517                 var match = source.id.match(/([nrw])-\d*/); // temporary id
59518
59519                 if (match !== null) {
59520                   var nrw = match[1];
59521                   var permID;
59522
59523                   do {
59524                     permID = nrw + ++nextID[nrw];
59525                   } while (baseEntities.hasOwnProperty(permID));
59526
59527                   copy.id = permIDs[source.id] = permID;
59528                 }
59529
59530                 return copy;
59531               }
59532             },
59533             toJSON: function toJSON() {
59534               if (!this.hasChanges()) return;
59535               var allEntities = {};
59536               var baseEntities = {};
59537               var base = _stack[0];
59538
59539               var s = _stack.map(function (i) {
59540                 var modified = [];
59541                 var deleted = [];
59542                 Object.keys(i.graph.entities).forEach(function (id) {
59543                   var entity = i.graph.entities[id];
59544
59545                   if (entity) {
59546                     var key = osmEntity.key(entity);
59547                     allEntities[key] = entity;
59548                     modified.push(key);
59549                   } else {
59550                     deleted.push(id);
59551                   } // make sure that the originals of changed or deleted entities get merged
59552                   // into the base of the _stack after restoring the data from JSON.
59553
59554
59555                   if (id in base.graph.entities) {
59556                     baseEntities[id] = base.graph.entities[id];
59557                   }
59558
59559                   if (entity && entity.nodes) {
59560                     // get originals of pre-existing child nodes
59561                     entity.nodes.forEach(function (nodeID) {
59562                       if (nodeID in base.graph.entities) {
59563                         baseEntities[nodeID] = base.graph.entities[nodeID];
59564                       }
59565                     });
59566                   } // get originals of parent entities too
59567
59568
59569                   var baseParents = base.graph._parentWays[id];
59570
59571                   if (baseParents) {
59572                     baseParents.forEach(function (parentID) {
59573                       if (parentID in base.graph.entities) {
59574                         baseEntities[parentID] = base.graph.entities[parentID];
59575                       }
59576                     });
59577                   }
59578                 });
59579                 var x = {};
59580                 if (modified.length) x.modified = modified;
59581                 if (deleted.length) x.deleted = deleted;
59582                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
59583                 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
59584                 if (i.annotation) x.annotation = i.annotation;
59585                 if (i.transform) x.transform = i.transform;
59586                 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
59587                 return x;
59588               });
59589
59590               return JSON.stringify({
59591                 version: 3,
59592                 entities: Object.values(allEntities),
59593                 baseEntities: Object.values(baseEntities),
59594                 stack: s,
59595                 nextIDs: osmEntity.id.next,
59596                 index: _index,
59597                 // note the time the changes were saved
59598                 timestamp: new Date().getTime()
59599               });
59600             },
59601             fromJSON: function fromJSON(json, loadChildNodes) {
59602               var h = JSON.parse(json);
59603               var loadComplete = true;
59604               osmEntity.id.next = h.nextIDs;
59605               _index = h.index;
59606
59607               if (h.version === 2 || h.version === 3) {
59608                 var allEntities = {};
59609                 h.entities.forEach(function (entity) {
59610                   allEntities[osmEntity.key(entity)] = osmEntity(entity);
59611                 });
59612
59613                 if (h.version === 3) {
59614                   // This merges originals for changed entities into the base of
59615                   // the _stack even if the current _stack doesn't have them (for
59616                   // example when iD has been restarted in a different region)
59617                   var baseEntities = h.baseEntities.map(function (d) {
59618                     return osmEntity(d);
59619                   });
59620
59621                   var stack = _stack.map(function (state) {
59622                     return state.graph;
59623                   });
59624
59625                   _stack[0].graph.rebase(baseEntities, stack, true);
59626
59627                   _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
59628                   // childnodes that would normally have been downloaded with it.. #2142
59629
59630
59631                   if (loadChildNodes) {
59632                     var osm = context.connection();
59633                     var baseWays = baseEntities.filter(function (e) {
59634                       return e.type === 'way';
59635                     });
59636                     var nodeIDs = baseWays.reduce(function (acc, way) {
59637                       return utilArrayUnion(acc, way.nodes);
59638                     }, []);
59639                     var missing = nodeIDs.filter(function (n) {
59640                       return !_stack[0].graph.hasEntity(n);
59641                     });
59642
59643                     if (missing.length && osm) {
59644                       loadComplete = false;
59645                       context.map().redrawEnable(false);
59646                       var loading = uiLoading(context).blocking(true);
59647                       context.container().call(loading);
59648
59649                       var childNodesLoaded = function childNodesLoaded(err, result) {
59650                         if (!err) {
59651                           var visibleGroups = utilArrayGroupBy(result.data, 'visible');
59652                           var visibles = visibleGroups["true"] || []; // alive nodes
59653
59654                           var invisibles = visibleGroups["false"] || []; // deleted nodes
59655
59656                           if (visibles.length) {
59657                             var visibleIDs = visibles.map(function (entity) {
59658                               return entity.id;
59659                             });
59660
59661                             var stack = _stack.map(function (state) {
59662                               return state.graph;
59663                             });
59664
59665                             missing = utilArrayDifference(missing, visibleIDs);
59666
59667                             _stack[0].graph.rebase(visibles, stack, true);
59668
59669                             _tree.rebase(visibles, true);
59670                           } // fetch older versions of nodes that were deleted..
59671
59672
59673                           invisibles.forEach(function (entity) {
59674                             osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
59675                           });
59676                         }
59677
59678                         if (err || !missing.length) {
59679                           loading.close();
59680                           context.map().redrawEnable(true);
59681                           dispatch$1.call('change');
59682                           dispatch$1.call('restore', this);
59683                         }
59684                       };
59685
59686                       osm.loadMultiple(missing, childNodesLoaded);
59687                     }
59688                   }
59689                 }
59690
59691                 _stack = h.stack.map(function (d) {
59692                   var entities = {},
59693                       entity;
59694
59695                   if (d.modified) {
59696                     d.modified.forEach(function (key) {
59697                       entity = allEntities[key];
59698                       entities[entity.id] = entity;
59699                     });
59700                   }
59701
59702                   if (d.deleted) {
59703                     d.deleted.forEach(function (id) {
59704                       entities[id] = undefined;
59705                     });
59706                   }
59707
59708                   return {
59709                     graph: coreGraph(_stack[0].graph).load(entities),
59710                     annotation: d.annotation,
59711                     imageryUsed: d.imageryUsed,
59712                     photoOverlaysUsed: d.photoOverlaysUsed,
59713                     transform: d.transform,
59714                     selectedIDs: d.selectedIDs
59715                   };
59716                 });
59717               } else {
59718                 // original version
59719                 _stack = h.stack.map(function (d) {
59720                   var entities = {};
59721
59722                   for (var i in d.entities) {
59723                     var entity = d.entities[i];
59724                     entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
59725                   }
59726
59727                   d.graph = coreGraph(_stack[0].graph).load(entities);
59728                   return d;
59729                 });
59730               }
59731
59732               var transform = _stack[_index].transform;
59733
59734               if (transform) {
59735                 context.map().transformEase(transform, 0); // 0 = immediate, no easing
59736               }
59737
59738               if (loadComplete) {
59739                 dispatch$1.call('change');
59740                 dispatch$1.call('restore', this);
59741               }
59742
59743               return history;
59744             },
59745             lock: function lock() {
59746               return _lock.lock();
59747             },
59748             unlock: function unlock() {
59749               _lock.unlock();
59750             },
59751             save: function save() {
59752               if (_lock.locked() && // don't overwrite existing, unresolved changes
59753               !_hasUnresolvedRestorableChanges) {
59754                 corePreferences(getKey('saved_history'), history.toJSON() || null);
59755               }
59756
59757               return history;
59758             },
59759             // delete the history version saved in localStorage
59760             clearSaved: function clearSaved() {
59761               context.debouncedSave.cancel();
59762
59763               if (_lock.locked()) {
59764                 _hasUnresolvedRestorableChanges = false;
59765                 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
59766
59767                 corePreferences('comment', null);
59768                 corePreferences('hashtags', null);
59769                 corePreferences('source', null);
59770               }
59771
59772               return history;
59773             },
59774             savedHistoryJSON: function savedHistoryJSON() {
59775               return corePreferences(getKey('saved_history'));
59776             },
59777             hasRestorableChanges: function hasRestorableChanges() {
59778               return _hasUnresolvedRestorableChanges;
59779             },
59780             // load history from a version stored in localStorage
59781             restore: function restore() {
59782               if (_lock.locked()) {
59783                 _hasUnresolvedRestorableChanges = false;
59784                 var json = this.savedHistoryJSON();
59785                 if (json) history.fromJSON(json, true);
59786               }
59787             },
59788             _getKey: getKey
59789           };
59790           history.reset();
59791           return utilRebind(history, dispatch$1, 'on');
59792         }
59793
59794         /**
59795          * Look for roads that can be connected to other roads with a short extension
59796          */
59797
59798         function validationAlmostJunction(context) {
59799           var type = 'almost_junction';
59800           var EXTEND_TH_METERS = 5;
59801           var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
59802
59803           var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
59804
59805           var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
59806
59807           function isHighway(entity) {
59808             return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
59809           }
59810
59811           function isTaggedAsNotContinuing(node) {
59812             return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
59813           }
59814
59815           var validation = function checkAlmostJunction(entity, graph) {
59816             if (!isHighway(entity)) return [];
59817             if (entity.isDegenerate()) return [];
59818             var tree = context.history().tree();
59819             var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
59820             var issues = [];
59821             extendableNodeInfos.forEach(function (extendableNodeInfo) {
59822               issues.push(new validationIssue({
59823                 type: type,
59824                 subtype: 'highway-highway',
59825                 severity: 'warning',
59826                 message: function message(context) {
59827                   var entity1 = context.hasEntity(this.entityIds[0]);
59828
59829                   if (this.entityIds[0] === this.entityIds[2]) {
59830                     return entity1 ? _t.html('issues.almost_junction.self.message', {
59831                       feature: utilDisplayLabel(entity1, context.graph())
59832                     }) : '';
59833                   } else {
59834                     var entity2 = context.hasEntity(this.entityIds[2]);
59835                     return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
59836                       feature: utilDisplayLabel(entity1, context.graph()),
59837                       feature2: utilDisplayLabel(entity2, context.graph())
59838                     }) : '';
59839                   }
59840                 },
59841                 reference: showReference,
59842                 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
59843                 loc: extendableNodeInfo.node.loc,
59844                 hash: JSON.stringify(extendableNodeInfo.node.loc),
59845                 data: {
59846                   midId: extendableNodeInfo.mid.id,
59847                   edge: extendableNodeInfo.edge,
59848                   cross_loc: extendableNodeInfo.cross_loc
59849                 },
59850                 dynamicFixes: makeFixes
59851               }));
59852             });
59853             return issues;
59854
59855             function makeFixes(context) {
59856               var fixes = [new validationIssueFix({
59857                 icon: 'iD-icon-abutment',
59858                 title: _t.html('issues.fix.connect_features.title'),
59859                 onClick: function onClick(context) {
59860                   var annotation = _t('issues.fix.connect_almost_junction.annotation');
59861
59862                   var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
59863                       endNodeId = _this$issue$entityIds[1],
59864                       crossWayId = _this$issue$entityIds[2];
59865
59866                   var midNode = context.entity(this.issue.data.midId);
59867                   var endNode = context.entity(endNodeId);
59868                   var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
59869
59870                   var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
59871
59872                   if (nearEndNodes.length > 0) {
59873                     var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
59874
59875                     if (collinear) {
59876                       context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
59877                       return;
59878                     }
59879                   }
59880
59881                   var targetEdge = this.issue.data.edge;
59882                   var crossLoc = this.issue.data.cross_loc;
59883                   var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
59884                   var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
59885
59886                   if (closestNodeInfo.distance < WELD_TH_METERS) {
59887                     context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
59888                   } else {
59889                     context.perform(actionAddMidpoint({
59890                       loc: crossLoc,
59891                       edge: targetEdge
59892                     }, endNode), annotation);
59893                   }
59894                 }
59895               })];
59896               var node = context.hasEntity(this.entityIds[1]);
59897
59898               if (node && !node.hasInterestingTags()) {
59899                 // node has no descriptive tags, suggest noexit fix
59900                 fixes.push(new validationIssueFix({
59901                   icon: 'maki-barrier',
59902                   title: _t.html('issues.fix.tag_as_disconnected.title'),
59903                   onClick: function onClick(context) {
59904                     var nodeID = this.issue.entityIds[1];
59905                     var tags = Object.assign({}, context.entity(nodeID).tags);
59906                     tags.noexit = 'yes';
59907                     context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
59908                   }
59909                 }));
59910               }
59911
59912               return fixes;
59913             }
59914
59915             function showReference(selection) {
59916               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
59917             }
59918
59919             function isExtendableCandidate(node, way) {
59920               // can not accurately test vertices on tiles not downloaded from osm - #5938
59921               var osm = services.osm;
59922
59923               if (osm && !osm.isDataLoaded(node.loc)) {
59924                 return false;
59925               }
59926
59927               if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
59928                 return false;
59929               }
59930
59931               var occurrences = 0;
59932
59933               for (var index in way.nodes) {
59934                 if (way.nodes[index] === node.id) {
59935                   occurrences += 1;
59936
59937                   if (occurrences > 1) {
59938                     return false;
59939                   }
59940                 }
59941               }
59942
59943               return true;
59944             }
59945
59946             function findConnectableEndNodesByExtension(way) {
59947               var results = [];
59948               if (way.isClosed()) return results;
59949               var testNodes;
59950               var indices = [0, way.nodes.length - 1];
59951               indices.forEach(function (nodeIndex) {
59952                 var nodeID = way.nodes[nodeIndex];
59953                 var node = graph.entity(nodeID);
59954                 if (!isExtendableCandidate(node, way)) return;
59955                 var connectionInfo = canConnectByExtend(way, nodeIndex);
59956                 if (!connectionInfo) return;
59957                 testNodes = graph.childNodes(way).slice(); // shallow copy
59958
59959                 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
59960
59961                 if (geoHasSelfIntersections(testNodes, nodeID)) return;
59962                 results.push(connectionInfo);
59963               });
59964               return results;
59965             }
59966
59967             function findNearbyEndNodes(node, way) {
59968               return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
59969                 return graph.entity(d);
59970               }).filter(function (d) {
59971                 // Node cannot be near to itself, but other endnode of same way could be
59972                 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
59973               });
59974             }
59975
59976             function findSmallJoinAngle(midNode, tipNode, endNodes) {
59977               // Both nodes could be close, so want to join whichever is closest to collinear
59978               var joinTo;
59979               var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
59980
59981               endNodes.forEach(function (endNode) {
59982                 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
59983                 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
59984                 var diff = Math.max(a1, a2) - Math.min(a1, a2);
59985
59986                 if (diff < minAngle) {
59987                   joinTo = endNode;
59988                   minAngle = diff;
59989                 }
59990               });
59991               /* Threshold set by considering right angle triangle
59992               based on node joining threshold and extension distance */
59993
59994               if (minAngle <= SIG_ANGLE_TH) return joinTo;
59995               return null;
59996             }
59997
59998             function hasTag(tags, key) {
59999               return tags[key] !== undefined && tags[key] !== 'no';
60000             }
60001
60002             function canConnectWays(way, way2) {
60003               // allow self-connections
60004               if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
60005
60006               if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
60007               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
60008
60009               var layer1 = way.tags.layer || '0',
60010                   layer2 = way2.tags.layer || '0';
60011               if (layer1 !== layer2) return false;
60012               var level1 = way.tags.level || '0',
60013                   level2 = way2.tags.level || '0';
60014               if (level1 !== level2) return false;
60015               return true;
60016             }
60017
60018             function canConnectByExtend(way, endNodeIdx) {
60019               var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
60020
60021               var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
60022
60023               var tipNode = graph.entity(tipNid);
60024               var midNode = graph.entity(midNid);
60025               var lon = tipNode.loc[0];
60026               var lat = tipNode.loc[1];
60027               var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
60028               var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
60029               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
60030
60031               var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
60032               var t = EXTEND_TH_METERS / edgeLen + 1.0;
60033               var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
60034
60035               var segmentInfos = tree.waySegments(queryExtent, graph);
60036
60037               for (var i = 0; i < segmentInfos.length; i++) {
60038                 var segmentInfo = segmentInfos[i];
60039                 var way2 = graph.entity(segmentInfo.wayId);
60040                 if (!isHighway(way2)) continue;
60041                 if (!canConnectWays(way, way2)) continue;
60042                 var nAid = segmentInfo.nodes[0],
60043                     nBid = segmentInfo.nodes[1];
60044                 if (nAid === tipNid || nBid === tipNid) continue;
60045                 var nA = graph.entity(nAid),
60046                     nB = graph.entity(nBid);
60047                 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
60048
60049                 if (crossLoc) {
60050                   return {
60051                     mid: midNode,
60052                     node: tipNode,
60053                     wid: way2.id,
60054                     edge: [nA.id, nB.id],
60055                     cross_loc: crossLoc
60056                   };
60057                 }
60058               }
60059
60060               return null;
60061             }
60062           };
60063
60064           validation.type = type;
60065           return validation;
60066         }
60067
60068         function validationCloseNodes(context) {
60069           var type = 'close_nodes';
60070           var pointThresholdMeters = 0.2;
60071
60072           var validation = function validation(entity, graph) {
60073             if (entity.type === 'node') {
60074               return getIssuesForNode(entity);
60075             } else if (entity.type === 'way') {
60076               return getIssuesForWay(entity);
60077             }
60078
60079             return [];
60080
60081             function getIssuesForNode(node) {
60082               var parentWays = graph.parentWays(node);
60083
60084               if (parentWays.length) {
60085                 return getIssuesForVertex(node, parentWays);
60086               } else {
60087                 return getIssuesForDetachedPoint(node);
60088               }
60089             }
60090
60091             function wayTypeFor(way) {
60092               if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
60093               if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
60094               if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
60095               if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
60096               var parentRelations = graph.parentRelations(way);
60097
60098               for (var i in parentRelations) {
60099                 var relation = parentRelations[i];
60100                 if (relation.tags.type === 'boundary') return 'boundary';
60101
60102                 if (relation.isMultipolygon()) {
60103                   if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
60104                   if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
60105                 }
60106               }
60107
60108               return 'other';
60109             }
60110
60111             function shouldCheckWay(way) {
60112               // don't flag issues where merging would create degenerate ways
60113               if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
60114               var bbox = way.extent(graph).bbox();
60115               var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
60116
60117               if (hypotenuseMeters < 1.5) return false;
60118               return true;
60119             }
60120
60121             function getIssuesForWay(way) {
60122               if (!shouldCheckWay(way)) return [];
60123               var issues = [],
60124                   nodes = graph.childNodes(way);
60125
60126               for (var i = 0; i < nodes.length - 1; i++) {
60127                 var node1 = nodes[i];
60128                 var node2 = nodes[i + 1];
60129                 var issue = getWayIssueIfAny(node1, node2, way);
60130                 if (issue) issues.push(issue);
60131               }
60132
60133               return issues;
60134             }
60135
60136             function getIssuesForVertex(node, parentWays) {
60137               var issues = [];
60138
60139               function checkForCloseness(node1, node2, way) {
60140                 var issue = getWayIssueIfAny(node1, node2, way);
60141                 if (issue) issues.push(issue);
60142               }
60143
60144               for (var i = 0; i < parentWays.length; i++) {
60145                 var parentWay = parentWays[i];
60146                 if (!shouldCheckWay(parentWay)) continue;
60147                 var lastIndex = parentWay.nodes.length - 1;
60148
60149                 for (var j = 0; j < parentWay.nodes.length; j++) {
60150                   if (j !== 0) {
60151                     if (parentWay.nodes[j - 1] === node.id) {
60152                       checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
60153                     }
60154                   }
60155
60156                   if (j !== lastIndex) {
60157                     if (parentWay.nodes[j + 1] === node.id) {
60158                       checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
60159                     }
60160                   }
60161                 }
60162               }
60163
60164               return issues;
60165             }
60166
60167             function thresholdMetersForWay(way) {
60168               if (!shouldCheckWay(way)) return 0;
60169               var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
60170
60171               if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
60172
60173               if (wayType === 'indoor') return 0.01;
60174               if (wayType === 'building') return 0.05;
60175               if (wayType === 'path') return 0.1;
60176               return 0.2;
60177             }
60178
60179             function getIssuesForDetachedPoint(node) {
60180               var issues = [];
60181               var lon = node.loc[0];
60182               var lat = node.loc[1];
60183               var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
60184               var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
60185               var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
60186               var intersected = context.history().tree().intersects(queryExtent, graph);
60187
60188               for (var j = 0; j < intersected.length; j++) {
60189                 var nearby = intersected[j];
60190                 if (nearby.id === node.id) continue;
60191                 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
60192
60193                 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
60194                   // allow very close points if tags indicate the z-axis might vary
60195                   var zAxisKeys = {
60196                     layer: true,
60197                     level: true,
60198                     'addr:housenumber': true,
60199                     'addr:unit': true
60200                   };
60201                   var zAxisDifferentiates = false;
60202
60203                   for (var key in zAxisKeys) {
60204                     var nodeValue = node.tags[key] || '0';
60205                     var nearbyValue = nearby.tags[key] || '0';
60206
60207                     if (nodeValue !== nearbyValue) {
60208                       zAxisDifferentiates = true;
60209                       break;
60210                     }
60211                   }
60212
60213                   if (zAxisDifferentiates) continue;
60214                   issues.push(new validationIssue({
60215                     type: type,
60216                     subtype: 'detached',
60217                     severity: 'warning',
60218                     message: function message(context) {
60219                       var entity = context.hasEntity(this.entityIds[0]),
60220                           entity2 = context.hasEntity(this.entityIds[1]);
60221                       return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
60222                         feature: utilDisplayLabel(entity, context.graph()),
60223                         feature2: utilDisplayLabel(entity2, context.graph())
60224                       }) : '';
60225                     },
60226                     reference: showReference,
60227                     entityIds: [node.id, nearby.id],
60228                     dynamicFixes: function dynamicFixes() {
60229                       return [new validationIssueFix({
60230                         icon: 'iD-operation-disconnect',
60231                         title: _t.html('issues.fix.move_points_apart.title')
60232                       }), new validationIssueFix({
60233                         icon: 'iD-icon-layers',
60234                         title: _t.html('issues.fix.use_different_layers_or_levels.title')
60235                       })];
60236                     }
60237                   }));
60238                 }
60239               }
60240
60241               return issues;
60242
60243               function showReference(selection) {
60244                 var referenceText = _t('issues.close_nodes.detached.reference');
60245                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
60246               }
60247             }
60248
60249             function getWayIssueIfAny(node1, node2, way) {
60250               if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
60251                 return null;
60252               }
60253
60254               if (node1.loc !== node2.loc) {
60255                 var parentWays1 = graph.parentWays(node1);
60256                 var parentWays2 = new Set(graph.parentWays(node2));
60257                 var sharedWays = parentWays1.filter(function (parentWay) {
60258                   return parentWays2.has(parentWay);
60259                 });
60260                 var thresholds = sharedWays.map(function (parentWay) {
60261                   return thresholdMetersForWay(parentWay);
60262                 });
60263                 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
60264                 var distance = geoSphericalDistance(node1.loc, node2.loc);
60265                 if (distance > threshold) return null;
60266               }
60267
60268               return new validationIssue({
60269                 type: type,
60270                 subtype: 'vertices',
60271                 severity: 'warning',
60272                 message: function message(context) {
60273                   var entity = context.hasEntity(this.entityIds[0]);
60274                   return entity ? _t.html('issues.close_nodes.message', {
60275                     way: utilDisplayLabel(entity, context.graph())
60276                   }) : '';
60277                 },
60278                 reference: showReference,
60279                 entityIds: [way.id, node1.id, node2.id],
60280                 loc: node1.loc,
60281                 dynamicFixes: function dynamicFixes() {
60282                   return [new validationIssueFix({
60283                     icon: 'iD-icon-plus',
60284                     title: _t.html('issues.fix.merge_points.title'),
60285                     onClick: function onClick(context) {
60286                       var entityIds = this.issue.entityIds;
60287                       var action = actionMergeNodes([entityIds[1], entityIds[2]]);
60288                       context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
60289                     }
60290                   }), new validationIssueFix({
60291                     icon: 'iD-operation-disconnect',
60292                     title: _t.html('issues.fix.move_points_apart.title')
60293                   })];
60294                 }
60295               });
60296
60297               function showReference(selection) {
60298                 var referenceText = _t('issues.close_nodes.reference');
60299                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
60300               }
60301             }
60302           };
60303
60304           validation.type = type;
60305           return validation;
60306         }
60307
60308         function validationCrossingWays(context) {
60309           var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
60310
60311           function getFeatureWithFeatureTypeTagsForWay(way, graph) {
60312             if (getFeatureType(way, graph) === null) {
60313               // if the way doesn't match a feature type, check its parent relations
60314               var parentRels = graph.parentRelations(way);
60315
60316               for (var i = 0; i < parentRels.length; i++) {
60317                 var rel = parentRels[i];
60318
60319                 if (getFeatureType(rel, graph) !== null) {
60320                   return rel;
60321                 }
60322               }
60323             }
60324
60325             return way;
60326           }
60327
60328           function hasTag(tags, key) {
60329             return tags[key] !== undefined && tags[key] !== 'no';
60330           }
60331
60332           function taggedAsIndoor(tags) {
60333             return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
60334           }
60335
60336           function allowsBridge(featureType) {
60337             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
60338           }
60339
60340           function allowsTunnel(featureType) {
60341             return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
60342           } // discard
60343
60344
60345           var ignoredBuildings = {
60346             demolished: true,
60347             dismantled: true,
60348             proposed: true,
60349             razed: true
60350           };
60351
60352           function getFeatureType(entity, graph) {
60353             var geometry = entity.geometry(graph);
60354             if (geometry !== 'line' && geometry !== 'area') return null;
60355             var tags = entity.tags;
60356             if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
60357             if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
60358
60359             if (geometry !== 'line') return null;
60360             if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
60361             if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
60362             return null;
60363           }
60364
60365           function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
60366             // assume 0 by default
60367             var level1 = tags1.level || '0';
60368             var level2 = tags2.level || '0';
60369
60370             if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
60371               // assume features don't interact if they're indoor on different levels
60372               return true;
60373             } // assume 0 by default; don't use way.layer() since we account for structures here
60374
60375
60376             var layer1 = tags1.layer || '0';
60377             var layer2 = tags2.layer || '0';
60378
60379             if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
60380               if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
60381               if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
60382
60383               if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
60384             } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
60385
60386             if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
60387               if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
60388               if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
60389
60390               if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
60391             } 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
60392
60393
60394             if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
60395             if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
60396
60397             if (featureType1 === 'building' || featureType2 === 'building') {
60398               // for building crossings, different layers are enough
60399               if (layer1 !== layer2) return true;
60400             }
60401
60402             return false;
60403           } // highway values for which we shouldn't recommend connecting to waterways
60404
60405
60406           var highwaysDisallowingFords = {
60407             motorway: true,
60408             motorway_link: true,
60409             trunk: true,
60410             trunk_link: true,
60411             primary: true,
60412             primary_link: true,
60413             secondary: true,
60414             secondary_link: true
60415           };
60416           var nonCrossingHighways = {
60417             track: true
60418           };
60419
60420           function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
60421             var featureType1 = getFeatureType(entity1, graph);
60422             var featureType2 = getFeatureType(entity2, graph);
60423             var geometry1 = entity1.geometry(graph);
60424             var geometry2 = entity2.geometry(graph);
60425             var bothLines = geometry1 === 'line' && geometry2 === 'line';
60426
60427             if (featureType1 === featureType2) {
60428               if (featureType1 === 'highway') {
60429                 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
60430                 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
60431
60432                 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
60433                   // one feature is a path but not both
60434                   var roadFeature = entity1IsPath ? entity2 : entity1;
60435
60436                   if (nonCrossingHighways[roadFeature.tags.highway]) {
60437                     // don't mark path connections with certain roads as crossings
60438                     return {};
60439                   }
60440
60441                   var pathFeature = entity1IsPath ? entity1 : entity2;
60442
60443                   if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
60444                     // if the path is a crossing, match the crossing type
60445                     return bothLines ? {
60446                       highway: 'crossing',
60447                       crossing: pathFeature.tags.crossing
60448                     } : {};
60449                   } // don't add a `crossing` subtag to ambiguous crossings
60450
60451
60452                   return bothLines ? {
60453                     highway: 'crossing'
60454                   } : {};
60455                 }
60456
60457                 return {};
60458               }
60459
60460               if (featureType1 === 'waterway') return {};
60461               if (featureType1 === 'railway') return {};
60462             } else {
60463               var featureTypes = [featureType1, featureType2];
60464
60465               if (featureTypes.indexOf('highway') !== -1) {
60466                 if (featureTypes.indexOf('railway') !== -1) {
60467                   if (!bothLines) return {};
60468                   var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
60469
60470                   if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
60471                     // path-tram connections use this tag
60472                     if (isTram) return {
60473                       railway: 'tram_crossing'
60474                     }; // other path-rail connections use this tag
60475
60476                     return {
60477                       railway: 'crossing'
60478                     };
60479                   } else {
60480                     // path-tram connections use this tag
60481                     if (isTram) return {
60482                       railway: 'tram_level_crossing'
60483                     }; // other road-rail connections use this tag
60484
60485                     return {
60486                       railway: 'level_crossing'
60487                     };
60488                   }
60489                 }
60490
60491                 if (featureTypes.indexOf('waterway') !== -1) {
60492                   // do not allow fords on structures
60493                   if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
60494                   if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
60495
60496                   if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
60497                     // do not allow fords on major highways
60498                     return null;
60499                   }
60500
60501                   return bothLines ? {
60502                     ford: 'yes'
60503                   } : {};
60504                 }
60505               }
60506             }
60507
60508             return null;
60509           }
60510
60511           function findCrossingsByWay(way1, graph, tree) {
60512             var edgeCrossInfos = [];
60513             if (way1.type !== 'way') return edgeCrossInfos;
60514             var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
60515             var way1FeatureType = getFeatureType(taggedFeature1, graph);
60516             if (way1FeatureType === null) return edgeCrossInfos;
60517             var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
60518
60519             var i, j;
60520             var extent;
60521             var n1, n2, nA, nB, nAId, nBId;
60522             var segment1, segment2;
60523             var oneOnly;
60524             var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
60525             var way1Nodes = graph.childNodes(way1);
60526             var comparedWays = {};
60527
60528             for (i = 0; i < way1Nodes.length - 1; i++) {
60529               n1 = way1Nodes[i];
60530               n2 = way1Nodes[i + 1];
60531               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
60532               // of overlapping ways
60533
60534               segmentInfos = tree.waySegments(extent, graph);
60535
60536               for (j = 0; j < segmentInfos.length; j++) {
60537                 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
60538
60539                 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
60540
60541                 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
60542
60543                 comparedWays[segment2Info.wayId] = true;
60544                 way2 = graph.hasEntity(segment2Info.wayId);
60545                 if (!way2) continue;
60546                 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
60547
60548                 way2FeatureType = getFeatureType(taggedFeature2, graph);
60549
60550                 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
60551                   continue;
60552                 } // create only one issue for building crossings
60553
60554
60555                 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
60556                 nAId = segment2Info.nodes[0];
60557                 nBId = segment2Info.nodes[1];
60558
60559                 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
60560                   // n1 or n2 is a connection node; skip
60561                   continue;
60562                 }
60563
60564                 nA = graph.hasEntity(nAId);
60565                 if (!nA) continue;
60566                 nB = graph.hasEntity(nBId);
60567                 if (!nB) continue;
60568                 segment1 = [n1.loc, n2.loc];
60569                 segment2 = [nA.loc, nB.loc];
60570                 var point = geoLineIntersection(segment1, segment2);
60571
60572                 if (point) {
60573                   edgeCrossInfos.push({
60574                     wayInfos: [{
60575                       way: way1,
60576                       featureType: way1FeatureType,
60577                       edge: [n1.id, n2.id]
60578                     }, {
60579                       way: way2,
60580                       featureType: way2FeatureType,
60581                       edge: [nA.id, nB.id]
60582                     }],
60583                     crossPoint: point
60584                   });
60585
60586                   if (oneOnly) {
60587                     checkedSingleCrossingWays[way2.id] = true;
60588                     break;
60589                   }
60590                 }
60591               }
60592             }
60593
60594             return edgeCrossInfos;
60595           }
60596
60597           function waysToCheck(entity, graph) {
60598             var featureType = getFeatureType(entity, graph);
60599             if (!featureType) return [];
60600
60601             if (entity.type === 'way') {
60602               return [entity];
60603             } else if (entity.type === 'relation') {
60604               return entity.members.reduce(function (array, member) {
60605                 if (member.type === 'way' && ( // only look at geometry ways
60606                 !member.role || member.role === 'outer' || member.role === 'inner')) {
60607                   var entity = graph.hasEntity(member.id); // don't add duplicates
60608
60609                   if (entity && array.indexOf(entity) === -1) {
60610                     array.push(entity);
60611                   }
60612                 }
60613
60614                 return array;
60615               }, []);
60616             }
60617
60618             return [];
60619           }
60620
60621           var validation = function checkCrossingWays(entity, graph) {
60622             var tree = context.history().tree();
60623             var ways = waysToCheck(entity, graph);
60624             var issues = []; // declare these here to reduce garbage collection
60625
60626             var wayIndex, crossingIndex, crossings;
60627
60628             for (wayIndex in ways) {
60629               crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
60630
60631               for (crossingIndex in crossings) {
60632                 issues.push(createIssue(crossings[crossingIndex], graph));
60633               }
60634             }
60635
60636             return issues;
60637           };
60638
60639           function createIssue(crossing, graph) {
60640             // use the entities with the tags that define the feature type
60641             crossing.wayInfos.sort(function (way1Info, way2Info) {
60642               var type1 = way1Info.featureType;
60643               var type2 = way2Info.featureType;
60644
60645               if (type1 === type2) {
60646                 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
60647               } else if (type1 === 'waterway') {
60648                 return true;
60649               } else if (type2 === 'waterway') {
60650                 return false;
60651               }
60652
60653               return type1 < type2;
60654             });
60655             var entities = crossing.wayInfos.map(function (wayInfo) {
60656               return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
60657             });
60658             var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
60659             var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
60660             var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
60661             var featureType1 = crossing.wayInfos[0].featureType;
60662             var featureType2 = crossing.wayInfos[1].featureType;
60663             var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
60664             var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
60665             var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
60666             var subtype = [featureType1, featureType2].sort().join('-');
60667             var crossingTypeID = subtype;
60668
60669             if (isCrossingIndoors) {
60670               crossingTypeID = 'indoor-indoor';
60671             } else if (isCrossingTunnels) {
60672               crossingTypeID = 'tunnel-tunnel';
60673             } else if (isCrossingBridges) {
60674               crossingTypeID = 'bridge-bridge';
60675             }
60676
60677             if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
60678               crossingTypeID += '_connectable';
60679             }
60680
60681             return new validationIssue({
60682               type: type,
60683               subtype: subtype,
60684               severity: 'warning',
60685               message: function message(context) {
60686                 var graph = context.graph();
60687                 var entity1 = graph.hasEntity(this.entityIds[0]),
60688                     entity2 = graph.hasEntity(this.entityIds[1]);
60689                 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
60690                   feature: utilDisplayLabel(entity1, graph),
60691                   feature2: utilDisplayLabel(entity2, graph)
60692                 }) : '';
60693               },
60694               reference: showReference,
60695               entityIds: entities.map(function (entity) {
60696                 return entity.id;
60697               }),
60698               data: {
60699                 edges: edges,
60700                 featureTypes: featureTypes,
60701                 connectionTags: connectionTags
60702               },
60703               // differentiate based on the loc since two ways can cross multiple times
60704               hash: crossing.crossPoint.toString() + // if the edges change then so does the fix
60705               edges.slice().sort(function (edge1, edge2) {
60706                 // order to assure hash is deterministic
60707                 return edge1[0] < edge2[0] ? -1 : 1;
60708               }).toString() + // ensure the correct connection tags are added in the fix
60709               JSON.stringify(connectionTags),
60710               loc: crossing.crossPoint,
60711               dynamicFixes: function dynamicFixes(context) {
60712                 var mode = context.mode();
60713                 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
60714                 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
60715                 var selectedFeatureType = this.data.featureTypes[selectedIndex];
60716                 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
60717                 var fixes = [];
60718
60719                 if (connectionTags) {
60720                   fixes.push(makeConnectWaysFix(this.data.connectionTags));
60721                 }
60722
60723                 if (isCrossingIndoors) {
60724                   fixes.push(new validationIssueFix({
60725                     icon: 'iD-icon-layers',
60726                     title: _t.html('issues.fix.use_different_levels.title')
60727                   }));
60728                 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
60729                   fixes.push(makeChangeLayerFix('higher'));
60730                   fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
60731                 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
60732                   // don't recommend adding bridges to waterways since they're uncommon
60733                   if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
60734                     fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
60735                   } // don't recommend adding tunnels under waterways since they're uncommon
60736
60737
60738                   var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
60739
60740                   if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
60741                     fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
60742                   }
60743                 } // repositioning the features is always an option
60744
60745
60746                 fixes.push(new validationIssueFix({
60747                   icon: 'iD-operation-move',
60748                   title: _t.html('issues.fix.reposition_features.title')
60749                 }));
60750                 return fixes;
60751               }
60752             });
60753
60754             function showReference(selection) {
60755               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
60756             }
60757           }
60758
60759           function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
60760             return new validationIssueFix({
60761               icon: iconName,
60762               title: _t.html('issues.fix.' + fixTitleID + '.title'),
60763               onClick: function onClick(context) {
60764                 var mode = context.mode();
60765                 if (!mode || mode.id !== 'select') return;
60766                 var selectedIDs = mode.selectedIDs();
60767                 if (selectedIDs.length !== 1) return;
60768                 var selectedWayID = selectedIDs[0];
60769                 if (!context.hasEntity(selectedWayID)) return;
60770                 var resultWayIDs = [selectedWayID];
60771                 var edge, crossedEdge, crossedWayID;
60772
60773                 if (this.issue.entityIds[0] === selectedWayID) {
60774                   edge = this.issue.data.edges[0];
60775                   crossedEdge = this.issue.data.edges[1];
60776                   crossedWayID = this.issue.entityIds[1];
60777                 } else {
60778                   edge = this.issue.data.edges[1];
60779                   crossedEdge = this.issue.data.edges[0];
60780                   crossedWayID = this.issue.entityIds[0];
60781                 }
60782
60783                 var crossingLoc = this.issue.loc;
60784                 var projection = context.projection;
60785
60786                 var action = function actionAddStructure(graph) {
60787                   var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60788                   var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
60789
60790                   var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
60791
60792                   if (!structLengthMeters) {
60793                     // if no explicit width is set, approximate the width based on the tags
60794                     structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
60795                   }
60796
60797                   if (structLengthMeters) {
60798                     if (getFeatureType(crossedWay, graph) === 'railway') {
60799                       // bridges over railways are generally much longer than the rail bed itself, compensate
60800                       structLengthMeters *= 2;
60801                     }
60802                   } else {
60803                     // should ideally never land here since all rail/water/road tags should have an implied width
60804                     structLengthMeters = 8;
60805                   }
60806
60807                   var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
60808                   var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
60809                   var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
60810                   if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
60811
60812                   structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
60813
60814                   structLengthMeters += 4; // clamp the length to a reasonable range
60815
60816                   structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
60817
60818                   function geomToProj(geoPoint) {
60819                     return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
60820                   }
60821
60822                   function projToGeom(projPoint) {
60823                     var lat = geoMetersToLat(projPoint[1]);
60824                     return [geoMetersToLon(projPoint[0], lat), lat];
60825                   }
60826
60827                   var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
60828                   var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
60829                   var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
60830                   var projectedCrossingLoc = geomToProj(crossingLoc);
60831                   var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
60832
60833                   function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
60834                     var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
60835                     return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
60836                   }
60837
60838                   var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
60839                     return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
60840                   };
60841
60842                   var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
60843                     return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
60844                   }; // avoid creating very short edges from splitting too close to another node
60845
60846
60847                   var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
60848
60849                   function determineEndpoint(edge, endNode, locGetter) {
60850                     var newNode;
60851                     var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
60852                     // the maximum length of this side of the structure
60853
60854                     var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
60855
60856                     if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
60857                       // the edge is long enough to insert a new node
60858                       // the loc that would result in the full expected length
60859                       var idealNodeLoc = locGetter(idealLengthMeters);
60860                       newNode = osmNode();
60861                       graph = actionAddMidpoint({
60862                         loc: idealNodeLoc,
60863                         edge: edge
60864                       }, newNode)(graph);
60865                     } else {
60866                       var edgeCount = 0;
60867                       endNode.parentIntersectionWays(graph).forEach(function (way) {
60868                         way.nodes.forEach(function (nodeID) {
60869                           if (nodeID === endNode.id) {
60870                             if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
60871                               edgeCount += 1;
60872                             } else {
60873                               edgeCount += 2;
60874                             }
60875                           }
60876                         });
60877                       });
60878
60879                       if (edgeCount >= 3) {
60880                         // the end node is a junction, try to leave a segment
60881                         // between it and the structure - #7202
60882                         var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
60883
60884                         if (insetLength > minEdgeLengthMeters) {
60885                           var insetNodeLoc = locGetter(insetLength);
60886                           newNode = osmNode();
60887                           graph = actionAddMidpoint({
60888                             loc: insetNodeLoc,
60889                             edge: edge
60890                           }, newNode)(graph);
60891                         }
60892                       }
60893                     } // if the edge is too short to subdivide as desired, then
60894                     // just bound the structure at the existing end node
60895
60896
60897                     if (!newNode) newNode = endNode;
60898                     var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
60899                     // do the split
60900
60901                     graph = splitAction(graph);
60902
60903                     if (splitAction.getCreatedWayIDs().length) {
60904                       resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
60905                     }
60906
60907                     return newNode;
60908                   }
60909
60910                   var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
60911                   var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
60912                   var structureWay = resultWayIDs.map(function (id) {
60913                     return graph.entity(id);
60914                   }).find(function (way) {
60915                     return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
60916                   });
60917                   var tags = Object.assign({}, structureWay.tags); // copy tags
60918
60919                   if (bridgeOrTunnel === 'bridge') {
60920                     tags.bridge = 'yes';
60921                     tags.layer = '1';
60922                   } else {
60923                     var tunnelValue = 'yes';
60924
60925                     if (getFeatureType(structureWay, graph) === 'waterway') {
60926                       // use `tunnel=culvert` for waterways by default
60927                       tunnelValue = 'culvert';
60928                     }
60929
60930                     tags.tunnel = tunnelValue;
60931                     tags.layer = '-1';
60932                   } // apply the structure tags to the way
60933
60934
60935                   graph = actionChangeTags(structureWay.id, tags)(graph);
60936                   return graph;
60937                 };
60938
60939                 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
60940                 context.enter(modeSelect(context, resultWayIDs));
60941               }
60942             });
60943           }
60944
60945           function makeConnectWaysFix(connectionTags) {
60946             var fixTitleID = 'connect_features';
60947
60948             if (connectionTags.ford) {
60949               fixTitleID = 'connect_using_ford';
60950             }
60951
60952             return new validationIssueFix({
60953               icon: 'iD-icon-crossing',
60954               title: _t.html('issues.fix.' + fixTitleID + '.title'),
60955               onClick: function onClick(context) {
60956                 var loc = this.issue.loc;
60957                 var connectionTags = this.issue.data.connectionTags;
60958                 var edges = this.issue.data.edges;
60959                 context.perform(function actionConnectCrossingWays(graph) {
60960                   // create the new node for the points
60961                   var node = osmNode({
60962                     loc: loc,
60963                     tags: connectionTags
60964                   });
60965                   graph = graph.replace(node);
60966                   var nodesToMerge = [node.id];
60967                   var mergeThresholdInMeters = 0.75;
60968                   edges.forEach(function (edge) {
60969                     var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
60970                     var closestNodeInfo = geoSphericalClosestNode(edgeNodes, loc); // if there is already a point nearby, use that
60971
60972                     if (closestNodeInfo.distance < mergeThresholdInMeters) {
60973                       nodesToMerge.push(closestNodeInfo.node.id); // else add the new node to the way
60974                     } else {
60975                       graph = actionAddMidpoint({
60976                         loc: loc,
60977                         edge: edge
60978                       }, node)(graph);
60979                     }
60980                   });
60981
60982                   if (nodesToMerge.length > 1) {
60983                     // if we're using nearby nodes, merge them with the new node
60984                     graph = actionMergeNodes(nodesToMerge, loc)(graph);
60985                   }
60986
60987                   return graph;
60988                 }, _t('issues.fix.connect_crossing_features.annotation'));
60989               }
60990             });
60991           }
60992
60993           function makeChangeLayerFix(higherOrLower) {
60994             return new validationIssueFix({
60995               icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
60996               title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
60997               onClick: function onClick(context) {
60998                 var mode = context.mode();
60999                 if (!mode || mode.id !== 'select') return;
61000                 var selectedIDs = mode.selectedIDs();
61001                 if (selectedIDs.length !== 1) return;
61002                 var selectedID = selectedIDs[0];
61003                 if (!this.issue.entityIds.some(function (entityId) {
61004                   return entityId === selectedID;
61005                 })) return;
61006                 var entity = context.hasEntity(selectedID);
61007                 if (!entity) return;
61008                 var tags = Object.assign({}, entity.tags); // shallow copy
61009
61010                 var layer = tags.layer && Number(tags.layer);
61011
61012                 if (layer && !isNaN(layer)) {
61013                   if (higherOrLower === 'higher') {
61014                     layer += 1;
61015                   } else {
61016                     layer -= 1;
61017                   }
61018                 } else {
61019                   if (higherOrLower === 'higher') {
61020                     layer = 1;
61021                   } else {
61022                     layer = -1;
61023                   }
61024                 }
61025
61026                 tags.layer = layer.toString();
61027                 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
61028               }
61029             });
61030           }
61031
61032           validation.type = type;
61033           return validation;
61034         }
61035
61036         function validationDisconnectedWay() {
61037           var type = 'disconnected_way';
61038
61039           function isTaggedAsHighway(entity) {
61040             return osmRoutableHighwayTagValues[entity.tags.highway];
61041           }
61042
61043           var validation = function checkDisconnectedWay(entity, graph) {
61044             var routingIslandWays = routingIslandForEntity(entity);
61045             if (!routingIslandWays) return [];
61046             return [new validationIssue({
61047               type: type,
61048               subtype: 'highway',
61049               severity: 'warning',
61050               message: function message(context) {
61051                 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
61052                 var label = entity && utilDisplayLabel(entity, context.graph());
61053                 return _t.html('issues.disconnected_way.routable.message', {
61054                   count: this.entityIds.length,
61055                   highway: label
61056                 });
61057               },
61058               reference: showReference,
61059               entityIds: Array.from(routingIslandWays).map(function (way) {
61060                 return way.id;
61061               }),
61062               dynamicFixes: makeFixes
61063             })];
61064
61065             function makeFixes(context) {
61066               var fixes = [];
61067               var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
61068
61069               if (singleEntity) {
61070                 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
61071                   var textDirection = _mainLocalizer.textDirection();
61072                   var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
61073                   if (startFix) fixes.push(startFix);
61074                   var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
61075                   if (endFix) fixes.push(endFix);
61076                 }
61077
61078                 if (!fixes.length) {
61079                   fixes.push(new validationIssueFix({
61080                     title: _t.html('issues.fix.connect_feature.title')
61081                   }));
61082                 }
61083
61084                 fixes.push(new validationIssueFix({
61085                   icon: 'iD-operation-delete',
61086                   title: _t.html('issues.fix.delete_feature.title'),
61087                   entityIds: [singleEntity.id],
61088                   onClick: function onClick(context) {
61089                     var id = this.issue.entityIds[0];
61090                     var operation = operationDelete(context, [id]);
61091
61092                     if (!operation.disabled()) {
61093                       operation();
61094                     }
61095                   }
61096                 }));
61097               } else {
61098                 fixes.push(new validationIssueFix({
61099                   title: _t.html('issues.fix.connect_features.title')
61100                 }));
61101               }
61102
61103               return fixes;
61104             }
61105
61106             function showReference(selection) {
61107               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
61108             }
61109
61110             function routingIslandForEntity(entity) {
61111               var routingIsland = new Set(); // the interconnected routable features
61112
61113               var waysToCheck = []; // the queue of remaining routable ways to traverse
61114
61115               function queueParentWays(node) {
61116                 graph.parentWays(node).forEach(function (parentWay) {
61117                   if (!routingIsland.has(parentWay) && // only check each feature once
61118                   isRoutableWay(parentWay, false)) {
61119                     // only check routable features
61120                     routingIsland.add(parentWay);
61121                     waysToCheck.push(parentWay);
61122                   }
61123                 });
61124               }
61125
61126               if (entity.type === 'way' && isRoutableWay(entity, true)) {
61127                 routingIsland.add(entity);
61128                 waysToCheck.push(entity);
61129               } else if (entity.type === 'node' && isRoutableNode(entity)) {
61130                 routingIsland.add(entity);
61131                 queueParentWays(entity);
61132               } else {
61133                 // this feature isn't routable, cannot be a routing island
61134                 return null;
61135               }
61136
61137               while (waysToCheck.length) {
61138                 var wayToCheck = waysToCheck.pop();
61139                 var childNodes = graph.childNodes(wayToCheck);
61140
61141                 for (var i in childNodes) {
61142                   var vertex = childNodes[i];
61143
61144                   if (isConnectedVertex(vertex)) {
61145                     // found a link to the wider network, not a routing island
61146                     return null;
61147                   }
61148
61149                   if (isRoutableNode(vertex)) {
61150                     routingIsland.add(vertex);
61151                   }
61152
61153                   queueParentWays(vertex);
61154                 }
61155               } // no network link found, this is a routing island, return its members
61156
61157
61158               return routingIsland;
61159             }
61160
61161             function isConnectedVertex(vertex) {
61162               // assume ways overlapping unloaded tiles are connected to the wider road network  - #5938
61163               var osm = services.osm;
61164               if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
61165
61166               if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
61167               if (vertex.tags.amenity === 'parking_entrance') return true;
61168               return false;
61169             }
61170
61171             function isRoutableNode(node) {
61172               // treat elevators as distinct features in the highway network
61173               if (node.tags.highway === 'elevator') return true;
61174               return false;
61175             }
61176
61177             function isRoutableWay(way, ignoreInnerWays) {
61178               if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
61179               return graph.parentRelations(way).some(function (parentRelation) {
61180                 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
61181                 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
61182                 return false;
61183               });
61184             }
61185
61186             function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
61187               var vertex = graph.hasEntity(vertexID);
61188               if (!vertex || vertex.tags.noexit === 'yes') return null;
61189               var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
61190               return new validationIssueFix({
61191                 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
61192                 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
61193                 entityIds: [vertexID],
61194                 onClick: function onClick(context) {
61195                   var wayId = this.issue.entityIds[0];
61196                   var way = context.hasEntity(wayId);
61197                   var vertexId = this.entityIds[0];
61198                   var vertex = context.hasEntity(vertexId);
61199                   if (!way || !vertex) return; // make sure the vertex is actually visible and editable
61200
61201                   var map = context.map();
61202
61203                   if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
61204                     map.zoomToEase(vertex);
61205                   }
61206
61207                   context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
61208                 }
61209               });
61210             }
61211           };
61212
61213           validation.type = type;
61214           return validation;
61215         }
61216
61217         function validationFormatting() {
61218           var type = 'invalid_format';
61219
61220           var validation = function validation(entity) {
61221             var issues = [];
61222
61223             function isValidEmail(email) {
61224               // Emails in OSM are going to be official so they should be pretty simple
61225               // Using negated lists to better support all possible unicode characters (#6494)
61226               var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
61227
61228               return !email || valid_email.test(email);
61229             }
61230             /*
61231             function isSchemePresent(url) {
61232                 var valid_scheme = /^https?:\/\//i;
61233                 return (!url || valid_scheme.test(url));
61234             }
61235             */
61236
61237
61238             function showReferenceEmail(selection) {
61239               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
61240             }
61241             /*
61242             function showReferenceWebsite(selection) {
61243                 selection.selectAll('.issue-reference')
61244                     .data([0])
61245                     .enter()
61246                     .append('div')
61247                     .attr('class', 'issue-reference')
61248                     .html(t.html('issues.invalid_format.website.reference'));
61249             }
61250              if (entity.tags.website) {
61251                 // Multiple websites are possible
61252                 // If ever we support ES6, arrow functions make this nicer
61253                 var websites = entity.tags.website
61254                     .split(';')
61255                     .map(function(s) { return s.trim(); })
61256                     .filter(function(x) { return !isSchemePresent(x); });
61257                  if (websites.length) {
61258                     issues.push(new validationIssue({
61259                         type: type,
61260                         subtype: 'website',
61261                         severity: 'warning',
61262                         message: function(context) {
61263                             var entity = context.hasEntity(this.entityIds[0]);
61264                             return entity ? t.html('issues.invalid_format.website.message' + this.data,
61265                                 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
61266                         },
61267                         reference: showReferenceWebsite,
61268                         entityIds: [entity.id],
61269                         hash: websites.join(),
61270                         data: (websites.length > 1) ? '_multi' : ''
61271                     }));
61272                 }
61273             }
61274             */
61275
61276
61277             if (entity.tags.email) {
61278               // Multiple emails are possible
61279               var emails = entity.tags.email.split(';').map(function (s) {
61280                 return s.trim();
61281               }).filter(function (x) {
61282                 return !isValidEmail(x);
61283               });
61284
61285               if (emails.length) {
61286                 issues.push(new validationIssue({
61287                   type: type,
61288                   subtype: 'email',
61289                   severity: 'warning',
61290                   message: function message(context) {
61291                     var entity = context.hasEntity(this.entityIds[0]);
61292                     return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
61293                       feature: utilDisplayLabel(entity, context.graph()),
61294                       email: emails.join(', ')
61295                     }) : '';
61296                   },
61297                   reference: showReferenceEmail,
61298                   entityIds: [entity.id],
61299                   hash: emails.join(),
61300                   data: emails.length > 1 ? '_multi' : ''
61301                 }));
61302               }
61303             }
61304
61305             return issues;
61306           };
61307
61308           validation.type = type;
61309           return validation;
61310         }
61311
61312         function validationHelpRequest(context) {
61313           var type = 'help_request';
61314
61315           var validation = function checkFixmeTag(entity) {
61316             if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
61317
61318             if (entity.version === undefined) return [];
61319
61320             if (entity.v !== undefined) {
61321               var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
61322
61323               if (!baseEntity || !baseEntity.tags.fixme) return [];
61324             }
61325
61326             return [new validationIssue({
61327               type: type,
61328               subtype: 'fixme_tag',
61329               severity: 'warning',
61330               message: function message(context) {
61331                 var entity = context.hasEntity(this.entityIds[0]);
61332                 return entity ? _t.html('issues.fixme_tag.message', {
61333                   feature: utilDisplayLabel(entity, context.graph())
61334                 }) : '';
61335               },
61336               dynamicFixes: function dynamicFixes() {
61337                 return [new validationIssueFix({
61338                   title: _t.html('issues.fix.address_the_concern.title')
61339                 })];
61340               },
61341               reference: showReference,
61342               entityIds: [entity.id]
61343             })];
61344
61345             function showReference(selection) {
61346               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
61347             }
61348           };
61349
61350           validation.type = type;
61351           return validation;
61352         }
61353
61354         function validationImpossibleOneway() {
61355           var type = 'impossible_oneway';
61356
61357           var validation = function checkImpossibleOneway(entity, graph) {
61358             if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
61359             if (entity.isClosed()) return [];
61360             if (!typeForWay(entity)) return [];
61361             if (!isOneway(entity)) return [];
61362             var firstIssues = issuesForNode(entity, entity.first());
61363             var lastIssues = issuesForNode(entity, entity.last());
61364             return firstIssues.concat(lastIssues);
61365
61366             function typeForWay(way) {
61367               if (way.geometry(graph) !== 'line') return null;
61368               if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
61369               if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
61370               return null;
61371             }
61372
61373             function isOneway(way) {
61374               if (way.tags.oneway === 'yes') return true;
61375               if (way.tags.oneway) return false;
61376
61377               for (var key in way.tags) {
61378                 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
61379                   return true;
61380                 }
61381               }
61382
61383               return false;
61384             }
61385
61386             function nodeOccursMoreThanOnce(way, nodeID) {
61387               var occurrences = 0;
61388
61389               for (var index in way.nodes) {
61390                 if (way.nodes[index] === nodeID) {
61391                   occurrences += 1;
61392                   if (occurrences > 1) return true;
61393                 }
61394               }
61395
61396               return false;
61397             }
61398
61399             function isConnectedViaOtherTypes(way, node) {
61400               var wayType = typeForWay(way);
61401
61402               if (wayType === 'highway') {
61403                 // entrances are considered connected
61404                 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
61405                 if (node.tags.amenity === 'parking_entrance') return true;
61406               } else if (wayType === 'waterway') {
61407                 if (node.id === way.first()) {
61408                   // multiple waterways may start at the same spring
61409                   if (node.tags.natural === 'spring') return true;
61410                 } else {
61411                   // multiple waterways may end at the same drain
61412                   if (node.tags.manhole === 'drain') return true;
61413                 }
61414               }
61415
61416               return graph.parentWays(node).some(function (parentWay) {
61417                 if (parentWay.id === way.id) return false;
61418
61419                 if (wayType === 'highway') {
61420                   // allow connections to highway areas
61421                   if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
61422
61423                   if (parentWay.tags.route === 'ferry') return true;
61424                   return graph.parentRelations(parentWay).some(function (parentRelation) {
61425                     if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
61426
61427                     return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
61428                   });
61429                 } else if (wayType === 'waterway') {
61430                   // multiple waterways may start or end at a water body at the same node
61431                   if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
61432                 }
61433
61434                 return false;
61435               });
61436             }
61437
61438             function issuesForNode(way, nodeID) {
61439               var isFirst = nodeID === way.first();
61440               var wayType = typeForWay(way); // ignore if this way is self-connected at this node
61441
61442               if (nodeOccursMoreThanOnce(way, nodeID)) return [];
61443               var osm = services.osm;
61444               if (!osm) return [];
61445               var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
61446
61447               if (!node || !osm.isDataLoaded(node.loc)) return [];
61448               if (isConnectedViaOtherTypes(way, node)) return [];
61449               var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
61450                 if (parentWay.id === way.id) return false;
61451                 return typeForWay(parentWay) === wayType;
61452               }); // assume it's okay for waterways to start or end disconnected for now
61453
61454               if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
61455               var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
61456                 return isOneway(attachedWay);
61457               }); // ignore if the way is connected to some non-oneway features
61458
61459               if (attachedOneways.length < attachedWaysOfSameType.length) return [];
61460
61461               if (attachedOneways.length) {
61462                 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
61463                   if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
61464                   if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
61465                   return false;
61466                 });
61467                 if (connectedEndpointsOkay) return [];
61468               }
61469
61470               var placement = isFirst ? 'start' : 'end',
61471                   messageID = wayType + '.',
61472                   referenceID = wayType + '.';
61473
61474               if (wayType === 'waterway') {
61475                 messageID += 'connected.' + placement;
61476                 referenceID += 'connected';
61477               } else {
61478                 messageID += placement;
61479                 referenceID += placement;
61480               }
61481
61482               return [new validationIssue({
61483                 type: type,
61484                 subtype: wayType,
61485                 severity: 'warning',
61486                 message: function message(context) {
61487                   var entity = context.hasEntity(this.entityIds[0]);
61488                   return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
61489                     feature: utilDisplayLabel(entity, context.graph())
61490                   }) : '';
61491                 },
61492                 reference: getReference(referenceID),
61493                 entityIds: [way.id, node.id],
61494                 dynamicFixes: function dynamicFixes() {
61495                   var fixes = [];
61496
61497                   if (attachedOneways.length) {
61498                     fixes.push(new validationIssueFix({
61499                       icon: 'iD-operation-reverse',
61500                       title: _t.html('issues.fix.reverse_feature.title'),
61501                       entityIds: [way.id],
61502                       onClick: function onClick(context) {
61503                         var id = this.issue.entityIds[0];
61504                         context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
61505                           n: 1
61506                         }));
61507                       }
61508                     }));
61509                   }
61510
61511                   if (node.tags.noexit !== 'yes') {
61512                     var textDirection = _mainLocalizer.textDirection();
61513                     var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
61514                     fixes.push(new validationIssueFix({
61515                       icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
61516                       title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
61517                       onClick: function onClick(context) {
61518                         var entityID = this.issue.entityIds[0];
61519                         var vertexID = this.issue.entityIds[1];
61520                         var way = context.entity(entityID);
61521                         var vertex = context.entity(vertexID);
61522                         continueDrawing(way, vertex, context);
61523                       }
61524                     }));
61525                   }
61526
61527                   return fixes;
61528                 },
61529                 loc: node.loc
61530               })];
61531
61532               function getReference(referenceID) {
61533                 return function showReference(selection) {
61534                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
61535                 };
61536               }
61537             }
61538           };
61539
61540           function continueDrawing(way, vertex, context) {
61541             // make sure the vertex is actually visible and editable
61542             var map = context.map();
61543
61544             if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
61545               map.zoomToEase(vertex);
61546             }
61547
61548             context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
61549           }
61550
61551           validation.type = type;
61552           return validation;
61553         }
61554
61555         function validationIncompatibleSource() {
61556           var type = 'incompatible_source';
61557           var invalidSources = [{
61558             id: 'google',
61559             regex: 'google',
61560             exceptRegex: 'books.google|Google Books|drive.google|googledrive|Google Drive'
61561           }];
61562
61563           var validation = function checkIncompatibleSource(entity) {
61564             var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
61565             if (!entitySources) return [];
61566             var issues = [];
61567             invalidSources.forEach(function (invalidSource) {
61568               var hasInvalidSource = entitySources.some(function (source) {
61569                 if (!source.match(new RegExp(invalidSource.regex, 'i'))) return false;
61570                 if (invalidSource.exceptRegex && source.match(new RegExp(invalidSource.exceptRegex, 'i'))) return false;
61571                 return true;
61572               });
61573               if (!hasInvalidSource) return;
61574               issues.push(new validationIssue({
61575                 type: type,
61576                 severity: 'warning',
61577                 message: function message(context) {
61578                   var entity = context.hasEntity(this.entityIds[0]);
61579                   return entity ? _t.html('issues.incompatible_source.' + invalidSource.id + '.feature.message', {
61580                     feature: utilDisplayLabel(entity, context.graph())
61581                   }) : '';
61582                 },
61583                 reference: getReference(invalidSource.id),
61584                 entityIds: [entity.id],
61585                 dynamicFixes: function dynamicFixes() {
61586                   return [new validationIssueFix({
61587                     title: _t.html('issues.fix.remove_proprietary_data.title')
61588                   })];
61589                 }
61590               }));
61591             });
61592             return issues;
61593
61594             function getReference(id) {
61595               return function showReference(selection) {
61596                 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.incompatible_source.' + id + '.reference'));
61597               };
61598             }
61599           };
61600
61601           validation.type = type;
61602           return validation;
61603         }
61604
61605         function validationMaprules() {
61606           var type = 'maprules';
61607
61608           var validation = function checkMaprules(entity, graph) {
61609             if (!services.maprules) return [];
61610             var rules = services.maprules.validationRules();
61611             var issues = [];
61612
61613             for (var i = 0; i < rules.length; i++) {
61614               var rule = rules[i];
61615               rule.findIssues(entity, graph, issues);
61616             }
61617
61618             return issues;
61619           };
61620
61621           validation.type = type;
61622           return validation;
61623         }
61624
61625         function validationMismatchedGeometry() {
61626           var type = 'mismatched_geometry';
61627
61628           function tagSuggestingLineIsArea(entity) {
61629             if (entity.type !== 'way' || entity.isClosed()) return null;
61630             var tagSuggestingArea = entity.tagSuggestingArea();
61631
61632             if (!tagSuggestingArea) {
61633               return null;
61634             }
61635
61636             var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
61637             var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
61638
61639             if (asLine && asArea && asLine === asArea) {
61640               // these tags also allow lines and making this an area wouldn't matter
61641               return null;
61642             }
61643
61644             return tagSuggestingArea;
61645           }
61646
61647           function makeConnectEndpointsFixOnClick(way, graph) {
61648             // must have at least three nodes to close this automatically
61649             if (way.nodes.length < 3) return null;
61650             var nodes = graph.childNodes(way),
61651                 testNodes;
61652             var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
61653
61654             if (firstToLastDistanceMeters < 0.75) {
61655               testNodes = nodes.slice(); // shallow copy
61656
61657               testNodes.pop();
61658               testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
61659
61660               if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
61661                 return function (context) {
61662                   var way = context.entity(this.issue.entityIds[0]);
61663                   context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
61664                 };
61665               }
61666             } // if the points were not merged, attempt to close the way
61667
61668
61669             testNodes = nodes.slice(); // shallow copy
61670
61671             testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
61672
61673             if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
61674               return function (context) {
61675                 var wayId = this.issue.entityIds[0];
61676                 var way = context.entity(wayId);
61677                 var nodeId = way.nodes[0];
61678                 var index = way.nodes.length;
61679                 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
61680               };
61681             }
61682           }
61683
61684           function lineTaggedAsAreaIssue(entity) {
61685             var tagSuggestingArea = tagSuggestingLineIsArea(entity);
61686             if (!tagSuggestingArea) return null;
61687             return new validationIssue({
61688               type: type,
61689               subtype: 'area_as_line',
61690               severity: 'warning',
61691               message: function message(context) {
61692                 var entity = context.hasEntity(this.entityIds[0]);
61693                 return entity ? _t.html('issues.tag_suggests_area.message', {
61694                   feature: utilDisplayLabel(entity, 'area'),
61695                   tag: utilTagText({
61696                     tags: tagSuggestingArea
61697                   })
61698                 }) : '';
61699               },
61700               reference: showReference,
61701               entityIds: [entity.id],
61702               hash: JSON.stringify(tagSuggestingArea),
61703               dynamicFixes: function dynamicFixes(context) {
61704                 var fixes = [];
61705                 var entity = context.entity(this.entityIds[0]);
61706                 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
61707                 fixes.push(new validationIssueFix({
61708                   title: _t.html('issues.fix.connect_endpoints.title'),
61709                   onClick: connectEndsOnClick
61710                 }));
61711                 fixes.push(new validationIssueFix({
61712                   icon: 'iD-operation-delete',
61713                   title: _t.html('issues.fix.remove_tag.title'),
61714                   onClick: function onClick(context) {
61715                     var entityId = this.issue.entityIds[0];
61716                     var entity = context.entity(entityId);
61717                     var tags = Object.assign({}, entity.tags); // shallow copy
61718
61719                     for (var key in tagSuggestingArea) {
61720                       delete tags[key];
61721                     }
61722
61723                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
61724                   }
61725                 }));
61726                 return fixes;
61727               }
61728             });
61729
61730             function showReference(selection) {
61731               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
61732             }
61733           }
61734
61735           function vertexTaggedAsPointIssue(entity, graph) {
61736             // we only care about nodes
61737             if (entity.type !== 'node') return null; // ignore tagless points
61738
61739             if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
61740
61741             if (entity.isOnAddressLine(graph)) return null;
61742             var geometry = entity.geometry(graph);
61743             var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
61744
61745             if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
61746               return new validationIssue({
61747                 type: type,
61748                 subtype: 'vertex_as_point',
61749                 severity: 'warning',
61750                 message: function message(context) {
61751                   var entity = context.hasEntity(this.entityIds[0]);
61752                   return entity ? _t.html('issues.vertex_as_point.message', {
61753                     feature: utilDisplayLabel(entity, 'vertex')
61754                   }) : '';
61755                 },
61756                 reference: function showReference(selection) {
61757                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
61758                 },
61759                 entityIds: [entity.id]
61760               });
61761             } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
61762               return new validationIssue({
61763                 type: type,
61764                 subtype: 'point_as_vertex',
61765                 severity: 'warning',
61766                 message: function message(context) {
61767                   var entity = context.hasEntity(this.entityIds[0]);
61768                   return entity ? _t.html('issues.point_as_vertex.message', {
61769                     feature: utilDisplayLabel(entity, 'point')
61770                   }) : '';
61771                 },
61772                 reference: function showReference(selection) {
61773                   selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
61774                 },
61775                 entityIds: [entity.id],
61776                 dynamicFixes: function dynamicFixes(context) {
61777                   var entityId = this.entityIds[0];
61778                   var extractOnClick = null;
61779
61780                   if (!context.hasHiddenConnections(entityId)) {
61781                     extractOnClick = function extractOnClick(context) {
61782                       var entityId = this.issue.entityIds[0];
61783                       var action = actionExtract(entityId);
61784                       context.perform(action, _t('operations.extract.annotation', {
61785                         n: 1
61786                       })); // re-enter mode to trigger updates
61787
61788                       context.enter(modeSelect(context, [action.getExtractedNodeID()]));
61789                     };
61790                   }
61791
61792                   return [new validationIssueFix({
61793                     icon: 'iD-operation-extract',
61794                     title: _t.html('issues.fix.extract_point.title'),
61795                     onClick: extractOnClick
61796                   })];
61797                 }
61798               });
61799             }
61800
61801             return null;
61802           }
61803
61804           function unclosedMultipolygonPartIssues(entity, graph) {
61805             if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
61806             !entity.isComplete(graph)) return null;
61807             var sequences = osmJoinWays(entity.members, graph);
61808             var issues = [];
61809
61810             for (var i in sequences) {
61811               var sequence = sequences[i];
61812               if (!sequence.nodes) continue;
61813               var firstNode = sequence.nodes[0];
61814               var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
61815
61816               if (firstNode === lastNode) continue;
61817               var issue = new validationIssue({
61818                 type: type,
61819                 subtype: 'unclosed_multipolygon_part',
61820                 severity: 'warning',
61821                 message: function message(context) {
61822                   var entity = context.hasEntity(this.entityIds[0]);
61823                   return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
61824                     feature: utilDisplayLabel(entity, context.graph())
61825                   }) : '';
61826                 },
61827                 reference: showReference,
61828                 loc: sequence.nodes[0].loc,
61829                 entityIds: [entity.id],
61830                 hash: sequence.map(function (way) {
61831                   return way.id;
61832                 }).join()
61833               });
61834               issues.push(issue);
61835             }
61836
61837             return issues;
61838
61839             function showReference(selection) {
61840               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
61841             }
61842           }
61843
61844           var validation = function checkMismatchedGeometry(entity, graph) {
61845             var issues = [vertexTaggedAsPointIssue(entity, graph), lineTaggedAsAreaIssue(entity)];
61846             issues = issues.concat(unclosedMultipolygonPartIssues(entity, graph));
61847             return issues.filter(Boolean);
61848           };
61849
61850           validation.type = type;
61851           return validation;
61852         }
61853
61854         function validationMissingRole() {
61855           var type = 'missing_role';
61856
61857           var validation = function checkMissingRole(entity, graph) {
61858             var issues = [];
61859
61860             if (entity.type === 'way') {
61861               graph.parentRelations(entity).forEach(function (relation) {
61862                 if (!relation.isMultipolygon()) return;
61863                 var member = relation.memberById(entity.id);
61864
61865                 if (member && isMissingRole(member)) {
61866                   issues.push(makeIssue(entity, relation, member));
61867                 }
61868               });
61869             } else if (entity.type === 'relation' && entity.isMultipolygon()) {
61870               entity.indexedMembers().forEach(function (member) {
61871                 var way = graph.hasEntity(member.id);
61872
61873                 if (way && isMissingRole(member)) {
61874                   issues.push(makeIssue(way, entity, member));
61875                 }
61876               });
61877             }
61878
61879             return issues;
61880           };
61881
61882           function isMissingRole(member) {
61883             return !member.role || !member.role.trim().length;
61884           }
61885
61886           function makeIssue(way, relation, member) {
61887             return new validationIssue({
61888               type: type,
61889               severity: 'warning',
61890               message: function message(context) {
61891                 var member = context.hasEntity(this.entityIds[1]),
61892                     relation = context.hasEntity(this.entityIds[0]);
61893                 return member && relation ? _t.html('issues.missing_role.message', {
61894                   member: utilDisplayLabel(member, context.graph()),
61895                   relation: utilDisplayLabel(relation, context.graph())
61896                 }) : '';
61897               },
61898               reference: showReference,
61899               entityIds: [relation.id, way.id],
61900               data: {
61901                 member: member
61902               },
61903               hash: member.index.toString(),
61904               dynamicFixes: function dynamicFixes() {
61905                 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
61906                   icon: 'iD-operation-delete',
61907                   title: _t.html('issues.fix.remove_from_relation.title'),
61908                   onClick: function onClick(context) {
61909                     context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
61910                       n: 1
61911                     }));
61912                   }
61913                 })];
61914               }
61915             });
61916
61917             function showReference(selection) {
61918               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
61919             }
61920           }
61921
61922           function makeAddRoleFix(role) {
61923             return new validationIssueFix({
61924               title: _t.html('issues.fix.set_as_' + role + '.title'),
61925               onClick: function onClick(context) {
61926                 var oldMember = this.issue.data.member;
61927                 var member = {
61928                   id: this.issue.entityIds[1],
61929                   type: oldMember.type,
61930                   role: role
61931                 };
61932                 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
61933                   n: 1
61934                 }));
61935               }
61936             });
61937           }
61938
61939           validation.type = type;
61940           return validation;
61941         }
61942
61943         function validationMissingTag(context) {
61944           var type = 'missing_tag';
61945
61946           function hasDescriptiveTags(entity, graph) {
61947             var keys = Object.keys(entity.tags).filter(function (k) {
61948               if (k === 'area' || k === 'name') {
61949                 return false;
61950               } else {
61951                 return osmIsInterestingTag(k);
61952               }
61953             });
61954
61955             if (entity.type === 'relation' && keys.length === 1 && entity.tags.type === 'multipolygon') {
61956               // this relation's only interesting tag just says its a multipolygon,
61957               // which is not descriptive enough
61958               // It's okay for a simple multipolygon to have no descriptive tags
61959               // if its outer way has them (old model, see `outdated_tags.js`)
61960               return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
61961             }
61962
61963             return keys.length > 0;
61964           }
61965
61966           function isUnknownRoad(entity) {
61967             return entity.type === 'way' && entity.tags.highway === 'road';
61968           }
61969
61970           function isUntypedRelation(entity) {
61971             return entity.type === 'relation' && !entity.tags.type;
61972           }
61973
61974           var validation = function checkMissingTag(entity, graph) {
61975             var subtype;
61976             var osm = context.connection();
61977             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
61978
61979             if (!isUnloadedNode && // allow untagged nodes that are part of ways
61980             entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
61981             !entity.hasParentRelations(graph)) {
61982               if (Object.keys(entity.tags).length === 0) {
61983                 subtype = 'any';
61984               } else if (!hasDescriptiveTags(entity, graph)) {
61985                 subtype = 'descriptive';
61986               } else if (isUntypedRelation(entity)) {
61987                 subtype = 'relation_type';
61988               }
61989             } // flag an unknown road even if it's a member of a relation
61990
61991
61992             if (!subtype && isUnknownRoad(entity)) {
61993               subtype = 'highway_classification';
61994             }
61995
61996             if (!subtype) return [];
61997             var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
61998             var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
61999
62000             var canDelete = entity.version === undefined || entity.v !== undefined;
62001             var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
62002             return [new validationIssue({
62003               type: type,
62004               subtype: subtype,
62005               severity: severity,
62006               message: function message(context) {
62007                 var entity = context.hasEntity(this.entityIds[0]);
62008                 return entity ? _t.html('issues.' + messageID + '.message', {
62009                   feature: utilDisplayLabel(entity, context.graph())
62010                 }) : '';
62011               },
62012               reference: showReference,
62013               entityIds: [entity.id],
62014               dynamicFixes: function dynamicFixes(context) {
62015                 var fixes = [];
62016                 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
62017                 fixes.push(new validationIssueFix({
62018                   icon: 'iD-icon-search',
62019                   title: _t.html('issues.fix.' + selectFixType + '.title'),
62020                   onClick: function onClick(context) {
62021                     context.ui().sidebar.showPresetList();
62022                   }
62023                 }));
62024                 var deleteOnClick;
62025                 var id = this.entityIds[0];
62026                 var operation = operationDelete(context, [id]);
62027                 var disabledReasonID = operation.disabled();
62028
62029                 if (!disabledReasonID) {
62030                   deleteOnClick = function deleteOnClick(context) {
62031                     var id = this.issue.entityIds[0];
62032                     var operation = operationDelete(context, [id]);
62033
62034                     if (!operation.disabled()) {
62035                       operation();
62036                     }
62037                   };
62038                 }
62039
62040                 fixes.push(new validationIssueFix({
62041                   icon: 'iD-operation-delete',
62042                   title: _t.html('issues.fix.delete_feature.title'),
62043                   disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
62044                   onClick: deleteOnClick
62045                 }));
62046                 return fixes;
62047               }
62048             })];
62049
62050             function showReference(selection) {
62051               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
62052             }
62053           };
62054
62055           validation.type = type;
62056           return validation;
62057         }
62058
62059         var simplify = function simplify(str) {
62060           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());
62061         };
62062
62063         // {
62064         //   kvnd:        "amenity/fast_food|Thaï Express~(North America)",
62065         //   kvn:         "amenity/fast_food|Thaï Express",
62066         //   kv:          "amenity/fast_food",
62067         //   k:           "amenity",
62068         //   v:           "fast_food",
62069         //   n:           "Thaï Express",
62070         //   d:           "(North America)",
62071         //   nsimple:     "thaiexpress",
62072         //   kvnnsimple:  "amenity/fast_food|thaiexpress"
62073         // }
62074
62075         var to_parts = function to_parts(kvnd) {
62076           var parts = {};
62077           parts.kvnd = kvnd;
62078           var kvndparts = kvnd.split('~', 2);
62079           if (kvndparts.length > 1) parts.d = kvndparts[1];
62080           parts.kvn = kvndparts[0];
62081           var kvnparts = parts.kvn.split('|', 2);
62082           if (kvnparts.length > 1) parts.n = kvnparts[1];
62083           parts.kv = kvnparts[0];
62084           var kvparts = parts.kv.split('/', 2);
62085           parts.k = kvparts[0];
62086           parts.v = kvparts[1];
62087           parts.nsimple = simplify(parts.n);
62088           parts.kvnsimple = parts.kv + '|' + parts.nsimple;
62089           return parts;
62090         };
62091
62092         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"]};
62093         var require$$0 = {
62094         matchGroups: matchGroups
62095         };
62096
62097         var matchGroups$1 = require$$0.matchGroups;
62098
62099         var matcher$1 = function matcher() {
62100           var _warnings = []; // array of match conflict pairs
62101
62102           var _ambiguous = {};
62103           var _matchIndex = {};
62104           var matcher = {}; // Create an index of all the keys/simplenames for fast matching
62105
62106           matcher.buildMatchIndex = function (brands) {
62107             // two passes - once for primary names, once for secondary/alternate names
62108             Object.keys(brands).forEach(function (kvnd) {
62109               return insertNames(kvnd, 'primary');
62110             });
62111             Object.keys(brands).forEach(function (kvnd) {
62112               return insertNames(kvnd, 'secondary');
62113             });
62114
62115             function insertNames(kvnd, which) {
62116               var obj = brands[kvnd];
62117               var parts = to_parts(kvnd); // Exit early for ambiguous names in the second pass.
62118               // They were collected in the first pass and we don't gather alt names for them.
62119
62120               if (which === 'secondary' && parts.d) return;
62121
62122               if (obj.countryCodes) {
62123                 parts.countryCodes = obj.countryCodes.slice(); // copy
62124               }
62125
62126               var nomatches = obj.nomatch || [];
62127
62128               if (nomatches.some(function (s) {
62129                 return s === kvnd;
62130               })) {
62131                 console.log("WARNING match/nomatch conflict for ".concat(kvnd));
62132                 return;
62133               }
62134
62135               var match_kv = [parts.kv].concat(obj.matchTags || []).concat(["".concat(parts.k, "/yes"), "building/yes"]) // #3454 - match some generic tags
62136               .map(function (s) {
62137                 return s.toLowerCase();
62138               });
62139               var match_nsimple = [];
62140
62141               if (which === 'primary') {
62142                 match_nsimple = [parts.n].concat(obj.matchNames || []).concat(obj.tags.official_name || []) // #2732 - match alternate names
62143                 .map(simplify);
62144               } else if (which === 'secondary') {
62145                 match_nsimple = [].concat(obj.tags.alt_name || []) // #2732 - match alternate names
62146                 .concat(obj.tags.short_name || []) // #2732 - match alternate names
62147                 .map(simplify);
62148               }
62149
62150               if (!match_nsimple.length) return; // nothing to do
62151
62152               match_kv.forEach(function (kv) {
62153                 match_nsimple.forEach(function (nsimple) {
62154                   if (parts.d) {
62155                     // Known ambiguous names with disambiguation string ~(USA) / ~(Canada)
62156                     // FIXME: Name collisions will overwrite the initial entry (ok for now)
62157                     if (!_ambiguous[kv]) _ambiguous[kv] = {};
62158                     _ambiguous[kv][nsimple] = parts;
62159                   } else {
62160                     // Names we mostly expect to be unique..
62161                     if (!_matchIndex[kv]) _matchIndex[kv] = {};
62162                     var m = _matchIndex[kv][nsimple];
62163
62164                     if (m) {
62165                       // There already is a match for this name, skip it
62166                       // Warn if we detect collisions in a primary name.
62167                       // Skip warning if a secondary name or a generic `*=yes` tag - #2972 / #3454
62168                       if (which === 'primary' && !/\/yes$/.test(kv)) {
62169                         _warnings.push([m.kvnd, "".concat(kvnd, " (").concat(kv, "/").concat(nsimple, ")")]);
62170                       }
62171                     } else {
62172                       _matchIndex[kv][nsimple] = parts; // insert
62173                     }
62174                   }
62175                 });
62176               });
62177             }
62178           }; // pass a `key`, `value`, `name` and return the best match,
62179           // `countryCode` optional (if supplied, must match that too)
62180
62181
62182           matcher.matchKVN = function (key, value, name, countryCode) {
62183             return matcher.matchParts(to_parts("".concat(key, "/").concat(value, "|").concat(name)), countryCode);
62184           }; // pass a parts object and return the best match,
62185           // `countryCode` optional (if supplied, must match that too)
62186
62187
62188           matcher.matchParts = function (parts, countryCode) {
62189             var match = null;
62190             var inGroup = false; // fixme: we currently return a single match for ambiguous
62191
62192             match = _ambiguous[parts.kv] && _ambiguous[parts.kv][parts.nsimple];
62193             if (match && matchesCountryCode(match)) return match; // try to return an exact match
62194
62195             match = _matchIndex[parts.kv] && _matchIndex[parts.kv][parts.nsimple];
62196             if (match && matchesCountryCode(match)) return match; // look in match groups
62197
62198             for (var mg in matchGroups$1) {
62199               var matchGroup = matchGroups$1[mg];
62200               match = null;
62201               inGroup = false;
62202
62203               for (var i = 0; i < matchGroup.length; i++) {
62204                 var otherkv = matchGroup[i].toLowerCase();
62205
62206                 if (!inGroup) {
62207                   inGroup = otherkv === parts.kv;
62208                 }
62209
62210                 if (!match) {
62211                   // fixme: we currently return a single match for ambiguous
62212                   match = _ambiguous[otherkv] && _ambiguous[otherkv][parts.nsimple];
62213                 }
62214
62215                 if (!match) {
62216                   match = _matchIndex[otherkv] && _matchIndex[otherkv][parts.nsimple];
62217                 }
62218
62219                 if (match && !matchesCountryCode(match)) {
62220                   match = null;
62221                 }
62222
62223                 if (inGroup && match) {
62224                   return match;
62225                 }
62226               }
62227             }
62228
62229             return null;
62230
62231             function matchesCountryCode(match) {
62232               if (!countryCode) return true;
62233               if (!match.countryCodes) return true;
62234               return match.countryCodes.indexOf(countryCode) !== -1;
62235             }
62236           };
62237
62238           matcher.getWarnings = function () {
62239             return _warnings;
62240           };
62241
62242           return matcher;
62243         };
62244
62245         var fromCharCode = String.fromCharCode;
62246         var nativeFromCodePoint = String.fromCodePoint;
62247
62248         // length should be 1, old FF problem
62249         var INCORRECT_LENGTH = !!nativeFromCodePoint && nativeFromCodePoint.length != 1;
62250
62251         // `String.fromCodePoint` method
62252         // https://tc39.github.io/ecma262/#sec-string.fromcodepoint
62253         _export({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
62254           fromCodePoint: function fromCodePoint(x) { // eslint-disable-line no-unused-vars
62255             var elements = [];
62256             var length = arguments.length;
62257             var i = 0;
62258             var code;
62259             while (length > i) {
62260               code = +arguments[i++];
62261               if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
62262               elements.push(code < 0x10000
62263                 ? fromCharCode(code)
62264                 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
62265               );
62266             } return elements.join('');
62267           }
62268         });
62269
62270         var quickselect$2 = createCommonjsModule(function (module, exports) {
62271           (function (global, factory) {
62272              module.exports = factory() ;
62273           })(commonjsGlobal, function () {
62274
62275             function quickselect(arr, k, left, right, compare) {
62276               quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
62277             }
62278
62279             function quickselectStep(arr, k, left, right, compare) {
62280               while (right > left) {
62281                 if (right - left > 600) {
62282                   var n = right - left + 1;
62283                   var m = k - left + 1;
62284                   var z = Math.log(n);
62285                   var s = 0.5 * Math.exp(2 * z / 3);
62286                   var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
62287                   var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
62288                   var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
62289                   quickselectStep(arr, k, newLeft, newRight, compare);
62290                 }
62291
62292                 var t = arr[k];
62293                 var i = left;
62294                 var j = right;
62295                 swap(arr, left, k);
62296                 if (compare(arr[right], t) > 0) swap(arr, left, right);
62297
62298                 while (i < j) {
62299                   swap(arr, i, j);
62300                   i++;
62301                   j--;
62302
62303                   while (compare(arr[i], t) < 0) {
62304                     i++;
62305                   }
62306
62307                   while (compare(arr[j], t) > 0) {
62308                     j--;
62309                   }
62310                 }
62311
62312                 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
62313                   j++;
62314                   swap(arr, j, right);
62315                 }
62316                 if (j <= k) left = j + 1;
62317                 if (k <= j) right = j - 1;
62318               }
62319             }
62320
62321             function swap(arr, i, j) {
62322               var tmp = arr[i];
62323               arr[i] = arr[j];
62324               arr[j] = tmp;
62325             }
62326
62327             function defaultCompare(a, b) {
62328               return a < b ? -1 : a > b ? 1 : 0;
62329             }
62330
62331             return quickselect;
62332           });
62333         });
62334
62335         var rbush_1 = rbush;
62336         var _default$2 = rbush;
62337
62338         function rbush(maxEntries, format) {
62339           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
62340
62341           this._maxEntries = Math.max(4, maxEntries || 9);
62342           this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
62343
62344           if (format) {
62345             this._initFormat(format);
62346           }
62347
62348           this.clear();
62349         }
62350
62351         rbush.prototype = {
62352           all: function all() {
62353             return this._all(this.data, []);
62354           },
62355           search: function search(bbox) {
62356             var node = this.data,
62357                 result = [],
62358                 toBBox = this.toBBox;
62359             if (!intersects$1(bbox, node)) return result;
62360             var nodesToSearch = [],
62361                 i,
62362                 len,
62363                 child,
62364                 childBBox;
62365
62366             while (node) {
62367               for (i = 0, len = node.children.length; i < len; i++) {
62368                 child = node.children[i];
62369                 childBBox = node.leaf ? toBBox(child) : child;
62370
62371                 if (intersects$1(bbox, childBBox)) {
62372                   if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
62373                 }
62374               }
62375
62376               node = nodesToSearch.pop();
62377             }
62378
62379             return result;
62380           },
62381           collides: function collides(bbox) {
62382             var node = this.data,
62383                 toBBox = this.toBBox;
62384             if (!intersects$1(bbox, node)) return false;
62385             var nodesToSearch = [],
62386                 i,
62387                 len,
62388                 child,
62389                 childBBox;
62390
62391             while (node) {
62392               for (i = 0, len = node.children.length; i < len; i++) {
62393                 child = node.children[i];
62394                 childBBox = node.leaf ? toBBox(child) : child;
62395
62396                 if (intersects$1(bbox, childBBox)) {
62397                   if (node.leaf || contains$1(bbox, childBBox)) return true;
62398                   nodesToSearch.push(child);
62399                 }
62400               }
62401
62402               node = nodesToSearch.pop();
62403             }
62404
62405             return false;
62406           },
62407           load: function load(data) {
62408             if (!(data && data.length)) return this;
62409
62410             if (data.length < this._minEntries) {
62411               for (var i = 0, len = data.length; i < len; i++) {
62412                 this.insert(data[i]);
62413               }
62414
62415               return this;
62416             } // recursively build the tree with the given data from scratch using OMT algorithm
62417
62418
62419             var node = this._build(data.slice(), 0, data.length - 1, 0);
62420
62421             if (!this.data.children.length) {
62422               // save as is if tree is empty
62423               this.data = node;
62424             } else if (this.data.height === node.height) {
62425               // split root if trees have the same height
62426               this._splitRoot(this.data, node);
62427             } else {
62428               if (this.data.height < node.height) {
62429                 // swap trees if inserted one is bigger
62430                 var tmpNode = this.data;
62431                 this.data = node;
62432                 node = tmpNode;
62433               } // insert the small tree into the large tree at appropriate level
62434
62435
62436               this._insert(node, this.data.height - node.height - 1, true);
62437             }
62438
62439             return this;
62440           },
62441           insert: function insert(item) {
62442             if (item) this._insert(item, this.data.height - 1);
62443             return this;
62444           },
62445           clear: function clear() {
62446             this.data = createNode$1([]);
62447             return this;
62448           },
62449           remove: function remove(item, equalsFn) {
62450             if (!item) return this;
62451             var node = this.data,
62452                 bbox = this.toBBox(item),
62453                 path = [],
62454                 indexes = [],
62455                 i,
62456                 parent,
62457                 index,
62458                 goingUp; // depth-first iterative tree traversal
62459
62460             while (node || path.length) {
62461               if (!node) {
62462                 // go up
62463                 node = path.pop();
62464                 parent = path[path.length - 1];
62465                 i = indexes.pop();
62466                 goingUp = true;
62467               }
62468
62469               if (node.leaf) {
62470                 // check current node
62471                 index = findItem$1(item, node.children, equalsFn);
62472
62473                 if (index !== -1) {
62474                   // item found, remove the item and condense tree upwards
62475                   node.children.splice(index, 1);
62476                   path.push(node);
62477
62478                   this._condense(path);
62479
62480                   return this;
62481                 }
62482               }
62483
62484               if (!goingUp && !node.leaf && contains$1(node, bbox)) {
62485                 // go down
62486                 path.push(node);
62487                 indexes.push(i);
62488                 i = 0;
62489                 parent = node;
62490                 node = node.children[0];
62491               } else if (parent) {
62492                 // go right
62493                 i++;
62494                 node = parent.children[i];
62495                 goingUp = false;
62496               } else node = null; // nothing found
62497
62498             }
62499
62500             return this;
62501           },
62502           toBBox: function toBBox(item) {
62503             return item;
62504           },
62505           compareMinX: compareNodeMinX$1,
62506           compareMinY: compareNodeMinY$1,
62507           toJSON: function toJSON() {
62508             return this.data;
62509           },
62510           fromJSON: function fromJSON(data) {
62511             this.data = data;
62512             return this;
62513           },
62514           _all: function _all(node, result) {
62515             var nodesToSearch = [];
62516
62517             while (node) {
62518               if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
62519               node = nodesToSearch.pop();
62520             }
62521
62522             return result;
62523           },
62524           _build: function _build(items, left, right, height) {
62525             var N = right - left + 1,
62526                 M = this._maxEntries,
62527                 node;
62528
62529             if (N <= M) {
62530               // reached leaf level; return leaf
62531               node = createNode$1(items.slice(left, right + 1));
62532               calcBBox$1(node, this.toBBox);
62533               return node;
62534             }
62535
62536             if (!height) {
62537               // target height of the bulk-loaded tree
62538               height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
62539
62540               M = Math.ceil(N / Math.pow(M, height - 1));
62541             }
62542
62543             node = createNode$1([]);
62544             node.leaf = false;
62545             node.height = height; // split the items into M mostly square tiles
62546
62547             var N2 = Math.ceil(N / M),
62548                 N1 = N2 * Math.ceil(Math.sqrt(M)),
62549                 i,
62550                 j,
62551                 right2,
62552                 right3;
62553             multiSelect$1(items, left, right, N1, this.compareMinX);
62554
62555             for (i = left; i <= right; i += N1) {
62556               right2 = Math.min(i + N1 - 1, right);
62557               multiSelect$1(items, i, right2, N2, this.compareMinY);
62558
62559               for (j = i; j <= right2; j += N2) {
62560                 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
62561
62562                 node.children.push(this._build(items, j, right3, height - 1));
62563               }
62564             }
62565
62566             calcBBox$1(node, this.toBBox);
62567             return node;
62568           },
62569           _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
62570             var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
62571
62572             while (true) {
62573               path.push(node);
62574               if (node.leaf || path.length - 1 === level) break;
62575               minArea = minEnlargement = Infinity;
62576
62577               for (i = 0, len = node.children.length; i < len; i++) {
62578                 child = node.children[i];
62579                 area = bboxArea$1(child);
62580                 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
62581
62582                 if (enlargement < minEnlargement) {
62583                   minEnlargement = enlargement;
62584                   minArea = area < minArea ? area : minArea;
62585                   targetNode = child;
62586                 } else if (enlargement === minEnlargement) {
62587                   // otherwise choose one with the smallest area
62588                   if (area < minArea) {
62589                     minArea = area;
62590                     targetNode = child;
62591                   }
62592                 }
62593               }
62594
62595               node = targetNode || node.children[0];
62596             }
62597
62598             return node;
62599           },
62600           _insert: function _insert(item, level, isNode) {
62601             var toBBox = this.toBBox,
62602                 bbox = isNode ? item : toBBox(item),
62603                 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
62604
62605             var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
62606
62607
62608             node.children.push(item);
62609             extend$3(node, bbox); // split on node overflow; propagate upwards if necessary
62610
62611             while (level >= 0) {
62612               if (insertPath[level].children.length > this._maxEntries) {
62613                 this._split(insertPath, level);
62614
62615                 level--;
62616               } else break;
62617             } // adjust bboxes along the insertion path
62618
62619
62620             this._adjustParentBBoxes(bbox, insertPath, level);
62621           },
62622           // split overflowed node into two
62623           _split: function _split(insertPath, level) {
62624             var node = insertPath[level],
62625                 M = node.children.length,
62626                 m = this._minEntries;
62627
62628             this._chooseSplitAxis(node, m, M);
62629
62630             var splitIndex = this._chooseSplitIndex(node, m, M);
62631
62632             var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
62633             newNode.height = node.height;
62634             newNode.leaf = node.leaf;
62635             calcBBox$1(node, this.toBBox);
62636             calcBBox$1(newNode, this.toBBox);
62637             if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
62638           },
62639           _splitRoot: function _splitRoot(node, newNode) {
62640             // split root node
62641             this.data = createNode$1([node, newNode]);
62642             this.data.height = node.height + 1;
62643             this.data.leaf = false;
62644             calcBBox$1(this.data, this.toBBox);
62645           },
62646           _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
62647             var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
62648             minOverlap = minArea = Infinity;
62649
62650             for (i = m; i <= M - m; i++) {
62651               bbox1 = distBBox$1(node, 0, i, this.toBBox);
62652               bbox2 = distBBox$1(node, i, M, this.toBBox);
62653               overlap = intersectionArea$1(bbox1, bbox2);
62654               area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
62655
62656               if (overlap < minOverlap) {
62657                 minOverlap = overlap;
62658                 index = i;
62659                 minArea = area < minArea ? area : minArea;
62660               } else if (overlap === minOverlap) {
62661                 // otherwise choose distribution with minimum area
62662                 if (area < minArea) {
62663                   minArea = area;
62664                   index = i;
62665                 }
62666               }
62667             }
62668
62669             return index;
62670           },
62671           // sorts node children by the best axis for split
62672           _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
62673             var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
62674                 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
62675                 xMargin = this._allDistMargin(node, m, M, compareMinX),
62676                 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
62677             // otherwise it's already sorted by minY
62678
62679
62680             if (xMargin < yMargin) node.children.sort(compareMinX);
62681           },
62682           // total margin of all possible split distributions where each node is at least m full
62683           _allDistMargin: function _allDistMargin(node, m, M, compare) {
62684             node.children.sort(compare);
62685             var toBBox = this.toBBox,
62686                 leftBBox = distBBox$1(node, 0, m, toBBox),
62687                 rightBBox = distBBox$1(node, M - m, M, toBBox),
62688                 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
62689                 i,
62690                 child;
62691
62692             for (i = m; i < M - m; i++) {
62693               child = node.children[i];
62694               extend$3(leftBBox, node.leaf ? toBBox(child) : child);
62695               margin += bboxMargin$1(leftBBox);
62696             }
62697
62698             for (i = M - m - 1; i >= m; i--) {
62699               child = node.children[i];
62700               extend$3(rightBBox, node.leaf ? toBBox(child) : child);
62701               margin += bboxMargin$1(rightBBox);
62702             }
62703
62704             return margin;
62705           },
62706           _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
62707             // adjust bboxes along the given tree path
62708             for (var i = level; i >= 0; i--) {
62709               extend$3(path[i], bbox);
62710             }
62711           },
62712           _condense: function _condense(path) {
62713             // go through the path, removing empty nodes and updating bboxes
62714             for (var i = path.length - 1, siblings; i >= 0; i--) {
62715               if (path[i].children.length === 0) {
62716                 if (i > 0) {
62717                   siblings = path[i - 1].children;
62718                   siblings.splice(siblings.indexOf(path[i]), 1);
62719                 } else this.clear();
62720               } else calcBBox$1(path[i], this.toBBox);
62721             }
62722           },
62723           _initFormat: function _initFormat(format) {
62724             // data format (minX, minY, maxX, maxY accessors)
62725             // uses eval-type function compilation instead of just accepting a toBBox function
62726             // because the algorithms are very sensitive to sorting functions performance,
62727             // so they should be dead simple and without inner calls
62728             var compareArr = ['return a', ' - b', ';'];
62729             this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
62730             this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
62731             this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
62732           }
62733         };
62734
62735         function findItem$1(item, items, equalsFn) {
62736           if (!equalsFn) return items.indexOf(item);
62737
62738           for (var i = 0; i < items.length; i++) {
62739             if (equalsFn(item, items[i])) return i;
62740           }
62741
62742           return -1;
62743         } // calculate node's bbox from bboxes of its children
62744
62745
62746         function calcBBox$1(node, toBBox) {
62747           distBBox$1(node, 0, node.children.length, toBBox, node);
62748         } // min bounding rectangle of node children from k to p-1
62749
62750
62751         function distBBox$1(node, k, p, toBBox, destNode) {
62752           if (!destNode) destNode = createNode$1(null);
62753           destNode.minX = Infinity;
62754           destNode.minY = Infinity;
62755           destNode.maxX = -Infinity;
62756           destNode.maxY = -Infinity;
62757
62758           for (var i = k, child; i < p; i++) {
62759             child = node.children[i];
62760             extend$3(destNode, node.leaf ? toBBox(child) : child);
62761           }
62762
62763           return destNode;
62764         }
62765
62766         function extend$3(a, b) {
62767           a.minX = Math.min(a.minX, b.minX);
62768           a.minY = Math.min(a.minY, b.minY);
62769           a.maxX = Math.max(a.maxX, b.maxX);
62770           a.maxY = Math.max(a.maxY, b.maxY);
62771           return a;
62772         }
62773
62774         function compareNodeMinX$1(a, b) {
62775           return a.minX - b.minX;
62776         }
62777
62778         function compareNodeMinY$1(a, b) {
62779           return a.minY - b.minY;
62780         }
62781
62782         function bboxArea$1(a) {
62783           return (a.maxX - a.minX) * (a.maxY - a.minY);
62784         }
62785
62786         function bboxMargin$1(a) {
62787           return a.maxX - a.minX + (a.maxY - a.minY);
62788         }
62789
62790         function enlargedArea$1(a, b) {
62791           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));
62792         }
62793
62794         function intersectionArea$1(a, b) {
62795           var minX = Math.max(a.minX, b.minX),
62796               minY = Math.max(a.minY, b.minY),
62797               maxX = Math.min(a.maxX, b.maxX),
62798               maxY = Math.min(a.maxY, b.maxY);
62799           return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
62800         }
62801
62802         function contains$1(a, b) {
62803           return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
62804         }
62805
62806         function intersects$1(a, b) {
62807           return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
62808         }
62809
62810         function createNode$1(children) {
62811           return {
62812             children: children,
62813             height: 1,
62814             leaf: true,
62815             minX: Infinity,
62816             minY: Infinity,
62817             maxX: -Infinity,
62818             maxY: -Infinity
62819           };
62820         } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
62821         // combines selection algorithm with binary divide & conquer approach
62822
62823
62824         function multiSelect$1(arr, left, right, n, compare) {
62825           var stack = [left, right],
62826               mid;
62827
62828           while (stack.length) {
62829             right = stack.pop();
62830             left = stack.pop();
62831             if (right - left <= n) continue;
62832             mid = left + Math.ceil((right - left) / n / 2) * n;
62833             quickselect$2(arr, mid, left, right, compare);
62834             stack.push(left, mid, mid, right);
62835           }
62836         }
62837         rbush_1["default"] = _default$2;
62838
62839         var lineclip_1$1 = lineclip$1;
62840         lineclip$1.polyline = lineclip$1;
62841         lineclip$1.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
62842         // handle polylines rather than just segments
62843
62844         function lineclip$1(points, bbox, result) {
62845           var len = points.length,
62846               codeA = bitCode$1(points[0], bbox),
62847               part = [],
62848               i,
62849               a,
62850               b,
62851               codeB,
62852               lastCode;
62853           if (!result) result = [];
62854
62855           for (i = 1; i < len; i++) {
62856             a = points[i - 1];
62857             b = points[i];
62858             codeB = lastCode = bitCode$1(b, bbox);
62859
62860             while (true) {
62861               if (!(codeA | codeB)) {
62862                 // accept
62863                 part.push(a);
62864
62865                 if (codeB !== lastCode) {
62866                   // segment went outside
62867                   part.push(b);
62868
62869                   if (i < len - 1) {
62870                     // start a new line
62871                     result.push(part);
62872                     part = [];
62873                   }
62874                 } else if (i === len - 1) {
62875                   part.push(b);
62876                 }
62877
62878                 break;
62879               } else if (codeA & codeB) {
62880                 // trivial reject
62881                 break;
62882               } else if (codeA) {
62883                 // a outside, intersect with clip edge
62884                 a = intersect$1(a, b, codeA, bbox);
62885                 codeA = bitCode$1(a, bbox);
62886               } else {
62887                 // b outside
62888                 b = intersect$1(a, b, codeB, bbox);
62889                 codeB = bitCode$1(b, bbox);
62890               }
62891             }
62892
62893             codeA = lastCode;
62894           }
62895
62896           if (part.length) result.push(part);
62897           return result;
62898         } // Sutherland-Hodgeman polygon clipping algorithm
62899
62900
62901         function polygonclip$1(points, bbox) {
62902           var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
62903
62904           for (edge = 1; edge <= 8; edge *= 2) {
62905             result = [];
62906             prev = points[points.length - 1];
62907             prevInside = !(bitCode$1(prev, bbox) & edge);
62908
62909             for (i = 0; i < points.length; i++) {
62910               p = points[i];
62911               inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
62912
62913               if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
62914               if (inside) result.push(p); // add a point if it's inside
62915
62916               prev = p;
62917               prevInside = inside;
62918             }
62919
62920             points = result;
62921             if (!points.length) break;
62922           }
62923
62924           return result;
62925         } // intersect a segment against one of the 4 lines that make up the bbox
62926
62927
62928         function intersect$1(a, b, edge, bbox) {
62929           return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
62930           edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
62931           edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
62932           edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
62933           null;
62934         } // bit code reflects the point position relative to the bbox:
62935         //         left  mid  right
62936         //    top  1001  1000  1010
62937         //    mid  0001  0000  0010
62938         // bottom  0101  0100  0110
62939
62940
62941         function bitCode$1(p, bbox) {
62942           var code = 0;
62943           if (p[0] < bbox[0]) code |= 1; // left
62944           else if (p[0] > bbox[2]) code |= 2; // right
62945
62946           if (p[1] < bbox[1]) code |= 4; // bottom
62947           else if (p[1] > bbox[3]) code |= 8; // top
62948
62949           return code;
62950         }
62951
62952         var whichPolygon_1 = whichPolygon;
62953
62954         function whichPolygon(data) {
62955           var bboxes = [];
62956
62957           for (var i = 0; i < data.features.length; i++) {
62958             var feature = data.features[i];
62959             var coords = feature.geometry.coordinates;
62960
62961             if (feature.geometry.type === 'Polygon') {
62962               bboxes.push(treeItem(coords, feature.properties));
62963             } else if (feature.geometry.type === 'MultiPolygon') {
62964               for (var j = 0; j < coords.length; j++) {
62965                 bboxes.push(treeItem(coords[j], feature.properties));
62966               }
62967             }
62968           }
62969
62970           var tree = rbush_1().load(bboxes);
62971
62972           function query(p, multi) {
62973             var output = [],
62974                 result = tree.search({
62975               minX: p[0],
62976               minY: p[1],
62977               maxX: p[0],
62978               maxY: p[1]
62979             });
62980
62981             for (var i = 0; i < result.length; i++) {
62982               if (insidePolygon(result[i].coords, p)) {
62983                 if (multi) output.push(result[i].props);else return result[i].props;
62984               }
62985             }
62986
62987             return multi && output.length ? output : null;
62988           }
62989
62990           query.tree = tree;
62991
62992           query.bbox = function queryBBox(bbox) {
62993             var output = [];
62994             var result = tree.search({
62995               minX: bbox[0],
62996               minY: bbox[1],
62997               maxX: bbox[2],
62998               maxY: bbox[3]
62999             });
63000
63001             for (var i = 0; i < result.length; i++) {
63002               if (polygonIntersectsBBox(result[i].coords, bbox)) {
63003                 output.push(result[i].props);
63004               }
63005             }
63006
63007             return output;
63008           };
63009
63010           return query;
63011         }
63012
63013         function polygonIntersectsBBox(polygon, bbox) {
63014           var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
63015           if (insidePolygon(polygon, bboxCenter)) return true;
63016
63017           for (var i = 0; i < polygon.length; i++) {
63018             if (lineclip_1$1(polygon[i], bbox).length > 0) return true;
63019           }
63020
63021           return false;
63022         } // ray casting algorithm for detecting if point is in polygon
63023
63024
63025         function insidePolygon(rings, p) {
63026           var inside = false;
63027
63028           for (var i = 0, len = rings.length; i < len; i++) {
63029             var ring = rings[i];
63030
63031             for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
63032               if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
63033             }
63034           }
63035
63036           return inside;
63037         }
63038
63039         function rayIntersect(p, p1, p2) {
63040           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];
63041         }
63042
63043         function treeItem(coords, props) {
63044           var item = {
63045             minX: Infinity,
63046             minY: Infinity,
63047             maxX: -Infinity,
63048             maxY: -Infinity,
63049             coords: coords,
63050             props: props
63051           };
63052
63053           for (var i = 0; i < coords[0].length; i++) {
63054             var p = coords[0][i];
63055             item.minX = Math.min(item.minX, p[0]);
63056             item.minY = Math.min(item.minY, p[1]);
63057             item.maxX = Math.max(item.maxX, p[0]);
63058             item.maxY = Math.max(item.maxY, p[1]);
63059           }
63060
63061           return item;
63062         }
63063
63064         var type = "FeatureCollection";
63065         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]]]]}}];
63066         var rawBorders = {
63067         type: type,
63068         features: features
63069         };
63070
63071         var borders = rawBorders;
63072         var whichPolygonGetter = {};
63073         var featuresByCode = {};
63074         var idFilterRegex = /\bThe\b|\bthe\b|\band\b|\bof\b|[-_ .,()&[\]/]/g;
63075         var levels = ['subterritory', 'territory', 'country', 'intermediateRegion', 'subregion', 'region', 'union', 'world'];
63076         loadDerivedDataAndCaches(borders);
63077
63078         function loadDerivedDataAndCaches(borders) {
63079           var identifierProps = ['iso1A2', 'iso1A3', 'm49', 'wikidata', 'emojiFlag', 'nameEn'];
63080           var geometryFeatures = [];
63081
63082           for (var i in borders.features) {
63083             var _feature = borders.features[i];
63084             _feature.properties.id = _feature.properties.iso1A2 || _feature.properties.m49;
63085             loadM49(_feature);
63086             loadIsoStatus(_feature);
63087             loadLevel(_feature);
63088             loadGroups(_feature);
63089             loadRoadSpeedUnit(_feature);
63090             loadDriveSide(_feature);
63091             loadFlag(_feature);
63092             cacheFeatureByIDs(_feature);
63093             if (_feature.geometry) geometryFeatures.push(_feature);
63094           }
63095
63096           for (var _i in borders.features) {
63097             var _feature2 = borders.features[_i];
63098
63099             _feature2.properties.groups.sort(function (groupID1, groupID2) {
63100               return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
63101             });
63102
63103             loadMembersForGroupsOf(_feature2);
63104           }
63105
63106           var geometryOnlyCollection = {
63107             type: 'RegionFeatureCollection',
63108             features: geometryFeatures
63109           };
63110           whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
63111
63112           function loadGroups(feature) {
63113             var props = feature.properties;
63114
63115             if (!props.groups) {
63116               props.groups = [];
63117             }
63118
63119             if (props.country) {
63120               props.groups.push(props.country);
63121             }
63122
63123             if (props.m49 !== '001') {
63124               props.groups.push('001');
63125             }
63126           }
63127
63128           function loadM49(feature) {
63129             var props = feature.properties;
63130
63131             if (!props.m49 && props.iso1N3) {
63132               props.m49 = props.iso1N3;
63133             }
63134           }
63135
63136           function loadIsoStatus(feature) {
63137             var props = feature.properties;
63138
63139             if (!props.isoStatus && props.iso1A2) {
63140               props.isoStatus = 'official';
63141             }
63142           }
63143
63144           function loadLevel(feature) {
63145             var props = feature.properties;
63146             if (props.level) return;
63147
63148             if (!props.country) {
63149               props.level = 'country';
63150             } else if (props.isoStatus === 'official') {
63151               props.level = 'territory';
63152             } else {
63153               props.level = 'subterritory';
63154             }
63155           }
63156
63157           function loadRoadSpeedUnit(feature) {
63158             var props = feature.properties;
63159
63160             if (props.roadSpeedUnit === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
63161               props.roadSpeedUnit = 'km/h';
63162             }
63163           }
63164
63165           function loadDriveSide(feature) {
63166             var props = feature.properties;
63167
63168             if (props.driveSide === undefined && props.iso1A2 && props.iso1A2 !== 'EU') {
63169               props.driveSide = 'right';
63170             }
63171           }
63172
63173           function loadFlag(feature) {
63174             if (!feature.properties.iso1A2) return;
63175             var flag = feature.properties.iso1A2.replace(/./g, function (_char) {
63176               return String.fromCodePoint(_char.charCodeAt(0) + 127397);
63177             });
63178             feature.properties.emojiFlag = flag;
63179           }
63180
63181           function loadMembersForGroupsOf(feature) {
63182             var featureID = feature.properties.id;
63183             var standardizedGroupIDs = [];
63184
63185             for (var j in feature.properties.groups) {
63186               var groupID = feature.properties.groups[j];
63187               var groupFeature = featuresByCode[groupID];
63188               standardizedGroupIDs.push(groupFeature.properties.id);
63189
63190               if (groupFeature.properties.members) {
63191                 groupFeature.properties.members.push(featureID);
63192               } else {
63193                 groupFeature.properties.members = [featureID];
63194               }
63195             }
63196
63197             feature.properties.groups = standardizedGroupIDs;
63198           }
63199
63200           function cacheFeatureByIDs(feature) {
63201             for (var k in identifierProps) {
63202               var prop = identifierProps[k];
63203               var id = prop && feature.properties[prop];
63204
63205               if (id) {
63206                 id = id.replace(idFilterRegex, '').toUpperCase();
63207                 featuresByCode[id] = feature;
63208               }
63209             }
63210
63211             if (feature.properties.aliases) {
63212               for (var j in feature.properties.aliases) {
63213                 var alias = feature.properties.aliases[j].replace(idFilterRegex, '').toUpperCase();
63214                 featuresByCode[alias] = feature;
63215               }
63216             }
63217           }
63218         }
63219
63220         function locArray(loc) {
63221           if (Array.isArray(loc)) {
63222             return loc;
63223           } else if (loc.coordinates) {
63224             return loc.coordinates;
63225           }
63226
63227           return loc.geometry.coordinates;
63228         }
63229
63230         function smallestFeature(loc) {
63231           var query = locArray(loc);
63232           var featureProperties = whichPolygonGetter(query);
63233           if (!featureProperties) return null;
63234           return featuresByCode[featureProperties.id];
63235         }
63236
63237         function countryFeature(loc) {
63238           var feature = smallestFeature(loc);
63239           if (!feature) return null;
63240           var countryCode = feature.properties.country || feature.properties.iso1A2;
63241           return featuresByCode[countryCode];
63242         }
63243
63244         function featureForLoc(loc, opts) {
63245           if (opts && opts.level && opts.level !== 'country') {
63246             var features = featuresContaining(loc);
63247             var targetLevel = opts.level;
63248             var targetLevelIndex = levels.indexOf(targetLevel);
63249             if (targetLevelIndex === -1) return null;
63250
63251             for (var i in features) {
63252               var _feature3 = features[i];
63253
63254               if (_feature3.properties.level === targetLevel || levels.indexOf(_feature3.properties.level) > targetLevelIndex) {
63255                 return _feature3;
63256               }
63257             }
63258
63259             return null;
63260           }
63261
63262           return countryFeature(loc);
63263         }
63264
63265         function featureForID(id) {
63266           var stringID;
63267
63268           if (typeof id === 'number') {
63269             stringID = id.toString();
63270
63271             if (stringID.length === 1) {
63272               stringID = '00' + stringID;
63273             } else if (stringID.length === 2) {
63274               stringID = '0' + stringID;
63275             }
63276           } else {
63277             stringID = id.replace(idFilterRegex, '').toUpperCase();
63278           }
63279
63280           return featuresByCode[stringID] || null;
63281         }
63282
63283         function smallestOrMatchingFeature(query) {
63284           if (_typeof(query) === 'object') {
63285             return smallestFeature(query);
63286           }
63287
63288           return featureForID(query);
63289         }
63290
63291         function feature(query, opts) {
63292           if (_typeof(query) === 'object') {
63293             return featureForLoc(query, opts);
63294           }
63295
63296           return featureForID(query);
63297         }
63298         function iso1A2Code(query, opts) {
63299           var match = feature(query, opts);
63300           if (!match) return null;
63301           return match.properties.iso1A2 || null;
63302         }
63303         function featuresContaining(query, strict) {
63304           var feature = smallestOrMatchingFeature(query);
63305           if (!feature) return [];
63306           var features = [];
63307
63308           if (!strict || _typeof(query) === 'object') {
63309             features.push(feature);
63310           }
63311
63312           var properties = feature.properties;
63313
63314           for (var i in properties.groups) {
63315             var groupID = properties.groups[i];
63316             features.push(featuresByCode[groupID]);
63317           }
63318
63319           return features;
63320         }
63321         function roadSpeedUnit(query) {
63322           var feature = smallestOrMatchingFeature(query);
63323           return feature && feature.properties.roadSpeedUnit || null;
63324         }
63325
63326         var _dataDeprecated;
63327
63328         var _nsi;
63329
63330         function validationOutdatedTags() {
63331           var type = 'outdated_tags';
63332           var nsiKeys = ['amenity', 'shop', 'tourism', 'leisure', 'office']; // A concern here in switching to async data means that `_dataDeprecated`
63333           // and `_nsi` will not be available at first, so the data on early tiles
63334           // may not have tags validated fully.
63335           // initialize deprecated tags array
63336
63337           _mainFileFetcher.get('deprecated').then(function (d) {
63338             return _dataDeprecated = d;
63339           })["catch"](function () {
63340             /* ignore */
63341           });
63342           _mainFileFetcher.get('nsi_brands').then(function (d) {
63343             _nsi = {
63344               brands: d.brands,
63345               matcher: matcher$1(),
63346               wikidata: {},
63347               wikipedia: {}
63348             }; // initialize name-suggestion-index matcher
63349
63350             _nsi.matcher.buildMatchIndex(d.brands); // index all known wikipedia and wikidata tags
63351
63352
63353             Object.keys(d.brands).forEach(function (kvnd) {
63354               var brand = d.brands[kvnd];
63355               var wd = brand.tags['brand:wikidata'];
63356               var wp = brand.tags['brand:wikipedia'];
63357
63358               if (wd) {
63359                 _nsi.wikidata[wd] = kvnd;
63360               }
63361
63362               if (wp) {
63363                 _nsi.wikipedia[wp] = kvnd;
63364               }
63365             });
63366             return _nsi;
63367           })["catch"](function () {
63368             /* ignore */
63369           });
63370
63371           function oldTagIssues(entity, graph) {
63372             var oldTags = Object.assign({}, entity.tags); // shallow copy
63373
63374             var preset = _mainPresetIndex.match(entity, graph);
63375             var subtype = 'deprecated_tags';
63376             if (!preset) return []; // upgrade preset..
63377
63378             if (preset.replacement) {
63379               var newPreset = _mainPresetIndex.item(preset.replacement);
63380               graph = actionChangePreset(entity.id, preset, newPreset, true
63381               /* skip field defaults */
63382               )(graph);
63383               entity = graph.entity(entity.id);
63384               preset = newPreset;
63385             } // upgrade tags..
63386
63387
63388             if (_dataDeprecated) {
63389               var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
63390
63391               if (deprecatedTags.length) {
63392                 deprecatedTags.forEach(function (tag) {
63393                   graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
63394                 });
63395                 entity = graph.entity(entity.id);
63396               }
63397             } // add missing addTags..
63398
63399
63400             var newTags = Object.assign({}, entity.tags); // shallow copy
63401
63402             if (preset.tags !== preset.addTags) {
63403               Object.keys(preset.addTags).forEach(function (k) {
63404                 if (!newTags[k]) {
63405                   if (preset.addTags[k] === '*') {
63406                     newTags[k] = 'yes';
63407                   } else {
63408                     newTags[k] = preset.addTags[k];
63409                   }
63410                 }
63411               });
63412             }
63413
63414             if (_nsi) {
63415               // Do `wikidata` or `wikipedia` identify this entity as a brand?  #6416
63416               // If so, these tags can be swapped to `brand:wikidata`/`brand:wikipedia`
63417               var isBrand;
63418
63419               if (newTags.wikidata) {
63420                 // try matching `wikidata`
63421                 isBrand = _nsi.wikidata[newTags.wikidata];
63422               }
63423
63424               if (!isBrand && newTags.wikipedia) {
63425                 // fallback to `wikipedia`
63426                 isBrand = _nsi.wikipedia[newTags.wikipedia];
63427               }
63428
63429               if (isBrand && !newTags.office) {
63430                 // but avoid doing this for corporate offices
63431                 if (newTags.wikidata) {
63432                   newTags['brand:wikidata'] = newTags.wikidata;
63433                   delete newTags.wikidata;
63434                 }
63435
63436                 if (newTags.wikipedia) {
63437                   newTags['brand:wikipedia'] = newTags.wikipedia;
63438                   delete newTags.wikipedia;
63439                 } // I considered setting `name` and other tags here, but they aren't unique per wikidata
63440                 // (Q2759586 -> in USA "Papa John's", in Russia "Папа Джонс")
63441                 // So users will really need to use a preset or assign `name` themselves.
63442
63443               } // try key/value|name match against name-suggestion-index
63444
63445
63446               if (newTags.name) {
63447                 for (var i = 0; i < nsiKeys.length; i++) {
63448                   var k = nsiKeys[i];
63449                   if (!newTags[k]) continue;
63450                   var center = entity.extent(graph).center();
63451                   var countryCode = iso1A2Code(center);
63452
63453                   var match = _nsi.matcher.matchKVN(k, newTags[k], newTags.name, countryCode && countryCode.toLowerCase());
63454
63455                   if (!match) continue; // for now skip ambiguous matches (like Target~(USA) vs Target~(Australia))
63456
63457                   if (match.d) continue;
63458                   var brand = _nsi.brands[match.kvnd];
63459
63460                   if (brand && brand.tags['brand:wikidata'] && brand.tags['brand:wikidata'] !== entity.tags['not:brand:wikidata']) {
63461                     subtype = 'noncanonical_brand';
63462                     var keepTags = ['takeaway'].reduce(function (acc, k) {
63463                       if (newTags[k]) {
63464                         acc[k] = newTags[k];
63465                       }
63466
63467                       return acc;
63468                     }, {});
63469                     nsiKeys.forEach(function (k) {
63470                       return delete newTags[k];
63471                     });
63472                     Object.assign(newTags, brand.tags, keepTags);
63473                     break;
63474                   }
63475                 }
63476               }
63477             } // determine diff
63478
63479
63480             var tagDiff = utilTagDiff(oldTags, newTags);
63481             if (!tagDiff.length) return [];
63482             var isOnlyAddingTags = tagDiff.every(function (d) {
63483               return d.type === '+';
63484             });
63485             var prefix = '';
63486
63487             if (subtype === 'noncanonical_brand') {
63488               prefix = 'noncanonical_brand.';
63489             } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
63490               subtype = 'incomplete_tags';
63491               prefix = 'incomplete.';
63492             } // don't allow autofixing brand tags
63493
63494
63495             var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
63496             return [new validationIssue({
63497               type: type,
63498               subtype: subtype,
63499               severity: 'warning',
63500               message: showMessage,
63501               reference: showReference,
63502               entityIds: [entity.id],
63503               hash: JSON.stringify(tagDiff),
63504               dynamicFixes: function dynamicFixes() {
63505                 return [new validationIssueFix({
63506                   autoArgs: autoArgs,
63507                   title: _t.html('issues.fix.upgrade_tags.title'),
63508                   onClick: function onClick(context) {
63509                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
63510                   }
63511                 })];
63512               }
63513             })];
63514
63515             function doUpgrade(graph) {
63516               var currEntity = graph.hasEntity(entity.id);
63517               if (!currEntity) return graph;
63518               var newTags = Object.assign({}, currEntity.tags); // shallow copy
63519
63520               tagDiff.forEach(function (diff) {
63521                 if (diff.type === '-') {
63522                   delete newTags[diff.key];
63523                 } else if (diff.type === '+') {
63524                   newTags[diff.key] = diff.newVal;
63525                 }
63526               });
63527               return actionChangeTags(currEntity.id, newTags)(graph);
63528             }
63529
63530             function showMessage(context) {
63531               var currEntity = context.hasEntity(entity.id);
63532               if (!currEntity) return '';
63533               var messageID = "issues.outdated_tags.".concat(prefix, "message");
63534
63535               if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
63536                 messageID += '_incomplete';
63537               }
63538
63539               return _t.html(messageID, {
63540                 feature: utilDisplayLabel(currEntity, context.graph())
63541               });
63542             }
63543
63544             function showReference(selection) {
63545               var enter = selection.selectAll('.issue-reference').data([0]).enter();
63546               enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
63547               enter.append('strong').html(_t.html('issues.suggested'));
63548               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) {
63549                 var klass = d.type === '+' ? 'add' : 'remove';
63550                 return "tagDiff-cell tagDiff-cell-".concat(klass);
63551               }).html(function (d) {
63552                 return d.display;
63553               });
63554             }
63555           }
63556
63557           function oldMultipolygonIssues(entity, graph) {
63558             var multipolygon, outerWay;
63559
63560             if (entity.type === 'relation') {
63561               outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
63562               multipolygon = entity;
63563             } else if (entity.type === 'way') {
63564               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
63565               outerWay = entity;
63566             } else {
63567               return [];
63568             }
63569
63570             if (!multipolygon || !outerWay) return [];
63571             return [new validationIssue({
63572               type: type,
63573               subtype: 'old_multipolygon',
63574               severity: 'warning',
63575               message: showMessage,
63576               reference: showReference,
63577               entityIds: [outerWay.id, multipolygon.id],
63578               dynamicFixes: function dynamicFixes() {
63579                 return [new validationIssueFix({
63580                   autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
63581                   title: _t.html('issues.fix.move_tags.title'),
63582                   onClick: function onClick(context) {
63583                     context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
63584                   }
63585                 })];
63586               }
63587             })];
63588
63589             function doUpgrade(graph) {
63590               var currMultipolygon = graph.hasEntity(multipolygon.id);
63591               var currOuterWay = graph.hasEntity(outerWay.id);
63592               if (!currMultipolygon || !currOuterWay) return graph;
63593               currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
63594               graph = graph.replace(currMultipolygon);
63595               return actionChangeTags(currOuterWay.id, {})(graph);
63596             }
63597
63598             function showMessage(context) {
63599               var currMultipolygon = context.hasEntity(multipolygon.id);
63600               if (!currMultipolygon) return '';
63601               return _t.html('issues.old_multipolygon.message', {
63602                 multipolygon: utilDisplayLabel(currMultipolygon, context.graph())
63603               });
63604             }
63605
63606             function showReference(selection) {
63607               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
63608             }
63609           }
63610
63611           var validation = function checkOutdatedTags(entity, graph) {
63612             var issues = oldMultipolygonIssues(entity, graph);
63613             if (!issues.length) issues = oldTagIssues(entity, graph);
63614             return issues;
63615           };
63616
63617           validation.type = type;
63618           return validation;
63619         }
63620
63621         function validationPrivateData() {
63622           var type = 'private_data'; // assume that some buildings are private
63623
63624           var privateBuildingValues = {
63625             detached: true,
63626             farm: true,
63627             house: true,
63628             houseboat: true,
63629             residential: true,
63630             semidetached_house: true,
63631             static_caravan: true
63632           }; // but they might be public if they have one of these other tags
63633
63634           var publicKeys = {
63635             amenity: true,
63636             craft: true,
63637             historic: true,
63638             leisure: true,
63639             office: true,
63640             shop: true,
63641             tourism: true
63642           }; // these tags may contain personally identifying info
63643
63644           var personalTags = {
63645             'contact:email': true,
63646             'contact:fax': true,
63647             'contact:phone': true,
63648             email: true,
63649             fax: true,
63650             phone: true
63651           };
63652
63653           var validation = function checkPrivateData(entity) {
63654             var tags = entity.tags;
63655             if (!tags.building || !privateBuildingValues[tags.building]) return [];
63656             var keepTags = {};
63657
63658             for (var k in tags) {
63659               if (publicKeys[k]) return []; // probably a public feature
63660
63661               if (!personalTags[k]) {
63662                 keepTags[k] = tags[k];
63663               }
63664             }
63665
63666             var tagDiff = utilTagDiff(tags, keepTags);
63667             if (!tagDiff.length) return [];
63668             var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
63669             return [new validationIssue({
63670               type: type,
63671               severity: 'warning',
63672               message: showMessage,
63673               reference: showReference,
63674               entityIds: [entity.id],
63675               dynamicFixes: function dynamicFixes() {
63676                 return [new validationIssueFix({
63677                   icon: 'iD-operation-delete',
63678                   title: _t.html('issues.fix.' + fixID + '.title'),
63679                   onClick: function onClick(context) {
63680                     context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
63681                   }
63682                 })];
63683               }
63684             })];
63685
63686             function doUpgrade(graph) {
63687               var currEntity = graph.hasEntity(entity.id);
63688               if (!currEntity) return graph;
63689               var newTags = Object.assign({}, currEntity.tags); // shallow copy
63690
63691               tagDiff.forEach(function (diff) {
63692                 if (diff.type === '-') {
63693                   delete newTags[diff.key];
63694                 } else if (diff.type === '+') {
63695                   newTags[diff.key] = diff.newVal;
63696                 }
63697               });
63698               return actionChangeTags(currEntity.id, newTags)(graph);
63699             }
63700
63701             function showMessage(context) {
63702               var currEntity = context.hasEntity(this.entityIds[0]);
63703               if (!currEntity) return '';
63704               return _t.html('issues.private_data.contact.message', {
63705                 feature: utilDisplayLabel(currEntity, context.graph())
63706               });
63707             }
63708
63709             function showReference(selection) {
63710               var enter = selection.selectAll('.issue-reference').data([0]).enter();
63711               enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
63712               enter.append('strong').html(_t.html('issues.suggested'));
63713               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) {
63714                 var klass = d.type === '+' ? 'add' : 'remove';
63715                 return 'tagDiff-cell tagDiff-cell-' + klass;
63716               }).html(function (d) {
63717                 return d.display;
63718               });
63719             }
63720           };
63721
63722           validation.type = type;
63723           return validation;
63724         }
63725
63726         var _discardNameRegexes = [];
63727         function validationSuspiciousName() {
63728           var type = 'suspicious_name';
63729           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
63730           // be available at first, so the data on early tiles may not have tags validated fully.
63731
63732           _mainFileFetcher.get('nsi_filters').then(function (filters) {
63733             // known list of generic names (e.g. "bar")
63734             _discardNameRegexes = filters.discardNames.map(function (discardName) {
63735               return new RegExp(discardName, 'i');
63736             });
63737           })["catch"](function () {
63738             /* ignore */
63739           });
63740
63741           function isDiscardedSuggestionName(lowercaseName) {
63742             return _discardNameRegexes.some(function (regex) {
63743               return regex.test(lowercaseName);
63744             });
63745           } // test if the name is just the key or tag value (e.g. "park")
63746
63747
63748           function nameMatchesRawTag(lowercaseName, tags) {
63749             for (var i = 0; i < keysToTestForGenericValues.length; i++) {
63750               var key = keysToTestForGenericValues[i];
63751               var val = tags[key];
63752
63753               if (val) {
63754                 val = val.toLowerCase();
63755
63756                 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
63757                   return true;
63758                 }
63759               }
63760             }
63761
63762             return false;
63763           }
63764
63765           function isGenericName(name, tags) {
63766             name = name.toLowerCase();
63767             return nameMatchesRawTag(name, tags) || isDiscardedSuggestionName(name);
63768           }
63769
63770           function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
63771             return new validationIssue({
63772               type: type,
63773               subtype: 'generic_name',
63774               severity: 'warning',
63775               message: function message(context) {
63776                 var entity = context.hasEntity(this.entityIds[0]);
63777                 if (!entity) return '';
63778                 var preset = _mainPresetIndex.match(entity, context.graph());
63779                 var langName = langCode && _mainLocalizer.languageName(langCode);
63780                 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
63781                   feature: preset.name(),
63782                   name: genericName,
63783                   language: langName
63784                 });
63785               },
63786               reference: showReference,
63787               entityIds: [entityId],
63788               hash: nameKey + '=' + genericName,
63789               dynamicFixes: function dynamicFixes() {
63790                 return [new validationIssueFix({
63791                   icon: 'iD-operation-delete',
63792                   title: _t.html('issues.fix.remove_the_name.title'),
63793                   onClick: function onClick(context) {
63794                     var entityId = this.issue.entityIds[0];
63795                     var entity = context.entity(entityId);
63796                     var tags = Object.assign({}, entity.tags); // shallow copy
63797
63798                     delete tags[nameKey];
63799                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
63800                   }
63801                 })];
63802               }
63803             });
63804
63805             function showReference(selection) {
63806               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
63807             }
63808           }
63809
63810           function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
63811             return new validationIssue({
63812               type: type,
63813               subtype: 'not_name',
63814               severity: 'warning',
63815               message: function message(context) {
63816                 var entity = context.hasEntity(this.entityIds[0]);
63817                 if (!entity) return '';
63818                 var preset = _mainPresetIndex.match(entity, context.graph());
63819                 var langName = langCode && _mainLocalizer.languageName(langCode);
63820                 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
63821                   feature: preset.name(),
63822                   name: incorrectName,
63823                   language: langName
63824                 });
63825               },
63826               reference: showReference,
63827               entityIds: [entityId],
63828               hash: nameKey + '=' + incorrectName,
63829               dynamicFixes: function dynamicFixes() {
63830                 return [new validationIssueFix({
63831                   icon: 'iD-operation-delete',
63832                   title: _t.html('issues.fix.remove_the_name.title'),
63833                   onClick: function onClick(context) {
63834                     var entityId = this.issue.entityIds[0];
63835                     var entity = context.entity(entityId);
63836                     var tags = Object.assign({}, entity.tags); // shallow copy
63837
63838                     delete tags[nameKey];
63839                     context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
63840                   }
63841                 })];
63842               }
63843             });
63844
63845             function showReference(selection) {
63846               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
63847             }
63848           }
63849
63850           var validation = function checkGenericName(entity) {
63851             // a generic name is okay if it's a known brand or entity
63852             if (entity.hasWikidata()) return [];
63853             var issues = [];
63854             var notNames = (entity.tags['not:name'] || '').split(';');
63855
63856             for (var key in entity.tags) {
63857               var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
63858               if (!m) continue;
63859               var langCode = m.length >= 2 ? m[1] : null;
63860               var value = entity.tags[key];
63861
63862               if (notNames.length) {
63863                 for (var i in notNames) {
63864                   var notName = notNames[i];
63865
63866                   if (notName && value === notName) {
63867                     issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
63868                     continue;
63869                   }
63870                 }
63871               }
63872
63873               if (isGenericName(value, entity.tags)) {
63874                 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
63875               }
63876             }
63877
63878             return issues;
63879           };
63880
63881           validation.type = type;
63882           return validation;
63883         }
63884
63885         function validationUnsquareWay(context) {
63886           var type = 'unsquare_way';
63887           var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
63888           // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
63889
63890           var epsilon = 0.05;
63891           var nodeThreshold = 10;
63892
63893           function isBuilding(entity, graph) {
63894             if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
63895             return entity.tags.building && entity.tags.building !== 'no';
63896           }
63897
63898           var validation = function checkUnsquareWay(entity, graph) {
63899             if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
63900
63901             if (entity.tags.nonsquare === 'yes') return [];
63902             var isClosed = entity.isClosed();
63903             if (!isClosed) return []; // this building has bigger problems
63904             // don't flag ways with lots of nodes since they are likely detail-mapped
63905
63906             var nodes = graph.childNodes(entity).slice(); // shallow copy
63907
63908             if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
63909             // ignore if not all nodes are fully downloaded
63910
63911             var osm = services.osm;
63912             if (!osm || nodes.some(function (node) {
63913               return !osm.isDataLoaded(node.loc);
63914             })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
63915
63916             var hasConnectedSquarableWays = nodes.some(function (node) {
63917               return graph.parentWays(node).some(function (way) {
63918                 if (way.id === entity.id) return false;
63919                 if (isBuilding(way, graph)) return true;
63920                 return graph.parentRelations(way).some(function (parentRelation) {
63921                   return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
63922                 });
63923               });
63924             });
63925             if (hasConnectedSquarableWays) return []; // user-configurable square threshold
63926
63927             var storedDegreeThreshold = corePreferences('validate-square-degrees');
63928             var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
63929             var points = nodes.map(function (node) {
63930               return context.projection(node.loc);
63931             });
63932             if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
63933             var autoArgs; // don't allow autosquaring features linked to wikidata
63934
63935             if (!entity.tags.wikidata) {
63936               // use same degree threshold as for detection
63937               var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
63938               autoAction.transitionable = false; // when autofixing, do it instantly
63939
63940               autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
63941                 n: 1
63942               })];
63943             }
63944
63945             return [new validationIssue({
63946               type: type,
63947               subtype: 'building',
63948               severity: 'warning',
63949               message: function message(context) {
63950                 var entity = context.hasEntity(this.entityIds[0]);
63951                 return entity ? _t.html('issues.unsquare_way.message', {
63952                   feature: utilDisplayLabel(entity, context.graph())
63953                 }) : '';
63954               },
63955               reference: showReference,
63956               entityIds: [entity.id],
63957               hash: JSON.stringify(autoArgs !== undefined) + degreeThreshold,
63958               dynamicFixes: function dynamicFixes() {
63959                 return [new validationIssueFix({
63960                   icon: 'iD-operation-orthogonalize',
63961                   title: _t.html('issues.fix.square_feature.title'),
63962                   autoArgs: autoArgs,
63963                   onClick: function onClick(context, completionHandler) {
63964                     var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
63965
63966                     context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
63967                       n: 1
63968                     })); // run after the squaring transition (currently 150ms)
63969
63970                     window.setTimeout(function () {
63971                       completionHandler();
63972                     }, 175);
63973                   }
63974                 })
63975                 /*
63976                 new validationIssueFix({
63977                     title: t.html('issues.fix.tag_as_unsquare.title'),
63978                     onClick: function(context) {
63979                         var entityId = this.issue.entityIds[0];
63980                         var entity = context.entity(entityId);
63981                         var tags = Object.assign({}, entity.tags);  // shallow copy
63982                         tags.nonsquare = 'yes';
63983                         context.perform(
63984                             actionChangeTags(entityId, tags),
63985                             t('issues.fix.tag_as_unsquare.annotation')
63986                         );
63987                     }
63988                 })
63989                 */
63990                 ];
63991               }
63992             })];
63993
63994             function showReference(selection) {
63995               selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
63996             }
63997           };
63998
63999           validation.type = type;
64000           return validation;
64001         }
64002
64003         var Validations = /*#__PURE__*/Object.freeze({
64004                 __proto__: null,
64005                 validationAlmostJunction: validationAlmostJunction,
64006                 validationCloseNodes: validationCloseNodes,
64007                 validationCrossingWays: validationCrossingWays,
64008                 validationDisconnectedWay: validationDisconnectedWay,
64009                 validationFormatting: validationFormatting,
64010                 validationHelpRequest: validationHelpRequest,
64011                 validationImpossibleOneway: validationImpossibleOneway,
64012                 validationIncompatibleSource: validationIncompatibleSource,
64013                 validationMaprules: validationMaprules,
64014                 validationMismatchedGeometry: validationMismatchedGeometry,
64015                 validationMissingRole: validationMissingRole,
64016                 validationMissingTag: validationMissingTag,
64017                 validationOutdatedTags: validationOutdatedTags,
64018                 validationPrivateData: validationPrivateData,
64019                 validationSuspiciousName: validationSuspiciousName,
64020                 validationUnsquareWay: validationUnsquareWay
64021         });
64022
64023         function coreValidator(context) {
64024           var dispatch$1 = dispatch('validated', 'focusedIssue');
64025           var validator = utilRebind({}, dispatch$1, 'on');
64026           var _rules = {};
64027           var _disabledRules = {};
64028           var _ignoredIssueIDs = {}; // issue.id -> true
64029
64030           var _baseCache = validationCache(); // issues before any user edits
64031
64032
64033           var _headCache = validationCache(); // issues after all user edits
64034
64035
64036           var _validatedGraph = null;
64037
64038           var _deferred = new Set(); //
64039           // initialize the validator rulesets
64040           //
64041
64042
64043           validator.init = function () {
64044             Object.values(Validations).forEach(function (validation) {
64045               if (typeof validation !== 'function') return;
64046               var fn = validation(context);
64047               var key = fn.type;
64048               _rules[key] = fn;
64049             });
64050             var disabledRules = corePreferences('validate-disabledRules');
64051
64052             if (disabledRules) {
64053               disabledRules.split(',').forEach(function (key) {
64054                 _disabledRules[key] = true;
64055               });
64056             }
64057           };
64058
64059           function reset(resetIgnored) {
64060             Array.from(_deferred).forEach(function (handle) {
64061               window.cancelIdleCallback(handle);
64062
64063               _deferred["delete"](handle);
64064             }); // clear caches
64065
64066             if (resetIgnored) _ignoredIssueIDs = {};
64067             _baseCache = validationCache();
64068             _headCache = validationCache();
64069             _validatedGraph = null;
64070           } //
64071           // clear caches, called whenever iD resets after a save
64072           //
64073
64074
64075           validator.reset = function () {
64076             reset(true);
64077           };
64078
64079           validator.resetIgnoredIssues = function () {
64080             _ignoredIssueIDs = {}; // reload UI
64081
64082             dispatch$1.call('validated');
64083           }; // must update issues when the user changes the unsquare thereshold
64084
64085
64086           validator.reloadUnsquareIssues = function () {
64087             reloadUnsquareIssues(_headCache, context.graph());
64088             reloadUnsquareIssues(_baseCache, context.history().base());
64089             dispatch$1.call('validated');
64090           };
64091
64092           function reloadUnsquareIssues(cache, graph) {
64093             var checkUnsquareWay = _rules.unsquare_way;
64094             if (typeof checkUnsquareWay !== 'function') return; // uncache existing
64095
64096             cache.uncacheIssuesOfType('unsquare_way');
64097             var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), graph) // everywhere
64098             .filter(function (entity) {
64099               return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
64100             }); // rerun for all buildings
64101
64102             buildings.forEach(function (entity) {
64103               var detected = checkUnsquareWay(entity, graph);
64104               if (detected.length !== 1) return;
64105               var issue = detected[0];
64106
64107               if (!cache.issuesByEntityID[entity.id]) {
64108                 cache.issuesByEntityID[entity.id] = new Set();
64109               }
64110
64111               cache.issuesByEntityID[entity.id].add(issue.id);
64112               cache.issuesByIssueID[issue.id] = issue;
64113             });
64114           } // options = {
64115           //     what: 'all',     // 'all' or 'edited'
64116           //     where: 'all',   // 'all' or 'visible'
64117           //     includeIgnored: false   // true, false, or 'only'
64118           //     includeDisabledRules: false   // true, false, or 'only'
64119           // };
64120
64121
64122           validator.getIssues = function (options) {
64123             var opts = Object.assign({
64124               what: 'all',
64125               where: 'all',
64126               includeIgnored: false,
64127               includeDisabledRules: false
64128             }, options);
64129             var issues = Object.values(_headCache.issuesByIssueID);
64130             var view = context.map().extent();
64131             return issues.filter(function (issue) {
64132               if (!issue) return false;
64133               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
64134               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
64135               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
64136               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false; // Sanity check:  This issue may be for an entity that not longer exists.
64137               // If we detect this, uncache and return false so it is not included..
64138
64139               var entityIds = issue.entityIds || [];
64140
64141               for (var i = 0; i < entityIds.length; i++) {
64142                 var entityId = entityIds[i];
64143
64144                 if (!context.hasEntity(entityId)) {
64145                   delete _headCache.issuesByEntityID[entityId];
64146                   delete _headCache.issuesByIssueID[issue.id];
64147                   return false;
64148                 }
64149               }
64150
64151               if (opts.what === 'edited' && _baseCache.issuesByIssueID[issue.id]) return false;
64152
64153               if (opts.where === 'visible') {
64154                 var extent = issue.extent(context.graph());
64155                 if (!view.intersects(extent)) return false;
64156               }
64157
64158               return true;
64159             });
64160           };
64161
64162           validator.getResolvedIssues = function () {
64163             var baseIssues = Object.values(_baseCache.issuesByIssueID);
64164             return baseIssues.filter(function (issue) {
64165               return !_headCache.issuesByIssueID[issue.id];
64166             });
64167           };
64168
64169           validator.focusIssue = function (issue) {
64170             var extent = issue.extent(context.graph());
64171
64172             if (extent) {
64173               var setZoom = Math.max(context.map().zoom(), 19);
64174               context.map().unobscuredCenterZoomEase(extent.center(), setZoom); // select the first entity
64175
64176               if (issue.entityIds && issue.entityIds.length) {
64177                 window.setTimeout(function () {
64178                   var ids = issue.entityIds;
64179                   context.enter(modeSelect(context, [ids[0]]));
64180                   dispatch$1.call('focusedIssue', this, issue);
64181                 }, 250); // after ease
64182               }
64183             }
64184           };
64185
64186           validator.getIssuesBySeverity = function (options) {
64187             var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
64188             groups.error = groups.error || [];
64189             groups.warning = groups.warning || [];
64190             return groups;
64191           }; // show some issue types in a particular order
64192
64193
64194           var orderedIssueTypes = [// flag missing data first
64195           'missing_tag', 'missing_role', // then flag identity issues
64196           'outdated_tags', 'mismatched_geometry', // flag geometry issues where fixing them might solve connectivity issues
64197           'crossing_ways', 'almost_junction', // then flag connectivity issues
64198           'disconnected_way', 'impossible_oneway']; // returns the issues that the given entity IDs have in common, matching the given options
64199
64200           validator.getSharedEntityIssues = function (entityIDs, options) {
64201             var cache = _headCache; // gather the issues that are common to all the entities
64202
64203             var issueIDs = entityIDs.reduce(function (acc, entityID) {
64204               var entityIssueIDs = cache.issuesByEntityID[entityID] || new Set();
64205
64206               if (!acc) {
64207                 return new Set(entityIssueIDs);
64208               }
64209
64210               return new Set(_toConsumableArray(acc).filter(function (elem) {
64211                 return entityIssueIDs.has(elem);
64212               }));
64213             }, null) || [];
64214             var opts = options || {};
64215             return Array.from(issueIDs).map(function (id) {
64216               return cache.issuesByIssueID[id];
64217             }).filter(function (issue) {
64218               if (!issue) return false;
64219               if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
64220               if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
64221               if (opts.includeIgnored === 'only' && !_ignoredIssueIDs[issue.id]) return false;
64222               if (!opts.includeIgnored && _ignoredIssueIDs[issue.id]) return false;
64223               return true;
64224             }).sort(function (issue1, issue2) {
64225               if (issue1.type === issue2.type) {
64226                 // issues of the same type, sort deterministically
64227                 return issue1.id < issue2.id ? -1 : 1;
64228               }
64229
64230               var index1 = orderedIssueTypes.indexOf(issue1.type);
64231               var index2 = orderedIssueTypes.indexOf(issue2.type);
64232
64233               if (index1 !== -1 && index2 !== -1) {
64234                 // both issue types have explicit sort orders
64235                 return index1 - index2;
64236               } else if (index1 === -1 && index2 === -1) {
64237                 // neither issue type has an explicit sort order, sort by type
64238                 return issue1.type < issue2.type ? -1 : 1;
64239               } else {
64240                 // order explicit types before everything else
64241                 return index1 !== -1 ? -1 : 1;
64242               }
64243             });
64244           };
64245
64246           validator.getEntityIssues = function (entityID, options) {
64247             return validator.getSharedEntityIssues([entityID], options);
64248           };
64249
64250           validator.getRuleKeys = function () {
64251             return Object.keys(_rules);
64252           };
64253
64254           validator.isRuleEnabled = function (key) {
64255             return !_disabledRules[key];
64256           };
64257
64258           validator.toggleRule = function (key) {
64259             if (_disabledRules[key]) {
64260               delete _disabledRules[key];
64261             } else {
64262               _disabledRules[key] = true;
64263             }
64264
64265             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
64266             validator.validate();
64267           };
64268
64269           validator.disableRules = function (keys) {
64270             _disabledRules = {};
64271             keys.forEach(function (k) {
64272               _disabledRules[k] = true;
64273             });
64274             corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
64275             validator.validate();
64276           };
64277
64278           validator.ignoreIssue = function (id) {
64279             _ignoredIssueIDs[id] = true;
64280           }; //
64281           // Run validation on a single entity for the given graph
64282           //
64283
64284
64285           function validateEntity(entity, graph) {
64286             var entityIssues = []; // runs validation and appends resulting issues
64287
64288             function runValidation(key) {
64289               var fn = _rules[key];
64290
64291               if (typeof fn !== 'function') {
64292                 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
64293
64294                 return;
64295               }
64296
64297               var detected = fn(entity, graph);
64298               entityIssues = entityIssues.concat(detected);
64299             } // run all rules
64300
64301
64302             Object.keys(_rules).forEach(runValidation);
64303             return entityIssues;
64304           }
64305
64306           function entityIDsToValidate(entityIDs, graph) {
64307             var processedIDs = new Set();
64308             return entityIDs.reduce(function (acc, entityID) {
64309               // keep redundancy check separate from `acc` because an `entityID`
64310               // could have been added to `acc` as a related entity through an earlier pass
64311               if (processedIDs.has(entityID)) return acc;
64312               processedIDs.add(entityID);
64313               var entity = graph.hasEntity(entityID);
64314               if (!entity) return acc;
64315               acc.add(entityID);
64316               var checkParentRels = [entity];
64317
64318               if (entity.type === 'node') {
64319                 graph.parentWays(entity).forEach(function (parentWay) {
64320                   acc.add(parentWay.id); // include parent ways
64321
64322                   checkParentRels.push(parentWay);
64323                 });
64324               } else if (entity.type === 'relation') {
64325                 entity.members.forEach(function (member) {
64326                   acc.add(member.id); // include members
64327                 });
64328               } else if (entity.type === 'way') {
64329                 entity.nodes.forEach(function (nodeID) {
64330                   acc.add(nodeID); // include child nodes
64331
64332                   graph._parentWays[nodeID].forEach(function (wayID) {
64333                     acc.add(wayID); // include connected ways
64334                   });
64335                 });
64336               }
64337
64338               checkParentRels.forEach(function (entity) {
64339                 // include parent relations
64340                 if (entity.type !== 'relation') {
64341                   // but not super-relations
64342                   graph.parentRelations(entity).forEach(function (parentRelation) {
64343                     acc.add(parentRelation.id);
64344                   });
64345                 }
64346               });
64347               return acc;
64348             }, new Set());
64349           } //
64350           // Run validation for several entities, supplied `entityIDs`,
64351           // against `graph` for the given `cache`
64352           //
64353
64354
64355           function validateEntities(entityIDs, graph, cache) {
64356             // clear caches for existing issues related to these entities
64357             entityIDs.forEach(cache.uncacheEntityID); // detect new issues and update caches
64358
64359             entityIDs.forEach(function (entityID) {
64360               var entity = graph.hasEntity(entityID); // don't validate deleted entities
64361
64362               if (!entity) return;
64363               var issues = validateEntity(entity, graph);
64364               cache.cacheIssues(issues);
64365             });
64366           } //
64367           // Validates anything that has changed since the last time it was run.
64368           // Also updates the "validatedGraph" to be the current graph
64369           // and dispatches a `validated` event when finished.
64370           //
64371
64372
64373           validator.validate = function () {
64374             var currGraph = context.graph();
64375             _validatedGraph = _validatedGraph || context.history().base();
64376
64377             if (currGraph === _validatedGraph) {
64378               dispatch$1.call('validated');
64379               return;
64380             }
64381
64382             var oldGraph = _validatedGraph;
64383             var difference = coreDifference(oldGraph, currGraph);
64384             _validatedGraph = currGraph;
64385             var createdAndModifiedEntityIDs = difference.extantIDs(true); // created/modified (true = w/relation members)
64386
64387             var entityIDsToCheck = entityIDsToValidate(createdAndModifiedEntityIDs, currGraph); // check modified and deleted entities against the old graph in order to update their related entities
64388             // (e.g. deleting the only highway connected to a road should create a disconnected highway issue)
64389
64390             var modifiedAndDeletedEntityIDs = difference.deleted().concat(difference.modified()).map(function (entity) {
64391               return entity.id;
64392             });
64393             var entityIDsToCheckForOldGraph = entityIDsToValidate(modifiedAndDeletedEntityIDs, oldGraph); // concat the sets
64394
64395             entityIDsToCheckForOldGraph.forEach(entityIDsToCheck.add, entityIDsToCheck);
64396             validateEntities(entityIDsToCheck, context.graph(), _headCache);
64397             dispatch$1.call('validated');
64398           };
64399
64400           context.history().on('reset.validator', function () {
64401             // cached issues aren't valid any longer if the history has been reset
64402             reset(false);
64403             validator.validate();
64404           }); // WHEN TO RUN VALIDATION:
64405           // When graph changes:
64406
64407           context.history().on('restore.validator', validator.validate) // restore saved history
64408           .on('undone.validator', validator.validate) // undo
64409           .on('redone.validator', validator.validate); // redo
64410           // but not on 'change' (e.g. while drawing)
64411           // When user changes editing modes:
64412
64413           context.on('exit.validator', validator.validate); // When merging fetched data:
64414
64415           context.history().on('merge.validator', function (entities) {
64416             if (!entities) return;
64417             var handle = window.requestIdleCallback(function () {
64418               var entityIDs = entities.map(function (entity) {
64419                 return entity.id;
64420               });
64421               var headGraph = context.graph();
64422               validateEntities(entityIDsToValidate(entityIDs, headGraph), headGraph, _headCache);
64423               var baseGraph = context.history().base();
64424               validateEntities(entityIDsToValidate(entityIDs, baseGraph), baseGraph, _baseCache);
64425               dispatch$1.call('validated');
64426             });
64427
64428             _deferred.add(handle);
64429           });
64430           return validator;
64431         }
64432
64433         function validationCache() {
64434           var cache = {
64435             issuesByIssueID: {},
64436             // issue.id -> issue
64437             issuesByEntityID: {} // entity.id -> set(issue.id)
64438
64439           };
64440
64441           cache.cacheIssues = function (issues) {
64442             issues.forEach(function (issue) {
64443               var entityIds = issue.entityIds || [];
64444               entityIds.forEach(function (entityId) {
64445                 if (!cache.issuesByEntityID[entityId]) {
64446                   cache.issuesByEntityID[entityId] = new Set();
64447                 }
64448
64449                 cache.issuesByEntityID[entityId].add(issue.id);
64450               });
64451               cache.issuesByIssueID[issue.id] = issue;
64452             });
64453           };
64454
64455           cache.uncacheIssue = function (issue) {
64456             // When multiple entities are involved (e.g. crossing_ways),
64457             // remove this issue from the other entity caches too..
64458             var entityIds = issue.entityIds || [];
64459             entityIds.forEach(function (entityId) {
64460               if (cache.issuesByEntityID[entityId]) {
64461                 cache.issuesByEntityID[entityId]["delete"](issue.id);
64462               }
64463             });
64464             delete cache.issuesByIssueID[issue.id];
64465           };
64466
64467           cache.uncacheIssues = function (issues) {
64468             issues.forEach(cache.uncacheIssue);
64469           };
64470
64471           cache.uncacheIssuesOfType = function (type) {
64472             var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
64473               return issue.type === type;
64474             });
64475             cache.uncacheIssues(issuesOfType);
64476           }; //
64477           // Remove a single entity and all its related issues from the caches
64478           //
64479
64480
64481           cache.uncacheEntityID = function (entityID) {
64482             var issueIDs = cache.issuesByEntityID[entityID];
64483             if (!issueIDs) return;
64484             issueIDs.forEach(function (issueID) {
64485               var issue = cache.issuesByIssueID[issueID];
64486
64487               if (issue) {
64488                 cache.uncacheIssue(issue);
64489               } else {
64490                 delete cache.issuesByIssueID[issueID];
64491               }
64492             });
64493             delete cache.issuesByEntityID[entityID];
64494           };
64495
64496           return cache;
64497         }
64498
64499         function coreUploader(context) {
64500           var dispatch$1 = dispatch( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
64501           'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
64502           'saveEnded', // dispatched after the result event has been dispatched
64503           'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
64504           'progressChanged', // Each save results in one of these outcomes:
64505           'resultNoChanges', // upload wasn't attempted since there were no edits
64506           'resultErrors', // upload failed due to errors
64507           'resultConflicts', // upload failed due to data conflicts
64508           'resultSuccess' // upload completed without errors
64509           );
64510           var _isSaving = false;
64511           var _conflicts = [];
64512           var _errors = [];
64513
64514           var _origChanges;
64515
64516           var _discardTags = {};
64517           _mainFileFetcher.get('discarded').then(function (d) {
64518             _discardTags = d;
64519           })["catch"](function () {
64520             /* ignore */
64521           });
64522           var uploader = utilRebind({}, dispatch$1, 'on');
64523
64524           uploader.isSaving = function () {
64525             return _isSaving;
64526           };
64527
64528           uploader.save = function (changeset, tryAgain, checkConflicts) {
64529             // Guard against accidentally entering save code twice - #4641
64530             if (_isSaving && !tryAgain) {
64531               return;
64532             }
64533
64534             var osm = context.connection();
64535             if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
64536             // This can happen if they were logged in from before, but the tokens are no longer valid.
64537
64538             if (!osm.authenticated()) {
64539               osm.authenticate(function (err) {
64540                 if (!err) {
64541                   uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
64542                 }
64543               });
64544               return;
64545             }
64546
64547             if (!_isSaving) {
64548               _isSaving = true;
64549               dispatch$1.call('saveStarted', this);
64550             }
64551
64552             var history = context.history();
64553             _conflicts = [];
64554             _errors = []; // Store original changes, in case user wants to download them as an .osc file
64555
64556             _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
64557             // Any conflict resolutions will be done as `history.replace`
64558             // Remember to pop this later if needed
64559
64560             if (!tryAgain) {
64561               history.perform(actionNoop());
64562             } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
64563
64564
64565             if (!checkConflicts) {
64566               upload(changeset); // Do the full (slow) conflict check..
64567             } else {
64568               performFullConflictCheck(changeset);
64569             }
64570           };
64571
64572           function performFullConflictCheck(changeset) {
64573             var osm = context.connection();
64574             if (!osm) return;
64575             var history = context.history();
64576             var localGraph = context.graph();
64577             var remoteGraph = coreGraph(history.base(), true);
64578             var summary = history.difference().summary();
64579             var _toCheck = [];
64580
64581             for (var i = 0; i < summary.length; i++) {
64582               var item = summary[i];
64583
64584               if (item.changeType === 'modified') {
64585                 _toCheck.push(item.entity.id);
64586               }
64587             }
64588
64589             var _toLoad = withChildNodes(_toCheck, localGraph);
64590
64591             var _loaded = {};
64592             var _toLoadCount = 0;
64593             var _toLoadTotal = _toLoad.length;
64594
64595             if (_toCheck.length) {
64596               dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
64597
64598               _toLoad.forEach(function (id) {
64599                 _loaded[id] = false;
64600               });
64601
64602               osm.loadMultiple(_toLoad, loaded);
64603             } else {
64604               upload(changeset);
64605             }
64606
64607             return;
64608
64609             function withChildNodes(ids, graph) {
64610               var s = new Set(ids);
64611               ids.forEach(function (id) {
64612                 var entity = graph.entity(id);
64613                 if (entity.type !== 'way') return;
64614                 graph.childNodes(entity).forEach(function (child) {
64615                   if (child.version !== undefined) {
64616                     s.add(child.id);
64617                   }
64618                 });
64619               });
64620               return Array.from(s);
64621             } // Reload modified entities into an alternate graph and check for conflicts..
64622
64623
64624             function loaded(err, result) {
64625               if (_errors.length) return;
64626
64627               if (err) {
64628                 _errors.push({
64629                   msg: err.message || err.responseText,
64630                   details: [_t('save.status_code', {
64631                     code: err.status
64632                   })]
64633                 });
64634
64635                 didResultInErrors();
64636               } else {
64637                 var loadMore = [];
64638                 result.data.forEach(function (entity) {
64639                   remoteGraph.replace(entity);
64640                   _loaded[entity.id] = true;
64641                   _toLoad = _toLoad.filter(function (val) {
64642                     return val !== entity.id;
64643                   });
64644                   if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
64645                   // need to also load children that aren't already being checked..
64646
64647                   var i, id;
64648
64649                   if (entity.type === 'way') {
64650                     for (i = 0; i < entity.nodes.length; i++) {
64651                       id = entity.nodes[i];
64652
64653                       if (_loaded[id] === undefined) {
64654                         _loaded[id] = false;
64655                         loadMore.push(id);
64656                       }
64657                     }
64658                   } else if (entity.type === 'relation' && entity.isMultipolygon()) {
64659                     for (i = 0; i < entity.members.length; i++) {
64660                       id = entity.members[i].id;
64661
64662                       if (_loaded[id] === undefined) {
64663                         _loaded[id] = false;
64664                         loadMore.push(id);
64665                       }
64666                     }
64667                   }
64668                 });
64669                 _toLoadCount += result.data.length;
64670                 _toLoadTotal += loadMore.length;
64671                 dispatch$1.call('progressChanged', this, _toLoadCount, _toLoadTotal);
64672
64673                 if (loadMore.length) {
64674                   _toLoad.push.apply(_toLoad, loadMore);
64675
64676                   osm.loadMultiple(loadMore, loaded);
64677                 }
64678
64679                 if (!_toLoad.length) {
64680                   detectConflicts();
64681                   upload(changeset);
64682                 }
64683               }
64684             }
64685
64686             function detectConflicts() {
64687               function choice(id, text, _action) {
64688                 return {
64689                   id: id,
64690                   text: text,
64691                   action: function action() {
64692                     history.replace(_action);
64693                   }
64694                 };
64695               }
64696
64697               function formatUser(d) {
64698                 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
64699               }
64700
64701               function entityName(entity) {
64702                 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
64703               }
64704
64705               function sameVersions(local, remote) {
64706                 if (local.version !== remote.version) return false;
64707
64708                 if (local.type === 'way') {
64709                   var children = utilArrayUnion(local.nodes, remote.nodes);
64710
64711                   for (var i = 0; i < children.length; i++) {
64712                     var a = localGraph.hasEntity(children[i]);
64713                     var b = remoteGraph.hasEntity(children[i]);
64714                     if (a && b && a.version !== b.version) return false;
64715                   }
64716                 }
64717
64718                 return true;
64719               }
64720
64721               _toCheck.forEach(function (id) {
64722                 var local = localGraph.entity(id);
64723                 var remote = remoteGraph.entity(id);
64724                 if (sameVersions(local, remote)) return;
64725                 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
64726                 history.replace(merge);
64727                 var mergeConflicts = merge.conflicts();
64728                 if (!mergeConflicts.length) return; // merged safely
64729
64730                 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
64731                 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
64732                 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
64733                 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
64734
64735                 _conflicts.push({
64736                   id: id,
64737                   name: entityName(local),
64738                   details: mergeConflicts,
64739                   chosen: 1,
64740                   choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
64741                 });
64742               });
64743             }
64744           }
64745
64746           function upload(changeset) {
64747             var osm = context.connection();
64748
64749             if (!osm) {
64750               _errors.push({
64751                 msg: 'No OSM Service'
64752               });
64753             }
64754
64755             if (_conflicts.length) {
64756               didResultInConflicts(changeset);
64757             } else if (_errors.length) {
64758               didResultInErrors();
64759             } else {
64760               var history = context.history();
64761               var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
64762
64763               if (changes.modified.length || changes.created.length || changes.deleted.length) {
64764                 dispatch$1.call('willAttemptUpload', this);
64765                 osm.putChangeset(changeset, changes, uploadCallback);
64766               } else {
64767                 // changes were insignificant or reverted by user
64768                 didResultInNoChanges();
64769               }
64770             }
64771           }
64772
64773           function uploadCallback(err, changeset) {
64774             if (err) {
64775               if (err.status === 409) {
64776                 // 409 Conflict
64777                 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
64778               } else {
64779                 _errors.push({
64780                   msg: err.message || err.responseText,
64781                   details: [_t('save.status_code', {
64782                     code: err.status
64783                   })]
64784                 });
64785
64786                 didResultInErrors();
64787               }
64788             } else {
64789               didResultInSuccess(changeset);
64790             }
64791           }
64792
64793           function didResultInNoChanges() {
64794             dispatch$1.call('resultNoChanges', this);
64795             endSave();
64796             context.flush(); // reset iD
64797           }
64798
64799           function didResultInErrors() {
64800             context.history().pop();
64801             dispatch$1.call('resultErrors', this, _errors);
64802             endSave();
64803           }
64804
64805           function didResultInConflicts(changeset) {
64806             _conflicts.sort(function (a, b) {
64807               return b.id.localeCompare(a.id);
64808             });
64809
64810             dispatch$1.call('resultConflicts', this, changeset, _conflicts, _origChanges);
64811             endSave();
64812           }
64813
64814           function didResultInSuccess(changeset) {
64815             // delete the edit stack cached to local storage
64816             context.history().clearSaved();
64817             dispatch$1.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
64818
64819             window.setTimeout(function () {
64820               endSave();
64821               context.flush(); // reset iD
64822             }, 2500);
64823           }
64824
64825           function endSave() {
64826             _isSaving = false;
64827             dispatch$1.call('saveEnded', this);
64828           }
64829
64830           uploader.cancelConflictResolution = function () {
64831             context.history().pop();
64832           };
64833
64834           uploader.processResolvedConflicts = function (changeset) {
64835             var history = context.history();
64836
64837             for (var i = 0; i < _conflicts.length; i++) {
64838               if (_conflicts[i].chosen === 1) {
64839                 // user chose "use theirs"
64840                 var entity = context.hasEntity(_conflicts[i].id);
64841
64842                 if (entity && entity.type === 'way') {
64843                   var children = utilArrayUniq(entity.nodes);
64844
64845                   for (var j = 0; j < children.length; j++) {
64846                     history.replace(actionRevert(children[j]));
64847                   }
64848                 }
64849
64850                 history.replace(actionRevert(_conflicts[i].id));
64851               }
64852             }
64853
64854             uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
64855           };
64856
64857           uploader.reset = function () {};
64858
64859           return uploader;
64860         }
64861
64862         var abs$4 = Math.abs;
64863         var exp$2 = Math.exp;
64864         var E = Math.E;
64865
64866         var FORCED$g = fails(function () {
64867           return Math.sinh(-2e-17) != -2e-17;
64868         });
64869
64870         // `Math.sinh` method
64871         // https://tc39.github.io/ecma262/#sec-math.sinh
64872         // V8 near Chromium 38 has a problem with very small numbers
64873         _export({ target: 'Math', stat: true, forced: FORCED$g }, {
64874           sinh: function sinh(x) {
64875             return abs$4(x = +x) < 1 ? (mathExpm1(x) - mathExpm1(-x)) / 2 : (exp$2(x - 1) - exp$2(-x - 1)) * (E / 2);
64876           }
64877         });
64878
64879         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
64880
64881         window.matchMedia("\n        (-webkit-min-device-pixel-ratio: 2), /* Safari */\n        (min-resolution: 2dppx),             /* standard */\n        (min-resolution: 192dpi)             /* fallback */\n    ").addListener(function () {
64882           isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
64883         });
64884
64885         function localeDateString(s) {
64886           if (!s) return null;
64887           var options = {
64888             day: 'numeric',
64889             month: 'short',
64890             year: 'numeric'
64891           };
64892           var d = new Date(s);
64893           if (isNaN(d.getTime())) return null;
64894           return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
64895         }
64896
64897         function vintageRange(vintage) {
64898           var s;
64899
64900           if (vintage.start || vintage.end) {
64901             s = vintage.start || '?';
64902
64903             if (vintage.start !== vintage.end) {
64904               s += ' - ' + (vintage.end || '?');
64905             }
64906           }
64907
64908           return s;
64909         }
64910
64911         function rendererBackgroundSource(data) {
64912           var source = Object.assign({}, data); // shallow copy
64913
64914           var _offset = [0, 0];
64915           var _name = source.name;
64916           var _description = source.description;
64917
64918           var _best = !!source.best;
64919
64920           var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
64921
64922           source.tileSize = data.tileSize || 256;
64923           source.zoomExtent = data.zoomExtent || [0, 22];
64924           source.overzoom = data.overzoom !== false;
64925
64926           source.offset = function (val) {
64927             if (!arguments.length) return _offset;
64928             _offset = val;
64929             return source;
64930           };
64931
64932           source.nudge = function (val, zoomlevel) {
64933             _offset[0] += val[0] / Math.pow(2, zoomlevel);
64934             _offset[1] += val[1] / Math.pow(2, zoomlevel);
64935             return source;
64936           };
64937
64938           source.name = function () {
64939             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64940             return _t('imagery.' + id_safe + '.name', {
64941               "default": _name
64942             });
64943           };
64944
64945           source.label = function () {
64946             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64947             return _t.html('imagery.' + id_safe + '.name', {
64948               "default": _name
64949             });
64950           };
64951
64952           source.description = function () {
64953             var id_safe = source.id.replace(/\./g, '<TX_DOT>');
64954             return _t.html('imagery.' + id_safe + '.description', {
64955               "default": _description
64956             });
64957           };
64958
64959           source.best = function () {
64960             return _best;
64961           };
64962
64963           source.area = function () {
64964             if (!data.polygon) return Number.MAX_VALUE; // worldwide
64965
64966             var area = d3_geoArea({
64967               type: 'MultiPolygon',
64968               coordinates: [data.polygon]
64969             });
64970             return isNaN(area) ? 0 : area;
64971           };
64972
64973           source.imageryUsed = function () {
64974             return _name || source.id;
64975           };
64976
64977           source.template = function (val) {
64978             if (!arguments.length) return _template;
64979
64980             if (source.id === 'custom') {
64981               _template = val;
64982             }
64983
64984             return source;
64985           };
64986
64987           source.url = function (coord) {
64988             var result = _template;
64989             if (result === '') return result; // source 'none'
64990             // Guess a type based on the tokens present in the template
64991             // (This is for 'custom' source, where we don't know)
64992
64993             if (!source.type) {
64994               if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
64995                 source.type = 'wms';
64996                 source.projection = 'EPSG:3857'; // guess
64997               } else if (/\{(x|y)\}/.test(_template)) {
64998                 source.type = 'tms';
64999               } else if (/\{u\}/.test(_template)) {
65000                 source.type = 'bing';
65001               }
65002             }
65003
65004             if (source.type === 'wms') {
65005               var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
65006                 //polyfill for IE11, PhantomJS
65007                 var sinh = Math.sinh || function (x) {
65008                   var y = Math.exp(x);
65009                   return (y - 1 / y) / 2;
65010                 };
65011
65012                 var zoomSize = Math.pow(2, z);
65013                 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
65014                 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
65015
65016                 switch (source.projection) {
65017                   case 'EPSG:4326':
65018                     return {
65019                       x: lon * 180 / Math.PI,
65020                       y: lat * 180 / Math.PI
65021                     };
65022
65023                   default:
65024                     // EPSG:3857 and synonyms
65025                     var mercCoords = mercatorRaw(lon, lat);
65026                     return {
65027                       x: 20037508.34 / Math.PI * mercCoords[0],
65028                       y: 20037508.34 / Math.PI * mercCoords[1]
65029                     };
65030                 }
65031               };
65032
65033               var tileSize = source.tileSize;
65034               var projection = source.projection;
65035               var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
65036               var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
65037               result = result.replace(/\{(\w+)\}/g, function (token, key) {
65038                 switch (key) {
65039                   case 'width':
65040                   case 'height':
65041                     return tileSize;
65042
65043                   case 'proj':
65044                     return projection;
65045
65046                   case 'wkid':
65047                     return projection.replace(/^EPSG:/, '');
65048
65049                   case 'bbox':
65050                     // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
65051                     if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
65052                     /VERSION=1.3|CRS={proj}/.test(source.template())) {
65053                       return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
65054                     } else {
65055                       return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
65056                     }
65057
65058                   case 'w':
65059                     return minXmaxY.x;
65060
65061                   case 's':
65062                     return maxXminY.y;
65063
65064                   case 'n':
65065                     return maxXminY.x;
65066
65067                   case 'e':
65068                     return minXmaxY.y;
65069
65070                   default:
65071                     return token;
65072                 }
65073               });
65074             } else if (source.type === 'tms') {
65075               result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
65076               .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
65077               .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
65078             } else if (source.type === 'bing') {
65079               result = result.replace('{u}', function () {
65080                 var u = '';
65081
65082                 for (var zoom = coord[2]; zoom > 0; zoom--) {
65083                   var b = 0;
65084                   var mask = 1 << zoom - 1;
65085                   if ((coord[0] & mask) !== 0) b++;
65086                   if ((coord[1] & mask) !== 0) b += 2;
65087                   u += b.toString();
65088                 }
65089
65090                 return u;
65091               });
65092             } // these apply to any type..
65093
65094
65095             result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
65096               var subdomains = r.split(',');
65097               return subdomains[(coord[0] + coord[1]) % subdomains.length];
65098             });
65099             return result;
65100           };
65101
65102           source.validZoom = function (z) {
65103             return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
65104           };
65105
65106           source.isLocatorOverlay = function () {
65107             return source.id === 'mapbox_locator_overlay';
65108           };
65109           /* hides a source from the list, but leaves it available for use */
65110
65111
65112           source.isHidden = function () {
65113             return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
65114           };
65115
65116           source.copyrightNotices = function () {};
65117
65118           source.getMetadata = function (center, tileCoord, callback) {
65119             var vintage = {
65120               start: localeDateString(source.startDate),
65121               end: localeDateString(source.endDate)
65122             };
65123             vintage.range = vintageRange(vintage);
65124             var metadata = {
65125               vintage: vintage
65126             };
65127             callback(null, metadata);
65128           };
65129
65130           return source;
65131         }
65132
65133         rendererBackgroundSource.Bing = function (data, dispatch) {
65134           // http://msdn.microsoft.com/en-us/library/ff701716.aspx
65135           // http://msdn.microsoft.com/en-us/library/ff701701.aspx
65136           data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
65137           var bing = rendererBackgroundSource(data); // var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
65138
65139           var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
65140
65141           var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' + key;
65142           var cache = {};
65143           var inflight = {};
65144           var providers = [];
65145           d3_json(url).then(function (json) {
65146             providers = json.resourceSets[0].resources[0].imageryProviders.map(function (provider) {
65147               return {
65148                 attribution: provider.attribution,
65149                 areas: provider.coverageAreas.map(function (area) {
65150                   return {
65151                     zoom: [area.zoomMin, area.zoomMax],
65152                     extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
65153                   };
65154                 })
65155               };
65156             });
65157             dispatch.call('change');
65158           })["catch"](function () {
65159             /* ignore */
65160           });
65161
65162           bing.copyrightNotices = function (zoom, extent) {
65163             zoom = Math.min(zoom, 21);
65164             return providers.filter(function (provider) {
65165               return provider.areas.some(function (area) {
65166                 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
65167               });
65168             }).map(function (provider) {
65169               return provider.attribution;
65170             }).join(', ');
65171           };
65172
65173           bing.getMetadata = function (center, tileCoord, callback) {
65174             var tileID = tileCoord.slice(0, 3).join('/');
65175             var zoom = Math.min(tileCoord[2], 21);
65176             var centerPoint = center[1] + ',' + center[0]; // lat,lng
65177
65178             var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
65179             if (inflight[tileID]) return;
65180
65181             if (!cache[tileID]) {
65182               cache[tileID] = {};
65183             }
65184
65185             if (cache[tileID] && cache[tileID].metadata) {
65186               return callback(null, cache[tileID].metadata);
65187             }
65188
65189             inflight[tileID] = true;
65190             d3_json(url).then(function (result) {
65191               delete inflight[tileID];
65192
65193               if (!result) {
65194                 throw new Error('Unknown Error');
65195               }
65196
65197               var vintage = {
65198                 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
65199                 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
65200               };
65201               vintage.range = vintageRange(vintage);
65202               var metadata = {
65203                 vintage: vintage
65204               };
65205               cache[tileID].metadata = metadata;
65206               if (callback) callback(null, metadata);
65207             })["catch"](function (err) {
65208               delete inflight[tileID];
65209               if (callback) callback(err.message);
65210             });
65211           };
65212
65213           bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
65214           return bing;
65215         };
65216
65217         rendererBackgroundSource.Esri = function (data) {
65218           // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
65219           if (data.template.match(/blankTile/) === null) {
65220             data.template = data.template + '?blankTile=false';
65221           }
65222
65223           var esri = rendererBackgroundSource(data);
65224           var cache = {};
65225           var inflight = {};
65226
65227           var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
65228           // https://developers.arcgis.com/documentation/tiled-elevation-service/
65229
65230
65231           esri.fetchTilemap = function (center) {
65232             // skip if we have already fetched a tilemap within 5km
65233             if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
65234             _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
65235
65236             var z = 20; // first generate a random url using the template
65237
65238             var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
65239
65240             var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
65241             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
65242
65243             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
65244
65245             d3_json(tilemapUrl).then(function (tilemap) {
65246               if (!tilemap) {
65247                 throw new Error('Unknown Error');
65248               }
65249
65250               var hasTiles = true;
65251
65252               for (var i = 0; i < tilemap.data.length; i++) {
65253                 // 0 means an individual tile in the grid doesn't exist
65254                 if (!tilemap.data[i]) {
65255                   hasTiles = false;
65256                   break;
65257                 }
65258               } // if any tiles are missing at level 20 we restrict maxZoom to 19
65259
65260
65261               esri.zoomExtent[1] = hasTiles ? 22 : 19;
65262             })["catch"](function () {
65263               /* ignore */
65264             });
65265           };
65266
65267           esri.getMetadata = function (center, tileCoord, callback) {
65268             var tileID = tileCoord.slice(0, 3).join('/');
65269             var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
65270             var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
65271
65272             var unknown = _t('info_panels.background.unknown');
65273             var metadataLayer;
65274             var vintage = {};
65275             var metadata = {};
65276             if (inflight[tileID]) return;
65277
65278             switch (true) {
65279               case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
65280                 metadataLayer = 4;
65281                 break;
65282
65283               case zoom >= 19:
65284                 metadataLayer = 3;
65285                 break;
65286
65287               case zoom >= 17:
65288                 metadataLayer = 2;
65289                 break;
65290
65291               case zoom >= 13:
65292                 metadataLayer = 0;
65293                 break;
65294
65295               default:
65296                 metadataLayer = 99;
65297             }
65298
65299             var url; // build up query using the layer appropriate to the current zoom
65300
65301             if (esri.id === 'EsriWorldImagery') {
65302               url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
65303             } else if (esri.id === 'EsriWorldImageryClarity') {
65304               url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
65305             }
65306
65307             url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
65308
65309             if (!cache[tileID]) {
65310               cache[tileID] = {};
65311             }
65312
65313             if (cache[tileID] && cache[tileID].metadata) {
65314               return callback(null, cache[tileID].metadata);
65315             } // accurate metadata is only available >= 13
65316
65317
65318             if (metadataLayer === 99) {
65319               vintage = {
65320                 start: null,
65321                 end: null,
65322                 range: null
65323               };
65324               metadata = {
65325                 vintage: null,
65326                 source: unknown,
65327                 description: unknown,
65328                 resolution: unknown,
65329                 accuracy: unknown
65330               };
65331               callback(null, metadata);
65332             } else {
65333               inflight[tileID] = true;
65334               d3_json(url).then(function (result) {
65335                 delete inflight[tileID];
65336
65337                 if (!result) {
65338                   throw new Error('Unknown Error');
65339                 } else if (result.features && result.features.length < 1) {
65340                   throw new Error('No Results');
65341                 } else if (result.error && result.error.message) {
65342                   throw new Error(result.error.message);
65343                 } // pass through the discrete capture date from metadata
65344
65345
65346                 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
65347                 vintage = {
65348                   start: captureDate,
65349                   end: captureDate,
65350                   range: captureDate
65351                 };
65352                 metadata = {
65353                   vintage: vintage,
65354                   source: clean(result.features[0].attributes.NICE_NAME),
65355                   description: clean(result.features[0].attributes.NICE_DESC),
65356                   resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
65357                   accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
65358                 }; // append units - meters
65359
65360                 if (isFinite(metadata.resolution)) {
65361                   metadata.resolution += ' m';
65362                 }
65363
65364                 if (isFinite(metadata.accuracy)) {
65365                   metadata.accuracy += ' m';
65366                 }
65367
65368                 cache[tileID].metadata = metadata;
65369                 if (callback) callback(null, metadata);
65370               })["catch"](function (err) {
65371                 delete inflight[tileID];
65372                 if (callback) callback(err.message);
65373               });
65374             }
65375
65376             function clean(val) {
65377               return String(val).trim() || unknown;
65378             }
65379           };
65380
65381           return esri;
65382         };
65383
65384         rendererBackgroundSource.None = function () {
65385           var source = rendererBackgroundSource({
65386             id: 'none',
65387             template: ''
65388           });
65389
65390           source.name = function () {
65391             return _t('background.none');
65392           };
65393
65394           source.label = function () {
65395             return _t.html('background.none');
65396           };
65397
65398           source.imageryUsed = function () {
65399             return null;
65400           };
65401
65402           source.area = function () {
65403             return -1; // sources in background pane are sorted by area
65404           };
65405
65406           return source;
65407         };
65408
65409         rendererBackgroundSource.Custom = function (template) {
65410           var source = rendererBackgroundSource({
65411             id: 'custom',
65412             template: template
65413           });
65414
65415           source.name = function () {
65416             return _t('background.custom');
65417           };
65418
65419           source.label = function () {
65420             return _t.html('background.custom');
65421           };
65422
65423           source.imageryUsed = function () {
65424             // sanitize personal connection tokens - #6801
65425             var cleaned = source.template(); // from query string parameters
65426
65427             if (cleaned.indexOf('?') !== -1) {
65428               var parts = cleaned.split('?', 2);
65429               var qs = utilStringQs(parts[1]);
65430               ['access_token', 'connectId', 'token'].forEach(function (param) {
65431                 if (qs[param]) {
65432                   qs[param] = '{apikey}';
65433                 }
65434               });
65435               cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
65436             } // from wms/wmts api path parameters
65437
65438
65439             cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
65440             return 'Custom (' + cleaned + ' )';
65441           };
65442
65443           source.area = function () {
65444             return -2; // sources in background pane are sorted by area
65445           };
65446
65447           return source;
65448         };
65449
65450         function rendererTileLayer(context) {
65451           var transformProp = utilPrefixCSSProperty('Transform');
65452           var tiler = utilTiler();
65453           var _tileSize = 256;
65454
65455           var _projection;
65456
65457           var _cache = {};
65458
65459           var _tileOrigin;
65460
65461           var _zoom;
65462
65463           var _source;
65464
65465           function tileSizeAtZoom(d, z) {
65466             var EPSILON = 0.002; // close seams
65467
65468             return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
65469           }
65470
65471           function atZoom(t, distance) {
65472             var power = Math.pow(2, distance);
65473             return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
65474           }
65475
65476           function lookUp(d) {
65477             for (var up = -1; up > -d[2]; up--) {
65478               var tile = atZoom(d, up);
65479
65480               if (_cache[_source.url(tile)] !== false) {
65481                 return tile;
65482               }
65483             }
65484           }
65485
65486           function uniqueBy(a, n) {
65487             var o = [];
65488             var seen = {};
65489
65490             for (var i = 0; i < a.length; i++) {
65491               if (seen[a[i][n]] === undefined) {
65492                 o.push(a[i]);
65493                 seen[a[i][n]] = true;
65494               }
65495             }
65496
65497             return o;
65498           }
65499
65500           function addSource(d) {
65501             d.push(_source.url(d));
65502             return d;
65503           } // Update tiles based on current state of `projection`.
65504
65505
65506           function background(selection) {
65507             _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
65508             var pixelOffset;
65509
65510             if (_source) {
65511               pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
65512             } else {
65513               pixelOffset = [0, 0];
65514             }
65515
65516             var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
65517             tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
65518             _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
65519             render(selection);
65520           } // Derive the tiles onscreen, remove those offscreen and position them.
65521           // Important that this part not depend on `_projection` because it's
65522           // rentered when tiles load/error (see #644).
65523
65524
65525           function render(selection) {
65526             if (!_source) return;
65527             var requests = [];
65528             var showDebug = context.getDebug('tile') && !_source.overlay;
65529
65530             if (_source.validZoom(_zoom)) {
65531               tiler.skipNullIsland(!!_source.overlay);
65532               tiler().forEach(function (d) {
65533                 addSource(d);
65534                 if (d[3] === '') return;
65535                 if (typeof d[3] !== 'string') return; // Workaround for #2295
65536
65537                 requests.push(d);
65538
65539                 if (_cache[d[3]] === false && lookUp(d)) {
65540                   requests.push(addSource(lookUp(d)));
65541                 }
65542               });
65543               requests = uniqueBy(requests, 3).filter(function (r) {
65544                 // don't re-request tiles which have failed in the past
65545                 return _cache[r[3]] !== false;
65546               });
65547             }
65548
65549             function load(d3_event, d) {
65550               _cache[d[3]] = true;
65551               select(this).on('error', null).on('load', null).classed('tile-loaded', true);
65552               render(selection);
65553             }
65554
65555             function error(d3_event, d) {
65556               _cache[d[3]] = false;
65557               select(this).on('error', null).on('load', null).remove();
65558               render(selection);
65559             }
65560
65561             function imageTransform(d) {
65562               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
65563
65564               var scale = tileSizeAtZoom(d, _zoom);
65565               return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
65566             }
65567
65568             function tileCenter(d) {
65569               var ts = _tileSize * Math.pow(2, _zoom - d[2]);
65570
65571               return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
65572             }
65573
65574             function debugTransform(d) {
65575               var coord = tileCenter(d);
65576               return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
65577             } // Pick a representative tile near the center of the viewport
65578             // (This is useful for sampling the imagery vintage)
65579
65580
65581             var dims = tiler.size();
65582             var mapCenter = [dims[0] / 2, dims[1] / 2];
65583             var minDist = Math.max(dims[0], dims[1]);
65584             var nearCenter;
65585             requests.forEach(function (d) {
65586               var c = tileCenter(d);
65587               var dist = geoVecLength(c, mapCenter);
65588
65589               if (dist < minDist) {
65590                 minDist = dist;
65591                 nearCenter = d;
65592               }
65593             });
65594             var image = selection.selectAll('img').data(requests, function (d) {
65595               return d[3];
65596             });
65597             image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
65598               var tile = select(this);
65599               window.setTimeout(function () {
65600                 if (tile.classed('tile-removing')) {
65601                   tile.remove();
65602                 }
65603               }, 300);
65604             });
65605             image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
65606               return d[3];
65607             }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
65608               return d === nearCenter;
65609             });
65610             var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
65611               return d[3];
65612             });
65613             debug.exit().remove();
65614
65615             if (showDebug) {
65616               var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
65617               debugEnter.append('div').attr('class', 'tile-label-debug-coord');
65618               debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
65619               debug = debug.merge(debugEnter);
65620               debug.style(transformProp, debugTransform);
65621               debug.selectAll('.tile-label-debug-coord').html(function (d) {
65622                 return d[2] + ' / ' + d[0] + ' / ' + d[1];
65623               });
65624               debug.selectAll('.tile-label-debug-vintage').each(function (d) {
65625                 var span = select(this);
65626                 var center = context.projection.invert(tileCenter(d));
65627
65628                 _source.getMetadata(center, d, function (err, result) {
65629                   span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
65630                 });
65631               });
65632             }
65633           }
65634
65635           background.projection = function (val) {
65636             if (!arguments.length) return _projection;
65637             _projection = val;
65638             return background;
65639           };
65640
65641           background.dimensions = function (val) {
65642             if (!arguments.length) return tiler.size();
65643             tiler.size(val);
65644             return background;
65645           };
65646
65647           background.source = function (val) {
65648             if (!arguments.length) return _source;
65649             _source = val;
65650             _tileSize = _source.tileSize;
65651             _cache = {};
65652             tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
65653             return background;
65654           };
65655
65656           return background;
65657         }
65658
65659         var _imageryIndex = null;
65660         function rendererBackground(context) {
65661           var dispatch$1 = dispatch('change');
65662           var detected = utilDetect();
65663           var baseLayer = rendererTileLayer(context).projection(context.projection);
65664           var _isValid = true;
65665           var _overlayLayers = [];
65666           var _brightness = 1;
65667           var _contrast = 1;
65668           var _saturation = 1;
65669           var _sharpness = 1;
65670
65671           function ensureImageryIndex() {
65672             return _mainFileFetcher.get('imagery').then(function (sources) {
65673               if (_imageryIndex) return _imageryIndex;
65674               _imageryIndex = {
65675                 imagery: sources,
65676                 features: {}
65677               }; // use which-polygon to support efficient index and querying for imagery
65678
65679               var features = sources.map(function (source) {
65680                 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
65681                 // Add an extra array nest to each element in `source.polygon`
65682                 // so the rings are not treated as a bunch of holes:
65683                 // what we have: [ [[outer],[hole],[hole]] ]
65684                 // what we want: [ [[outer]],[[outer]],[[outer]] ]
65685
65686                 var rings = source.polygon.map(function (ring) {
65687                   return [ring];
65688                 });
65689                 var feature = {
65690                   type: 'Feature',
65691                   properties: {
65692                     id: source.id
65693                   },
65694                   geometry: {
65695                     type: 'MultiPolygon',
65696                     coordinates: rings
65697                   }
65698                 };
65699                 _imageryIndex.features[source.id] = feature;
65700                 return feature;
65701               }).filter(Boolean);
65702               _imageryIndex.query = whichPolygon_1({
65703                 type: 'FeatureCollection',
65704                 features: features
65705               }); // Instantiate `rendererBackgroundSource` objects for each source
65706
65707               _imageryIndex.backgrounds = sources.map(function (source) {
65708                 if (source.type === 'bing') {
65709                   return rendererBackgroundSource.Bing(source, dispatch$1);
65710                 } else if (/^EsriWorldImagery/.test(source.id)) {
65711                   return rendererBackgroundSource.Esri(source);
65712                 } else {
65713                   return rendererBackgroundSource(source);
65714                 }
65715               }); // Add 'None'
65716
65717               _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
65718
65719
65720               var template = corePreferences('background-custom-template') || '';
65721               var custom = rendererBackgroundSource.Custom(template);
65722
65723               _imageryIndex.backgrounds.unshift(custom);
65724
65725               return _imageryIndex;
65726             });
65727           }
65728
65729           function background(selection) {
65730             var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
65731             // check its tilemap to see how high the zoom can go
65732
65733             if (context.map().zoom() > 18) {
65734               if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
65735                 var center = context.map().center();
65736                 currSource.fetchTilemap(center);
65737               }
65738             } // Is the imagery valid here? - #4827
65739
65740
65741             var sources = background.sources(context.map().extent());
65742             var wasValid = _isValid;
65743             _isValid = !!sources.filter(function (d) {
65744               return d === currSource;
65745             }).length;
65746
65747             if (wasValid !== _isValid) {
65748               // change in valid status
65749               background.updateImagery();
65750             }
65751
65752             var baseFilter = '';
65753
65754             if (detected.cssfilters) {
65755               if (_brightness !== 1) {
65756                 baseFilter += " brightness(".concat(_brightness, ")");
65757               }
65758
65759               if (_contrast !== 1) {
65760                 baseFilter += " contrast(".concat(_contrast, ")");
65761               }
65762
65763               if (_saturation !== 1) {
65764                 baseFilter += " saturate(".concat(_saturation, ")");
65765               }
65766
65767               if (_sharpness < 1) {
65768                 // gaussian blur
65769                 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
65770                 baseFilter += " blur(".concat(blur, "px)");
65771               }
65772             }
65773
65774             var base = selection.selectAll('.layer-background').data([0]);
65775             base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
65776
65777             if (detected.cssfilters) {
65778               base.style('filter', baseFilter || null);
65779             } else {
65780               base.style('opacity', _brightness);
65781             }
65782
65783             var imagery = base.selectAll('.layer-imagery').data([0]);
65784             imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
65785             var maskFilter = '';
65786             var mixBlendMode = '';
65787
65788             if (detected.cssfilters && _sharpness > 1) {
65789               // apply unsharp mask
65790               mixBlendMode = 'overlay';
65791               maskFilter = 'saturate(0) blur(3px) invert(1)';
65792               var contrast = _sharpness - 1;
65793               maskFilter += " contrast(".concat(contrast, ")");
65794               var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
65795               maskFilter += " brightness(".concat(brightness, ")");
65796             }
65797
65798             var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
65799             mask.exit().remove();
65800             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);
65801             var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
65802               return d.source().name();
65803             });
65804             overlays.exit().remove();
65805             overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
65806               return select(nodes[i]).call(layer);
65807             });
65808           }
65809
65810           background.updateImagery = function () {
65811             var currSource = baseLayer.source();
65812             if (context.inIntro() || !currSource) return;
65813
65814             var o = _overlayLayers.filter(function (d) {
65815               return !d.source().isLocatorOverlay() && !d.source().isHidden();
65816             }).map(function (d) {
65817               return d.source().id;
65818             }).join(',');
65819
65820             var meters = geoOffsetToMeters(currSource.offset());
65821             var EPSILON = 0.01;
65822             var x = +meters[0].toFixed(2);
65823             var y = +meters[1].toFixed(2);
65824             var hash = utilStringQs(window.location.hash);
65825             var id = currSource.id;
65826
65827             if (id === 'custom') {
65828               id = "custom:".concat(currSource.template());
65829             }
65830
65831             if (id) {
65832               hash.background = id;
65833             } else {
65834               delete hash.background;
65835             }
65836
65837             if (o) {
65838               hash.overlays = o;
65839             } else {
65840               delete hash.overlays;
65841             }
65842
65843             if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
65844               hash.offset = "".concat(x, ",").concat(y);
65845             } else {
65846               delete hash.offset;
65847             }
65848
65849             if (!window.mocha) {
65850               window.location.replace('#' + utilQsString(hash, true));
65851             }
65852
65853             var imageryUsed = [];
65854             var photoOverlaysUsed = [];
65855             var currUsed = currSource.imageryUsed();
65856
65857             if (currUsed && _isValid) {
65858               imageryUsed.push(currUsed);
65859             }
65860
65861             _overlayLayers.filter(function (d) {
65862               return !d.source().isLocatorOverlay() && !d.source().isHidden();
65863             }).forEach(function (d) {
65864               return imageryUsed.push(d.source().imageryUsed());
65865             });
65866
65867             var dataLayer = context.layers().layer('data');
65868
65869             if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
65870               imageryUsed.push(dataLayer.getSrc());
65871             }
65872
65873             var photoOverlayLayers = {
65874               streetside: 'Bing Streetside',
65875               mapillary: 'Mapillary Images',
65876               'mapillary-map-features': 'Mapillary Map Features',
65877               'mapillary-signs': 'Mapillary Signs',
65878               openstreetcam: 'OpenStreetCam Images'
65879             };
65880
65881             for (var layerID in photoOverlayLayers) {
65882               var layer = context.layers().layer(layerID);
65883
65884               if (layer && layer.enabled()) {
65885                 photoOverlaysUsed.push(layerID);
65886                 imageryUsed.push(photoOverlayLayers[layerID]);
65887               }
65888             }
65889
65890             context.history().imageryUsed(imageryUsed);
65891             context.history().photoOverlaysUsed(photoOverlaysUsed);
65892           };
65893
65894           var _checkedBlocklists;
65895
65896           background.sources = function (extent, zoom, includeCurrent) {
65897             if (!_imageryIndex) return []; // called before init()?
65898
65899             var visible = {};
65900             (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
65901               return visible[d.id] = true;
65902             });
65903             var currSource = baseLayer.source();
65904             var osm = context.connection();
65905             var blocklists = osm && osm.imageryBlocklists();
65906
65907             if (blocklists && blocklists !== _checkedBlocklists) {
65908               _imageryIndex.backgrounds.forEach(function (source) {
65909                 source.isBlocked = blocklists.some(function (blocklist) {
65910                   return blocklist.test(source.template());
65911                 });
65912               });
65913
65914               _checkedBlocklists = blocklists;
65915             }
65916
65917             return _imageryIndex.backgrounds.filter(function (source) {
65918               if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
65919
65920               if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
65921
65922               if (!source.polygon) return true; // always include imagery with worldwide coverage
65923
65924               if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
65925
65926               return visible[source.id]; // include imagery visible in given extent
65927             });
65928           };
65929
65930           background.dimensions = function (val) {
65931             if (!val) return;
65932             baseLayer.dimensions(val);
65933
65934             _overlayLayers.forEach(function (layer) {
65935               return layer.dimensions(val);
65936             });
65937           };
65938
65939           background.baseLayerSource = function (d) {
65940             if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
65941
65942             var osm = context.connection();
65943             if (!osm) return background;
65944             var blocklists = osm.imageryBlocklists();
65945             var template = d.template();
65946             var fail = false;
65947             var tested = 0;
65948             var regex;
65949
65950             for (var i = 0; i < blocklists.length; i++) {
65951               regex = blocklists[i];
65952               fail = regex.test(template);
65953               tested++;
65954               if (fail) break;
65955             } // ensure at least one test was run.
65956
65957
65958             if (!tested) {
65959               regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
65960               fail = regex.test(template);
65961             }
65962
65963             baseLayer.source(!fail ? d : background.findSource('none'));
65964             dispatch$1.call('change');
65965             background.updateImagery();
65966             return background;
65967           };
65968
65969           background.findSource = function (id) {
65970             if (!id || !_imageryIndex) return null; // called before init()?
65971
65972             return _imageryIndex.backgrounds.find(function (d) {
65973               return d.id && d.id === id;
65974             });
65975           };
65976
65977           background.bing = function () {
65978             background.baseLayerSource(background.findSource('Bing'));
65979           };
65980
65981           background.showsLayer = function (d) {
65982             var currSource = baseLayer.source();
65983             if (!d || !currSource) return false;
65984             return d.id === currSource.id || _overlayLayers.some(function (layer) {
65985               return d.id === layer.source().id;
65986             });
65987           };
65988
65989           background.overlayLayerSources = function () {
65990             return _overlayLayers.map(function (layer) {
65991               return layer.source();
65992             });
65993           };
65994
65995           background.toggleOverlayLayer = function (d) {
65996             var layer;
65997
65998             for (var i = 0; i < _overlayLayers.length; i++) {
65999               layer = _overlayLayers[i];
66000
66001               if (layer.source() === d) {
66002                 _overlayLayers.splice(i, 1);
66003
66004                 dispatch$1.call('change');
66005                 background.updateImagery();
66006                 return;
66007               }
66008             }
66009
66010             layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
66011
66012             _overlayLayers.push(layer);
66013
66014             dispatch$1.call('change');
66015             background.updateImagery();
66016           };
66017
66018           background.nudge = function (d, zoom) {
66019             var currSource = baseLayer.source();
66020
66021             if (currSource) {
66022               currSource.nudge(d, zoom);
66023               dispatch$1.call('change');
66024               background.updateImagery();
66025             }
66026
66027             return background;
66028           };
66029
66030           background.offset = function (d) {
66031             var currSource = baseLayer.source();
66032
66033             if (!arguments.length) {
66034               return currSource && currSource.offset() || [0, 0];
66035             }
66036
66037             if (currSource) {
66038               currSource.offset(d);
66039               dispatch$1.call('change');
66040               background.updateImagery();
66041             }
66042
66043             return background;
66044           };
66045
66046           background.brightness = function (d) {
66047             if (!arguments.length) return _brightness;
66048             _brightness = d;
66049             if (context.mode()) dispatch$1.call('change');
66050             return background;
66051           };
66052
66053           background.contrast = function (d) {
66054             if (!arguments.length) return _contrast;
66055             _contrast = d;
66056             if (context.mode()) dispatch$1.call('change');
66057             return background;
66058           };
66059
66060           background.saturation = function (d) {
66061             if (!arguments.length) return _saturation;
66062             _saturation = d;
66063             if (context.mode()) dispatch$1.call('change');
66064             return background;
66065           };
66066
66067           background.sharpness = function (d) {
66068             if (!arguments.length) return _sharpness;
66069             _sharpness = d;
66070             if (context.mode()) dispatch$1.call('change');
66071             return background;
66072           };
66073
66074           var _loadPromise;
66075
66076           background.ensureLoaded = function () {
66077             if (_loadPromise) return _loadPromise;
66078
66079             function parseMapParams(qmap) {
66080               if (!qmap) return false;
66081               var params = qmap.split('/').map(Number);
66082               if (params.length < 3 || params.some(isNaN)) return false;
66083               return geoExtent([params[2], params[1]]); // lon,lat
66084             }
66085
66086             var hash = utilStringQs(window.location.hash);
66087             var requested = hash.background || hash.layer;
66088             var extent = parseMapParams(hash.map);
66089             return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
66090               var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
66091               var best;
66092
66093               if (!requested && extent) {
66094                 best = background.sources(extent).find(function (s) {
66095                   return s.best();
66096                 });
66097               } // Decide which background layer to display
66098
66099
66100               if (requested && requested.indexOf('custom:') === 0) {
66101                 var template = requested.replace(/^custom:/, '');
66102                 var custom = background.findSource('custom');
66103                 background.baseLayerSource(custom.template(template));
66104                 corePreferences('background-custom-template', template);
66105               } else {
66106                 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
66107               }
66108
66109               var locator = imageryIndex.backgrounds.find(function (d) {
66110                 return d.overlay && d["default"];
66111               });
66112
66113               if (locator) {
66114                 background.toggleOverlayLayer(locator);
66115               }
66116
66117               var overlays = (hash.overlays || '').split(',');
66118               overlays.forEach(function (overlay) {
66119                 overlay = background.findSource(overlay);
66120
66121                 if (overlay) {
66122                   background.toggleOverlayLayer(overlay);
66123                 }
66124               });
66125
66126               if (hash.gpx) {
66127                 var gpx = context.layers().layer('data');
66128
66129                 if (gpx) {
66130                   gpx.url(hash.gpx, '.gpx');
66131                 }
66132               }
66133
66134               if (hash.offset) {
66135                 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
66136                   return !isNaN(n) && n;
66137                 });
66138
66139                 if (offset.length === 2) {
66140                   background.offset(geoMetersToOffset(offset));
66141                 }
66142               }
66143             })["catch"](function () {
66144               /* ignore */
66145             });
66146           };
66147
66148           return utilRebind(background, dispatch$1, 'on');
66149         }
66150
66151         function rendererFeatures(context) {
66152           var dispatch$1 = dispatch('change', 'redraw');
66153           var features = utilRebind({}, dispatch$1, 'on');
66154
66155           var _deferred = new Set();
66156
66157           var traffic_roads = {
66158             'motorway': true,
66159             'motorway_link': true,
66160             'trunk': true,
66161             'trunk_link': true,
66162             'primary': true,
66163             'primary_link': true,
66164             'secondary': true,
66165             'secondary_link': true,
66166             'tertiary': true,
66167             'tertiary_link': true,
66168             'residential': true,
66169             'unclassified': true,
66170             'living_street': true
66171           };
66172           var service_roads = {
66173             'service': true,
66174             'road': true,
66175             'track': true
66176           };
66177           var paths = {
66178             'path': true,
66179             'footway': true,
66180             'cycleway': true,
66181             'bridleway': true,
66182             'steps': true,
66183             'pedestrian': true
66184           };
66185           var past_futures = {
66186             'proposed': true,
66187             'construction': true,
66188             'abandoned': true,
66189             'dismantled': true,
66190             'disused': true,
66191             'razed': true,
66192             'demolished': true,
66193             'obliterated': true
66194           };
66195           var _cullFactor = 1;
66196           var _cache = {};
66197           var _rules = {};
66198           var _stats = {};
66199           var _keys = [];
66200           var _hidden = [];
66201           var _forceVisible = {};
66202
66203           function update() {
66204             if (!window.mocha) {
66205               var hash = utilStringQs(window.location.hash);
66206               var disabled = features.disabled();
66207
66208               if (disabled.length) {
66209                 hash.disable_features = disabled.join(',');
66210               } else {
66211                 delete hash.disable_features;
66212               }
66213
66214               window.location.replace('#' + utilQsString(hash, true));
66215               corePreferences('disabled-features', disabled.join(','));
66216             }
66217
66218             _hidden = features.hidden();
66219             dispatch$1.call('change');
66220             dispatch$1.call('redraw');
66221           }
66222
66223           function defineRule(k, filter, max) {
66224             var isEnabled = true;
66225
66226             _keys.push(k);
66227
66228             _rules[k] = {
66229               filter: filter,
66230               enabled: isEnabled,
66231               // whether the user wants it enabled..
66232               count: 0,
66233               currentMax: max || Infinity,
66234               defaultMax: max || Infinity,
66235               enable: function enable() {
66236                 this.enabled = true;
66237                 this.currentMax = this.defaultMax;
66238               },
66239               disable: function disable() {
66240                 this.enabled = false;
66241                 this.currentMax = 0;
66242               },
66243               hidden: function hidden() {
66244                 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
66245               },
66246               autoHidden: function autoHidden() {
66247                 return this.hidden() && this.currentMax > 0;
66248               }
66249             };
66250           }
66251
66252           defineRule('points', function isPoint(tags, geometry) {
66253             return geometry === 'point';
66254           }, 200);
66255           defineRule('traffic_roads', function isTrafficRoad(tags) {
66256             return traffic_roads[tags.highway];
66257           });
66258           defineRule('service_roads', function isServiceRoad(tags) {
66259             return service_roads[tags.highway];
66260           });
66261           defineRule('paths', function isPath(tags) {
66262             return paths[tags.highway];
66263           });
66264           defineRule('buildings', function isBuilding(tags) {
66265             return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
66266           }, 250);
66267           defineRule('building_parts', function isBuildingPart(tags) {
66268             return tags['building:part'];
66269           });
66270           defineRule('indoor', function isIndoor(tags) {
66271             return tags.indoor;
66272           });
66273           defineRule('landuse', function isLanduse(tags, geometry) {
66274             return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
66275           });
66276           defineRule('boundaries', function isBoundary(tags) {
66277             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);
66278           });
66279           defineRule('water', function isWater(tags) {
66280             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';
66281           });
66282           defineRule('rail', function isRail(tags) {
66283             return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
66284           });
66285           defineRule('pistes', function isPiste(tags) {
66286             return tags['piste:type'];
66287           });
66288           defineRule('aerialways', function isPiste(tags) {
66289             return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
66290           });
66291           defineRule('power', function isPower(tags) {
66292             return !!tags.power;
66293           }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
66294
66295           defineRule('past_future', function isPastFuture(tags) {
66296             if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
66297               return false;
66298             }
66299
66300             var strings = Object.keys(tags);
66301
66302             for (var i = 0; i < strings.length; i++) {
66303               var s = strings[i];
66304
66305               if (past_futures[s] || past_futures[tags[s]]) {
66306                 return true;
66307               }
66308             }
66309
66310             return false;
66311           }); // Lines or areas that don't match another feature filter.
66312           // IMPORTANT: The 'others' feature must be the last one defined,
66313           //   so that code in getMatches can skip this test if `hasMatch = true`
66314
66315           defineRule('others', function isOther(tags, geometry) {
66316             return geometry === 'line' || geometry === 'area';
66317           });
66318
66319           features.features = function () {
66320             return _rules;
66321           };
66322
66323           features.keys = function () {
66324             return _keys;
66325           };
66326
66327           features.enabled = function (k) {
66328             if (!arguments.length) {
66329               return _keys.filter(function (k) {
66330                 return _rules[k].enabled;
66331               });
66332             }
66333
66334             return _rules[k] && _rules[k].enabled;
66335           };
66336
66337           features.disabled = function (k) {
66338             if (!arguments.length) {
66339               return _keys.filter(function (k) {
66340                 return !_rules[k].enabled;
66341               });
66342             }
66343
66344             return _rules[k] && !_rules[k].enabled;
66345           };
66346
66347           features.hidden = function (k) {
66348             if (!arguments.length) {
66349               return _keys.filter(function (k) {
66350                 return _rules[k].hidden();
66351               });
66352             }
66353
66354             return _rules[k] && _rules[k].hidden();
66355           };
66356
66357           features.autoHidden = function (k) {
66358             if (!arguments.length) {
66359               return _keys.filter(function (k) {
66360                 return _rules[k].autoHidden();
66361               });
66362             }
66363
66364             return _rules[k] && _rules[k].autoHidden();
66365           };
66366
66367           features.enable = function (k) {
66368             if (_rules[k] && !_rules[k].enabled) {
66369               _rules[k].enable();
66370
66371               update();
66372             }
66373           };
66374
66375           features.enableAll = function () {
66376             var didEnable = false;
66377
66378             for (var k in _rules) {
66379               if (!_rules[k].enabled) {
66380                 didEnable = true;
66381
66382                 _rules[k].enable();
66383               }
66384             }
66385
66386             if (didEnable) update();
66387           };
66388
66389           features.disable = function (k) {
66390             if (_rules[k] && _rules[k].enabled) {
66391               _rules[k].disable();
66392
66393               update();
66394             }
66395           };
66396
66397           features.disableAll = function () {
66398             var didDisable = false;
66399
66400             for (var k in _rules) {
66401               if (_rules[k].enabled) {
66402                 didDisable = true;
66403
66404                 _rules[k].disable();
66405               }
66406             }
66407
66408             if (didDisable) update();
66409           };
66410
66411           features.toggle = function (k) {
66412             if (_rules[k]) {
66413               (function (f) {
66414                 return f.enabled ? f.disable() : f.enable();
66415               })(_rules[k]);
66416
66417               update();
66418             }
66419           };
66420
66421           features.resetStats = function () {
66422             for (var i = 0; i < _keys.length; i++) {
66423               _rules[_keys[i]].count = 0;
66424             }
66425
66426             dispatch$1.call('change');
66427           };
66428
66429           features.gatherStats = function (d, resolver, dimensions) {
66430             var needsRedraw = false;
66431             var types = utilArrayGroupBy(d, 'type');
66432             var entities = [].concat(types.relation || [], types.way || [], types.node || []);
66433             var currHidden, geometry, matches, i, j;
66434
66435             for (i = 0; i < _keys.length; i++) {
66436               _rules[_keys[i]].count = 0;
66437             } // adjust the threshold for point/building culling based on viewport size..
66438             // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
66439
66440
66441             _cullFactor = dimensions[0] * dimensions[1] / 1000000;
66442
66443             for (i = 0; i < entities.length; i++) {
66444               geometry = entities[i].geometry(resolver);
66445               matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
66446
66447               for (j = 0; j < matches.length; j++) {
66448                 _rules[matches[j]].count++;
66449               }
66450             }
66451
66452             currHidden = features.hidden();
66453
66454             if (currHidden !== _hidden) {
66455               _hidden = currHidden;
66456               needsRedraw = true;
66457               dispatch$1.call('change');
66458             }
66459
66460             return needsRedraw;
66461           };
66462
66463           features.stats = function () {
66464             for (var i = 0; i < _keys.length; i++) {
66465               _stats[_keys[i]] = _rules[_keys[i]].count;
66466             }
66467
66468             return _stats;
66469           };
66470
66471           features.clear = function (d) {
66472             for (var i = 0; i < d.length; i++) {
66473               features.clearEntity(d[i]);
66474             }
66475           };
66476
66477           features.clearEntity = function (entity) {
66478             delete _cache[osmEntity.key(entity)];
66479           };
66480
66481           features.reset = function () {
66482             Array.from(_deferred).forEach(function (handle) {
66483               window.cancelIdleCallback(handle);
66484
66485               _deferred["delete"](handle);
66486             });
66487             _cache = {};
66488           }; // only certain relations are worth checking
66489
66490
66491           function relationShouldBeChecked(relation) {
66492             // multipolygon features have `area` geometry and aren't checked here
66493             return relation.tags.type === 'boundary';
66494           }
66495
66496           features.getMatches = function (entity, resolver, geometry) {
66497             if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
66498             var ent = osmEntity.key(entity);
66499
66500             if (!_cache[ent]) {
66501               _cache[ent] = {};
66502             }
66503
66504             if (!_cache[ent].matches) {
66505               var matches = {};
66506               var hasMatch = false;
66507
66508               for (var i = 0; i < _keys.length; i++) {
66509                 if (_keys[i] === 'others') {
66510                   if (hasMatch) continue; // If an entity...
66511                   //   1. is a way that hasn't matched other 'interesting' feature rules,
66512
66513                   if (entity.type === 'way') {
66514                     var parents = features.getParents(entity, resolver, geometry); //   2a. belongs only to a single multipolygon relation
66515
66516                     if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
66517                     parents.length > 0 && parents.every(function (parent) {
66518                       return parent.tags.type === 'boundary';
66519                     })) {
66520                       // ...then match whatever feature rules the parent relation has matched.
66521                       // see #2548, #2887
66522                       //
66523                       // IMPORTANT:
66524                       // For this to work, getMatches must be called on relations before ways.
66525                       //
66526                       var pkey = osmEntity.key(parents[0]);
66527
66528                       if (_cache[pkey] && _cache[pkey].matches) {
66529                         matches = Object.assign({}, _cache[pkey].matches); // shallow copy
66530
66531                         continue;
66532                       }
66533                     }
66534                   }
66535                 }
66536
66537                 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
66538                   matches[_keys[i]] = hasMatch = true;
66539                 }
66540               }
66541
66542               _cache[ent].matches = matches;
66543             }
66544
66545             return _cache[ent].matches;
66546           };
66547
66548           features.getParents = function (entity, resolver, geometry) {
66549             if (geometry === 'point') return [];
66550             var ent = osmEntity.key(entity);
66551
66552             if (!_cache[ent]) {
66553               _cache[ent] = {};
66554             }
66555
66556             if (!_cache[ent].parents) {
66557               var parents = [];
66558
66559               if (geometry === 'vertex') {
66560                 parents = resolver.parentWays(entity);
66561               } else {
66562                 // 'line', 'area', 'relation'
66563                 parents = resolver.parentRelations(entity);
66564               }
66565
66566               _cache[ent].parents = parents;
66567             }
66568
66569             return _cache[ent].parents;
66570           };
66571
66572           features.isHiddenPreset = function (preset, geometry) {
66573             if (!_hidden.length) return false;
66574             if (!preset.tags) return false;
66575             var test = preset.setTags({}, geometry);
66576
66577             for (var key in _rules) {
66578               if (_rules[key].filter(test, geometry)) {
66579                 if (_hidden.indexOf(key) !== -1) {
66580                   return key;
66581                 }
66582
66583                 return false;
66584               }
66585             }
66586
66587             return false;
66588           };
66589
66590           features.isHiddenFeature = function (entity, resolver, geometry) {
66591             if (!_hidden.length) return false;
66592             if (!entity.version) return false;
66593             if (_forceVisible[entity.id]) return false;
66594             var matches = Object.keys(features.getMatches(entity, resolver, geometry));
66595             return matches.length && matches.every(function (k) {
66596               return features.hidden(k);
66597             });
66598           };
66599
66600           features.isHiddenChild = function (entity, resolver, geometry) {
66601             if (!_hidden.length) return false;
66602             if (!entity.version || geometry === 'point') return false;
66603             if (_forceVisible[entity.id]) return false;
66604             var parents = features.getParents(entity, resolver, geometry);
66605             if (!parents.length) return false;
66606
66607             for (var i = 0; i < parents.length; i++) {
66608               if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
66609                 return false;
66610               }
66611             }
66612
66613             return true;
66614           };
66615
66616           features.hasHiddenConnections = function (entity, resolver) {
66617             if (!_hidden.length) return false;
66618             var childNodes, connections;
66619
66620             if (entity.type === 'midpoint') {
66621               childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
66622               connections = [];
66623             } else {
66624               childNodes = entity.nodes ? resolver.childNodes(entity) : [];
66625               connections = features.getParents(entity, resolver, entity.geometry(resolver));
66626             } // gather ways connected to child nodes..
66627
66628
66629             connections = childNodes.reduce(function (result, e) {
66630               return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
66631             }, connections);
66632             return connections.some(function (e) {
66633               return features.isHidden(e, resolver, e.geometry(resolver));
66634             });
66635           };
66636
66637           features.isHidden = function (entity, resolver, geometry) {
66638             if (!_hidden.length) return false;
66639             if (!entity.version) return false;
66640             var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
66641             return fn(entity, resolver, geometry);
66642           };
66643
66644           features.filter = function (d, resolver) {
66645             if (!_hidden.length) return d;
66646             var result = [];
66647
66648             for (var i = 0; i < d.length; i++) {
66649               var entity = d[i];
66650
66651               if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
66652                 result.push(entity);
66653               }
66654             }
66655
66656             return result;
66657           };
66658
66659           features.forceVisible = function (entityIDs) {
66660             if (!arguments.length) return Object.keys(_forceVisible);
66661             _forceVisible = {};
66662
66663             for (var i = 0; i < entityIDs.length; i++) {
66664               _forceVisible[entityIDs[i]] = true;
66665               var entity = context.hasEntity(entityIDs[i]);
66666
66667               if (entity && entity.type === 'relation') {
66668                 // also show relation members (one level deep)
66669                 for (var j in entity.members) {
66670                   _forceVisible[entity.members[j].id] = true;
66671                 }
66672               }
66673             }
66674
66675             return features;
66676           };
66677
66678           features.init = function () {
66679             var storage = corePreferences('disabled-features');
66680
66681             if (storage) {
66682               var storageDisabled = storage.replace(/;/g, ',').split(',');
66683               storageDisabled.forEach(features.disable);
66684             }
66685
66686             var hash = utilStringQs(window.location.hash);
66687
66688             if (hash.disable_features) {
66689               var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
66690               hashDisabled.forEach(features.disable);
66691             }
66692           }; // warm up the feature matching cache upon merging fetched data
66693
66694
66695           context.history().on('merge.features', function (newEntities) {
66696             if (!newEntities) return;
66697             var handle = window.requestIdleCallback(function () {
66698               var graph = context.graph();
66699               var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
66700
66701               var entities = [].concat(types.relation || [], types.way || [], types.node || []);
66702
66703               for (var i = 0; i < entities.length; i++) {
66704                 var geometry = entities[i].geometry(graph);
66705                 features.getMatches(entities[i], graph, geometry);
66706               }
66707             });
66708
66709             _deferred.add(handle);
66710           });
66711           return features;
66712         }
66713
66714         //
66715         // - the activeID - nope
66716         // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
66717         // - 2 away from the activeID - nope (would create a self intersecting segment)
66718         // - all others on a linear way - yes
66719         // - all others on a closed way - nope (would create a self intersecting polygon)
66720         //
66721         // returns
66722         // 0 = active vertex - no touch/connect
66723         // 1 = passive vertex - yes touch/connect
66724         // 2 = adjacent vertex - yes but pay attention segmenting a line here
66725         //
66726
66727         function svgPassiveVertex(node, graph, activeID) {
66728           if (!activeID) return 1;
66729           if (activeID === node.id) return 0;
66730           var parents = graph.parentWays(node);
66731           var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
66732
66733           for (i = 0; i < parents.length; i++) {
66734             nodes = parents[i].nodes;
66735             isClosed = parents[i].isClosed();
66736
66737             for (j = 0; j < nodes.length; j++) {
66738               // find this vertex, look nearby
66739               if (nodes[j] === node.id) {
66740                 ix1 = j - 2;
66741                 ix2 = j - 1;
66742                 ix3 = j + 1;
66743                 ix4 = j + 2;
66744
66745                 if (isClosed) {
66746                   // wraparound if needed
66747                   max = nodes.length - 1;
66748                   if (ix1 < 0) ix1 = max + ix1;
66749                   if (ix2 < 0) ix2 = max + ix2;
66750                   if (ix3 > max) ix3 = ix3 - max;
66751                   if (ix4 > max) ix4 = ix4 - max;
66752                 }
66753
66754                 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
66755                 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
66756                   else if (nodes[ix3] === activeID) return 2; // ok - adjacent
66757                     else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
66758                       else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
66759               }
66760             }
66761           }
66762
66763           return 1; // ok
66764         }
66765         function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
66766           return function (entity) {
66767             var i = 0;
66768             var offset = dt;
66769             var segments = [];
66770             var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
66771             var coordinates = graph.childNodes(entity).map(function (n) {
66772               return n.loc;
66773             });
66774             var a, b;
66775
66776             if (shouldReverse(entity)) {
66777               coordinates.reverse();
66778             }
66779
66780             d3_geoStream({
66781               type: 'LineString',
66782               coordinates: coordinates
66783             }, projection.stream(clip({
66784               lineStart: function lineStart() {},
66785               lineEnd: function lineEnd() {
66786                 a = null;
66787               },
66788               point: function point(x, y) {
66789                 b = [x, y];
66790
66791                 if (a) {
66792                   var span = geoVecLength(a, b) - offset;
66793
66794                   if (span >= 0) {
66795                     var heading = geoVecAngle(a, b);
66796                     var dx = dt * Math.cos(heading);
66797                     var dy = dt * Math.sin(heading);
66798                     var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
66799
66800                     var coord = [a, p];
66801
66802                     for (span -= dt; span >= 0; span -= dt) {
66803                       p = geoVecAdd(p, [dx, dy]);
66804                       coord.push(p);
66805                     }
66806
66807                     coord.push(b); // generate svg paths
66808
66809                     var segment = '';
66810                     var j;
66811
66812                     for (j = 0; j < coord.length; j++) {
66813                       segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
66814                     }
66815
66816                     segments.push({
66817                       id: entity.id,
66818                       index: i++,
66819                       d: segment
66820                     });
66821
66822                     if (bothDirections(entity)) {
66823                       segment = '';
66824
66825                       for (j = coord.length - 1; j >= 0; j--) {
66826                         segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
66827                       }
66828
66829                       segments.push({
66830                         id: entity.id,
66831                         index: i++,
66832                         d: segment
66833                       });
66834                     }
66835                   }
66836
66837                   offset = -span;
66838                 }
66839
66840                 a = b;
66841               }
66842             })));
66843             return segments;
66844           };
66845         }
66846         function svgPath(projection, graph, isArea) {
66847           // Explanation of magic numbers:
66848           // "padding" here allows space for strokes to extend beyond the viewport,
66849           // so that the stroke isn't drawn along the edge of the viewport when
66850           // the shape is clipped.
66851           //
66852           // When drawing lines, pad viewport by 5px.
66853           // When drawing areas, pad viewport by 65px in each direction to allow
66854           // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
66855           var cache = {};
66856           var padding = isArea ? 65 : 5;
66857           var viewport = projection.clipExtent();
66858           var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
66859           var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
66860           var project = projection.stream;
66861           var path = d3_geoPath().projection({
66862             stream: function stream(output) {
66863               return project(clip(output));
66864             }
66865           });
66866
66867           var svgpath = function svgpath(entity) {
66868             if (entity.id in cache) {
66869               return cache[entity.id];
66870             } else {
66871               return cache[entity.id] = path(entity.asGeoJSON(graph));
66872             }
66873           };
66874
66875           svgpath.geojson = function (d) {
66876             if (d.__featurehash__ !== undefined) {
66877               if (d.__featurehash__ in cache) {
66878                 return cache[d.__featurehash__];
66879               } else {
66880                 return cache[d.__featurehash__] = path(d);
66881               }
66882             } else {
66883               return path(d);
66884             }
66885           };
66886
66887           return svgpath;
66888         }
66889         function svgPointTransform(projection) {
66890           var svgpoint = function svgpoint(entity) {
66891             // http://jsperf.com/short-array-join
66892             var pt = projection(entity.loc);
66893             return 'translate(' + pt[0] + ',' + pt[1] + ')';
66894           };
66895
66896           svgpoint.geojson = function (d) {
66897             return svgpoint(d.properties.entity);
66898           };
66899
66900           return svgpoint;
66901         }
66902         function svgRelationMemberTags(graph) {
66903           return function (entity) {
66904             var tags = entity.tags;
66905             var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
66906             graph.parentRelations(entity).forEach(function (relation) {
66907               var type = relation.tags.type;
66908
66909               if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
66910                 tags = Object.assign({}, relation.tags, tags);
66911               }
66912             });
66913             return tags;
66914           };
66915         }
66916         function svgSegmentWay(way, graph, activeID) {
66917           // When there is no activeID, we can memoize this expensive computation
66918           if (activeID === undefined) {
66919             return graph["transient"](way, 'waySegments', getWaySegments);
66920           } else {
66921             return getWaySegments();
66922           }
66923
66924           function getWaySegments() {
66925             var isActiveWay = way.nodes.indexOf(activeID) !== -1;
66926             var features = {
66927               passive: [],
66928               active: []
66929             };
66930             var start = {};
66931             var end = {};
66932             var node, type;
66933
66934             for (var i = 0; i < way.nodes.length; i++) {
66935               node = graph.entity(way.nodes[i]);
66936               type = svgPassiveVertex(node, graph, activeID);
66937               end = {
66938                 node: node,
66939                 type: type
66940               };
66941
66942               if (start.type !== undefined) {
66943                 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
66944                   // one adjacent vertex
66945                   pushActive(start, end, i);
66946                 } else if (start.type === 0 && end.type === 0) {
66947                   // both active vertices
66948                   pushActive(start, end, i);
66949                 } else {
66950                   pushPassive(start, end, i);
66951                 }
66952               }
66953
66954               start = end;
66955             }
66956
66957             return features;
66958
66959             function pushActive(start, end, index) {
66960               features.active.push({
66961                 type: 'Feature',
66962                 id: way.id + '-' + index + '-nope',
66963                 properties: {
66964                   nope: true,
66965                   target: true,
66966                   entity: way,
66967                   nodes: [start.node, end.node],
66968                   index: index
66969                 },
66970                 geometry: {
66971                   type: 'LineString',
66972                   coordinates: [start.node.loc, end.node.loc]
66973                 }
66974               });
66975             }
66976
66977             function pushPassive(start, end, index) {
66978               features.passive.push({
66979                 type: 'Feature',
66980                 id: way.id + '-' + index,
66981                 properties: {
66982                   target: true,
66983                   entity: way,
66984                   nodes: [start.node, end.node],
66985                   index: index
66986                 },
66987                 geometry: {
66988                   type: 'LineString',
66989                   coordinates: [start.node.loc, end.node.loc]
66990                 }
66991               });
66992             }
66993           }
66994         }
66995
66996         function svgTagClasses() {
66997           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'];
66998           var statuses = [// nonexistent, might be built
66999           'proposed', 'planned', // under maintentance or between groundbreaking and opening
67000           'construction', // existent but not functional
67001           'disused', // dilapidated to nonexistent
67002           'abandoned', // nonexistent, still may appear in imagery
67003           'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
67004           'intermittent'];
67005           var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
67006
67007           var _tags = function _tags(entity) {
67008             return entity.tags;
67009           };
67010
67011           var tagClasses = function tagClasses(selection) {
67012             selection.each(function tagClassesEach(entity) {
67013               var value = this.className;
67014
67015               if (value.baseVal !== undefined) {
67016                 value = value.baseVal;
67017               }
67018
67019               var t = _tags(entity);
67020
67021               var computed = tagClasses.getClassesString(t, value);
67022
67023               if (computed !== value) {
67024                 select(this).attr('class', computed);
67025               }
67026             });
67027           };
67028
67029           tagClasses.getClassesString = function (t, value) {
67030             var primary, status;
67031             var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
67032
67033             var overrideGeometry;
67034
67035             if (/\bstroke\b/.test(value)) {
67036               if (!!t.barrier && t.barrier !== 'no') {
67037                 overrideGeometry = 'line';
67038               }
67039             } // preserve base classes (nothing with `tag-`)
67040
67041
67042             var classes = value.trim().split(/\s+/).filter(function (klass) {
67043               return klass.length && !/^tag-/.test(klass);
67044             }).map(function (klass) {
67045               // special overrides for some perimeter strokes
67046               return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
67047             }); // pick at most one primary classification tag..
67048
67049             for (i = 0; i < primaries.length; i++) {
67050               k = primaries[i];
67051               v = t[k];
67052               if (!v || v === 'no') continue;
67053
67054               if (k === 'piste:type') {
67055                 // avoid a ':' in the class name
67056                 k = 'piste';
67057               } else if (k === 'building:part') {
67058                 // avoid a ':' in the class name
67059                 k = 'building_part';
67060               }
67061
67062               primary = k;
67063
67064               if (statuses.indexOf(v) !== -1) {
67065                 // e.g. `railway=abandoned`
67066                 status = v;
67067                 classes.push('tag-' + k);
67068               } else {
67069                 classes.push('tag-' + k);
67070                 classes.push('tag-' + k + '-' + v);
67071               }
67072
67073               break;
67074             }
67075
67076             if (!primary) {
67077               for (i = 0; i < statuses.length; i++) {
67078                 for (j = 0; j < primaries.length; j++) {
67079                   k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
67080
67081                   v = t[k];
67082                   if (!v || v === 'no') continue;
67083                   status = statuses[i];
67084                   break;
67085                 }
67086               }
67087             } // add at most one status tag, only if relates to primary tag..
67088
67089
67090             if (!status) {
67091               for (i = 0; i < statuses.length; i++) {
67092                 k = statuses[i];
67093                 v = t[k];
67094                 if (!v || v === 'no') continue;
67095
67096                 if (v === 'yes') {
67097                   // e.g. `railway=rail + abandoned=yes`
67098                   status = k;
67099                 } else if (primary && primary === v) {
67100                   // e.g. `railway=rail + abandoned=railway`
67101                   status = k;
67102                 } else if (!primary && primaries.indexOf(v) !== -1) {
67103                   // e.g. `abandoned=railway`
67104                   status = k;
67105                   primary = v;
67106                   classes.push('tag-' + v);
67107                 } // else ignore e.g.  `highway=path + abandoned=railway`
67108
67109
67110                 if (status) break;
67111               }
67112             }
67113
67114             if (status) {
67115               classes.push('tag-status');
67116               classes.push('tag-status-' + status);
67117             } // add any secondary tags
67118
67119
67120             for (i = 0; i < secondaries.length; i++) {
67121               k = secondaries[i];
67122               v = t[k];
67123               if (!v || v === 'no' || k === primary) continue;
67124               classes.push('tag-' + k);
67125               classes.push('tag-' + k + '-' + v);
67126             } // For highways, look for surface tagging..
67127
67128
67129             if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
67130               var surface = t.highway === 'track' ? 'unpaved' : 'paved';
67131
67132               for (k in t) {
67133                 v = t[k];
67134
67135                 if (k in osmPavedTags) {
67136                   surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
67137                 }
67138
67139                 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
67140                   surface = 'semipaved';
67141                 }
67142               }
67143
67144               classes.push('tag-' + surface);
67145             } // If this is a wikidata-tagged item, add a class for that..
67146
67147
67148             if (t.wikidata || t['brand:wikidata']) {
67149               classes.push('tag-wikidata');
67150             }
67151
67152             return classes.join(' ').trim();
67153           };
67154
67155           tagClasses.tags = function (val) {
67156             if (!arguments.length) return _tags;
67157             _tags = val;
67158             return tagClasses;
67159           };
67160
67161           return tagClasses;
67162         }
67163
67164         // Patterns only work in Firefox when set directly on element.
67165         // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
67166         var patterns = {
67167           // tag - pattern name
67168           // -or-
67169           // tag - value - pattern name
67170           // -or-
67171           // tag - value - rules (optional tag-values, pattern name)
67172           // (matches earlier rules first, so fallback should be last entry)
67173           amenity: {
67174             grave_yard: 'cemetery',
67175             fountain: 'water_standing'
67176           },
67177           landuse: {
67178             cemetery: [{
67179               religion: 'christian',
67180               pattern: 'cemetery_christian'
67181             }, {
67182               religion: 'buddhist',
67183               pattern: 'cemetery_buddhist'
67184             }, {
67185               religion: 'muslim',
67186               pattern: 'cemetery_muslim'
67187             }, {
67188               religion: 'jewish',
67189               pattern: 'cemetery_jewish'
67190             }, {
67191               pattern: 'cemetery'
67192             }],
67193             construction: 'construction',
67194             farmland: 'farmland',
67195             farmyard: 'farmyard',
67196             forest: [{
67197               leaf_type: 'broadleaved',
67198               pattern: 'forest_broadleaved'
67199             }, {
67200               leaf_type: 'needleleaved',
67201               pattern: 'forest_needleleaved'
67202             }, {
67203               leaf_type: 'leafless',
67204               pattern: 'forest_leafless'
67205             }, {
67206               pattern: 'forest'
67207             } // same as 'leaf_type:mixed'
67208             ],
67209             grave_yard: 'cemetery',
67210             grass: [{
67211               golf: 'green',
67212               pattern: 'golf_green'
67213             }, {
67214               pattern: 'grass'
67215             }],
67216             landfill: 'landfill',
67217             meadow: 'meadow',
67218             military: 'construction',
67219             orchard: 'orchard',
67220             quarry: 'quarry',
67221             vineyard: 'vineyard'
67222           },
67223           natural: {
67224             beach: 'beach',
67225             grassland: 'grass',
67226             sand: 'beach',
67227             scrub: 'scrub',
67228             water: [{
67229               water: 'pond',
67230               pattern: 'pond'
67231             }, {
67232               water: 'reservoir',
67233               pattern: 'water_standing'
67234             }, {
67235               pattern: 'waves'
67236             }],
67237             wetland: [{
67238               wetland: 'marsh',
67239               pattern: 'wetland_marsh'
67240             }, {
67241               wetland: 'swamp',
67242               pattern: 'wetland_swamp'
67243             }, {
67244               wetland: 'bog',
67245               pattern: 'wetland_bog'
67246             }, {
67247               wetland: 'reedbed',
67248               pattern: 'wetland_reedbed'
67249             }, {
67250               pattern: 'wetland'
67251             }],
67252             wood: [{
67253               leaf_type: 'broadleaved',
67254               pattern: 'forest_broadleaved'
67255             }, {
67256               leaf_type: 'needleleaved',
67257               pattern: 'forest_needleleaved'
67258             }, {
67259               leaf_type: 'leafless',
67260               pattern: 'forest_leafless'
67261             }, {
67262               pattern: 'forest'
67263             } // same as 'leaf_type:mixed'
67264             ]
67265           },
67266           traffic_calming: {
67267             island: [{
67268               surface: 'grass',
67269               pattern: 'grass'
67270             }],
67271             chicane: [{
67272               surface: 'grass',
67273               pattern: 'grass'
67274             }],
67275             choker: [{
67276               surface: 'grass',
67277               pattern: 'grass'
67278             }]
67279           }
67280         };
67281         function svgTagPattern(tags) {
67282           // Skip pattern filling if this is a building (buildings don't get patterns applied)
67283           if (tags.building && tags.building !== 'no') {
67284             return null;
67285           }
67286
67287           for (var tag in patterns) {
67288             var entityValue = tags[tag];
67289             if (!entityValue) continue;
67290
67291             if (typeof patterns[tag] === 'string') {
67292               // extra short syntax (just tag) - pattern name
67293               return 'pattern-' + patterns[tag];
67294             } else {
67295               var values = patterns[tag];
67296
67297               for (var value in values) {
67298                 if (entityValue !== value) continue;
67299                 var rules = values[value];
67300
67301                 if (typeof rules === 'string') {
67302                   // short syntax - pattern name
67303                   return 'pattern-' + rules;
67304                 } // long syntax - rule array
67305
67306
67307                 for (var ruleKey in rules) {
67308                   var rule = rules[ruleKey];
67309                   var pass = true;
67310
67311                   for (var criterion in rule) {
67312                     if (criterion !== 'pattern') {
67313                       // reserved for pattern name
67314                       // The only rule is a required tag-value pair
67315                       var v = tags[criterion];
67316
67317                       if (!v || v !== rule[criterion]) {
67318                         pass = false;
67319                         break;
67320                       }
67321                     }
67322                   }
67323
67324                   if (pass) {
67325                     return 'pattern-' + rule.pattern;
67326                   }
67327                 }
67328               }
67329             }
67330           }
67331
67332           return null;
67333         }
67334
67335         function svgAreas(projection, context) {
67336           function getPatternStyle(tags) {
67337             var imageID = svgTagPattern(tags);
67338
67339             if (imageID) {
67340               return 'url("#ideditor-' + imageID + '")';
67341             }
67342
67343             return '';
67344           }
67345
67346           function drawTargets(selection, graph, entities, filter) {
67347             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67348             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
67349             var getPath = svgPath(projection).geojson;
67350             var activeID = context.activeID();
67351             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
67352
67353             var data = {
67354               targets: [],
67355               nopes: []
67356             };
67357             entities.forEach(function (way) {
67358               var features = svgSegmentWay(way, graph, activeID);
67359               data.targets.push.apply(data.targets, features.passive);
67360               data.nopes.push.apply(data.nopes, features.active);
67361             }); // Targets allow hover and vertex snapping
67362
67363             var targetData = data.targets.filter(getPath);
67364             var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
67365               return filter(d.properties.entity);
67366             }).data(targetData, function key(d) {
67367               return d.id;
67368             }); // exit
67369
67370             targets.exit().remove();
67371
67372             var segmentWasEdited = function segmentWasEdited(d) {
67373               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
67374
67375               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
67376                 return false;
67377               }
67378
67379               return d.properties.nodes.some(function (n) {
67380                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
67381               });
67382             }; // enter/update
67383
67384
67385             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
67386               return 'way area target target-allowed ' + targetClass + d.id;
67387             }).classed('segment-edited', segmentWasEdited); // NOPE
67388
67389             var nopeData = data.nopes.filter(getPath);
67390             var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
67391               return filter(d.properties.entity);
67392             }).data(nopeData, function key(d) {
67393               return d.id;
67394             }); // exit
67395
67396             nopes.exit().remove(); // enter/update
67397
67398             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
67399               return 'way area target target-nope ' + nopeClass + d.id;
67400             }).classed('segment-edited', segmentWasEdited);
67401           }
67402
67403           function drawAreas(selection, graph, entities, filter) {
67404             var path = svgPath(projection, graph, true);
67405             var areas = {};
67406             var multipolygon;
67407             var base = context.history().base();
67408
67409             for (var i = 0; i < entities.length; i++) {
67410               var entity = entities[i];
67411               if (entity.geometry(graph) !== 'area') continue;
67412               multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
67413
67414               if (multipolygon) {
67415                 areas[multipolygon.id] = {
67416                   entity: multipolygon.mergeTags(entity.tags),
67417                   area: Math.abs(entity.area(graph))
67418                 };
67419               } else if (!areas[entity.id]) {
67420                 areas[entity.id] = {
67421                   entity: entity,
67422                   area: Math.abs(entity.area(graph))
67423                 };
67424               }
67425             }
67426
67427             var fills = Object.values(areas).filter(function hasPath(a) {
67428               return path(a.entity);
67429             });
67430             fills.sort(function areaSort(a, b) {
67431               return b.area - a.area;
67432             });
67433             fills = fills.map(function (a) {
67434               return a.entity;
67435             });
67436             var strokes = fills.filter(function (area) {
67437               return area.type === 'way';
67438             });
67439             var data = {
67440               clip: fills,
67441               shadow: strokes,
67442               stroke: strokes,
67443               fill: fills
67444             };
67445             var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
67446             clipPaths.exit().remove();
67447             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
67448               return 'ideditor-' + entity.id + '-clippath';
67449             });
67450             clipPathsEnter.append('path');
67451             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
67452             var drawLayer = selection.selectAll('.layer-osm.areas');
67453             var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
67454
67455             var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
67456             areagroup = areagroup.enter().append('g').attr('class', function (d) {
67457               return 'areagroup area-' + d;
67458             }).merge(areagroup);
67459             var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
67460               return data[layer];
67461             }, osmEntity.key);
67462             paths.exit().remove();
67463             var fillpaths = selection.selectAll('.area-fill path.area').nodes();
67464             var bisect = d3_bisector(function (node) {
67465               return -node.__data__.area(graph);
67466             }).left;
67467
67468             function sortedByArea(entity) {
67469               if (this._parent.__data__ === 'fill') {
67470                 return fillpaths[bisect(fillpaths, -entity.area(graph))];
67471               }
67472             }
67473
67474             paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
67475               var layer = this.parentNode.__data__;
67476               this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
67477
67478               if (layer === 'fill') {
67479                 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
67480                 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
67481               }
67482             }).classed('added', function (d) {
67483               return !base.entities[d.id];
67484             }).classed('geometry-edited', function (d) {
67485               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
67486             }).classed('retagged', function (d) {
67487               return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67488             }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
67489
67490             touchLayer.call(drawTargets, graph, data.stroke, filter);
67491           }
67492
67493           return drawAreas;
67494         }
67495
67496         //[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]
67497         //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
67498         //[5]           Name       ::=          NameStartChar (NameChar)*
67499         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
67500
67501         var nameChar = new RegExp("[\\-\\.0-9" + nameStartChar.source.slice(1, -1) + "\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
67502         var tagNamePattern = new RegExp('^' + nameStartChar.source + nameChar.source + '*(?:\:' + nameStartChar.source + nameChar.source + '*)?$'); //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
67503         //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(',')
67504         //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
67505         //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
67506
67507         var S_TAG = 0; //tag name offerring
67508
67509         var S_ATTR = 1; //attr name offerring 
67510
67511         var S_ATTR_SPACE = 2; //attr name end and space offer
67512
67513         var S_EQ = 3; //=space?
67514
67515         var S_ATTR_NOQUOT_VALUE = 4; //attr value(no quot value only)
67516
67517         var S_ATTR_END = 5; //attr value end and no space(quot end)
67518
67519         var S_TAG_SPACE = 6; //(attr value end || tag end ) && (space offer)
67520
67521         var S_TAG_CLOSE = 7; //closed el<el />
67522
67523         function XMLReader() {}
67524
67525         XMLReader.prototype = {
67526           parse: function parse(source, defaultNSMap, entityMap) {
67527             var domBuilder = this.domBuilder;
67528             domBuilder.startDocument();
67529
67530             _copy(defaultNSMap, defaultNSMap = {});
67531
67532             _parse(source, defaultNSMap, entityMap, domBuilder, this.errorHandler);
67533
67534             domBuilder.endDocument();
67535           }
67536         };
67537
67538         function _parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
67539           function fixedFromCharCode(code) {
67540             // String.prototype.fromCharCode does not supports
67541             // > 2 bytes unicode chars directly
67542             if (code > 0xffff) {
67543               code -= 0x10000;
67544               var surrogate1 = 0xd800 + (code >> 10),
67545                   surrogate2 = 0xdc00 + (code & 0x3ff);
67546               return String.fromCharCode(surrogate1, surrogate2);
67547             } else {
67548               return String.fromCharCode(code);
67549             }
67550           }
67551
67552           function entityReplacer(a) {
67553             var k = a.slice(1, -1);
67554
67555             if (k in entityMap) {
67556               return entityMap[k];
67557             } else if (k.charAt(0) === '#') {
67558               return fixedFromCharCode(parseInt(k.substr(1).replace('x', '0x')));
67559             } else {
67560               errorHandler.error('entity not found:' + a);
67561               return a;
67562             }
67563           }
67564
67565           function appendText(end) {
67566             //has some bugs
67567             if (end > start) {
67568               var xt = source.substring(start, end).replace(/&#?\w+;/g, entityReplacer);
67569               locator && position(start);
67570               domBuilder.characters(xt, 0, end - start);
67571               start = end;
67572             }
67573           }
67574
67575           function position(p, m) {
67576             while (p >= lineEnd && (m = linePattern.exec(source))) {
67577               lineStart = m.index;
67578               lineEnd = lineStart + m[0].length;
67579               locator.lineNumber++; //console.log('line++:',locator,startPos,endPos)
67580             }
67581
67582             locator.columnNumber = p - lineStart + 1;
67583           }
67584
67585           var lineStart = 0;
67586           var lineEnd = 0;
67587           var linePattern = /.*(?:\r\n?|\n)|.*$/g;
67588           var locator = domBuilder.locator;
67589           var parseStack = [{
67590             currentNSMap: defaultNSMapCopy
67591           }];
67592           var closeMap = {};
67593           var start = 0;
67594
67595           while (true) {
67596             try {
67597               var tagStart = source.indexOf('<', start);
67598
67599               if (tagStart < 0) {
67600                 if (!source.substr(start).match(/^\s*$/)) {
67601                   var doc = domBuilder.doc;
67602                   var text = doc.createTextNode(source.substr(start));
67603                   doc.appendChild(text);
67604                   domBuilder.currentElement = text;
67605                 }
67606
67607                 return;
67608               }
67609
67610               if (tagStart > start) {
67611                 appendText(tagStart);
67612               }
67613
67614               switch (source.charAt(tagStart + 1)) {
67615                 case '/':
67616                   var end = source.indexOf('>', tagStart + 3);
67617                   var tagName = source.substring(tagStart + 2, end);
67618                   var config = parseStack.pop();
67619
67620                   if (end < 0) {
67621                     tagName = source.substring(tagStart + 2).replace(/[\s<].*/, ''); //console.error('#@@@@@@'+tagName)
67622
67623                     errorHandler.error("end tag name: " + tagName + ' is not complete:' + config.tagName);
67624                     end = tagStart + 1 + tagName.length;
67625                   } else if (tagName.match(/\s</)) {
67626                     tagName = tagName.replace(/[\s<].*/, '');
67627                     errorHandler.error("end tag name: " + tagName + ' maybe not complete');
67628                     end = tagStart + 1 + tagName.length;
67629                   } //console.error(parseStack.length,parseStack)
67630                   //console.error(config);
67631
67632
67633                   var localNSMap = config.localNSMap;
67634                   var endMatch = config.tagName == tagName;
67635                   var endIgnoreCaseMach = endMatch || config.tagName && config.tagName.toLowerCase() == tagName.toLowerCase();
67636
67637                   if (endIgnoreCaseMach) {
67638                     domBuilder.endElement(config.uri, config.localName, tagName);
67639
67640                     if (localNSMap) {
67641                       for (var prefix in localNSMap) {
67642                         domBuilder.endPrefixMapping(prefix);
67643                       }
67644                     }
67645
67646                     if (!endMatch) {
67647                       errorHandler.fatalError("end tag name: " + tagName + ' is not match the current start tagName:' + config.tagName);
67648                     }
67649                   } else {
67650                     parseStack.push(config);
67651                   }
67652
67653                   end++;
67654                   break;
67655                 // end elment
67656
67657                 case '?':
67658                   // <?...?>
67659                   locator && position(tagStart);
67660                   end = parseInstruction(source, tagStart, domBuilder);
67661                   break;
67662
67663                 case '!':
67664                   // <!doctype,<![CDATA,<!--
67665                   locator && position(tagStart);
67666                   end = parseDCC(source, tagStart, domBuilder, errorHandler);
67667                   break;
67668
67669                 default:
67670                   locator && position(tagStart);
67671                   var el = new ElementAttributes();
67672                   var currentNSMap = parseStack[parseStack.length - 1].currentNSMap; //elStartEnd
67673
67674                   var end = parseElementStartPart(source, tagStart, el, currentNSMap, entityReplacer, errorHandler);
67675                   var len = el.length;
67676
67677                   if (!el.closed && fixSelfClosed(source, end, el.tagName, closeMap)) {
67678                     el.closed = true;
67679
67680                     if (!entityMap.nbsp) {
67681                       errorHandler.warning('unclosed xml attribute');
67682                     }
67683                   }
67684
67685                   if (locator && len) {
67686                     var locator2 = copyLocator(locator, {}); //try{//attribute position fixed
67687
67688                     for (var i = 0; i < len; i++) {
67689                       var a = el[i];
67690                       position(a.offset);
67691                       a.locator = copyLocator(locator, {});
67692                     } //}catch(e){console.error('@@@@@'+e)}
67693
67694
67695                     domBuilder.locator = locator2;
67696
67697                     if (appendElement(el, domBuilder, currentNSMap)) {
67698                       parseStack.push(el);
67699                     }
67700
67701                     domBuilder.locator = locator;
67702                   } else {
67703                     if (appendElement(el, domBuilder, currentNSMap)) {
67704                       parseStack.push(el);
67705                     }
67706                   }
67707
67708                   if (el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed) {
67709                     end = parseHtmlSpecialContent(source, end, el.tagName, entityReplacer, domBuilder);
67710                   } else {
67711                     end++;
67712                   }
67713
67714               }
67715             } catch (e) {
67716               errorHandler.error('element parse error: ' + e); //errorHandler.error('element parse error: '+e);
67717
67718               end = -1; //throw e;
67719             }
67720
67721             if (end > start) {
67722               start = end;
67723             } else {
67724               //TODO: 这里有可能sax回退,有位置错误风险
67725               appendText(Math.max(tagStart, start) + 1);
67726             }
67727           }
67728         }
67729
67730         function copyLocator(f, t) {
67731           t.lineNumber = f.lineNumber;
67732           t.columnNumber = f.columnNumber;
67733           return t;
67734         }
67735         /**
67736          * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
67737          * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
67738          */
67739
67740
67741         function parseElementStartPart(source, start, el, currentNSMap, entityReplacer, errorHandler) {
67742           var attrName;
67743           var value;
67744           var p = ++start;
67745           var s = S_TAG; //status
67746
67747           while (true) {
67748             var c = source.charAt(p);
67749
67750             switch (c) {
67751               case '=':
67752                 if (s === S_ATTR) {
67753                   //attrName
67754                   attrName = source.slice(start, p);
67755                   s = S_EQ;
67756                 } else if (s === S_ATTR_SPACE) {
67757                   s = S_EQ;
67758                 } else {
67759                   //fatalError: equal must after attrName or space after attrName
67760                   throw new Error('attribute equal must after attrName');
67761                 }
67762
67763                 break;
67764
67765               case '\'':
67766               case '"':
67767                 if (s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
67768                 ) {
67769                     //equal
67770                     if (s === S_ATTR) {
67771                       errorHandler.warning('attribute value must after "="');
67772                       attrName = source.slice(start, p);
67773                     }
67774
67775                     start = p + 1;
67776                     p = source.indexOf(c, start);
67777
67778                     if (p > 0) {
67779                       value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
67780                       el.add(attrName, value, start - 1);
67781                       s = S_ATTR_END;
67782                     } else {
67783                       //fatalError: no end quot match
67784                       throw new Error('attribute value no end \'' + c + '\' match');
67785                     }
67786                   } else if (s == S_ATTR_NOQUOT_VALUE) {
67787                   value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer); //console.log(attrName,value,start,p)
67788
67789                   el.add(attrName, value, start); //console.dir(el)
67790
67791                   errorHandler.warning('attribute "' + attrName + '" missed start quot(' + c + ')!!');
67792                   start = p + 1;
67793                   s = S_ATTR_END;
67794                 } else {
67795                   //fatalError: no equal before
67796                   throw new Error('attribute value must after "="');
67797                 }
67798
67799                 break;
67800
67801               case '/':
67802                 switch (s) {
67803                   case S_TAG:
67804                     el.setTagName(source.slice(start, p));
67805
67806                   case S_ATTR_END:
67807                   case S_TAG_SPACE:
67808                   case S_TAG_CLOSE:
67809                     s = S_TAG_CLOSE;
67810                     el.closed = true;
67811
67812                   case S_ATTR_NOQUOT_VALUE:
67813                   case S_ATTR:
67814                   case S_ATTR_SPACE:
67815                     break;
67816                   //case S_EQ:
67817
67818                   default:
67819                     throw new Error("attribute invalid close char('/')");
67820                 }
67821
67822                 break;
67823
67824               case '':
67825                 //end document
67826                 //throw new Error('unexpected end of input')
67827                 errorHandler.error('unexpected end of input');
67828
67829                 if (s == S_TAG) {
67830                   el.setTagName(source.slice(start, p));
67831                 }
67832
67833                 return p;
67834
67835               case '>':
67836                 switch (s) {
67837                   case S_TAG:
67838                     el.setTagName(source.slice(start, p));
67839
67840                   case S_ATTR_END:
67841                   case S_TAG_SPACE:
67842                   case S_TAG_CLOSE:
67843                     break;
67844                   //normal
67845
67846                   case S_ATTR_NOQUOT_VALUE: //Compatible state
67847
67848                   case S_ATTR:
67849                     value = source.slice(start, p);
67850
67851                     if (value.slice(-1) === '/') {
67852                       el.closed = true;
67853                       value = value.slice(0, -1);
67854                     }
67855
67856                   case S_ATTR_SPACE:
67857                     if (s === S_ATTR_SPACE) {
67858                       value = attrName;
67859                     }
67860
67861                     if (s == S_ATTR_NOQUOT_VALUE) {
67862                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
67863                       el.add(attrName, value.replace(/&#?\w+;/g, entityReplacer), start);
67864                     } else {
67865                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)) {
67866                         errorHandler.warning('attribute "' + value + '" missed value!! "' + value + '" instead!!');
67867                       }
67868
67869                       el.add(value, value, start);
67870                     }
67871
67872                     break;
67873
67874                   case S_EQ:
67875                     throw new Error('attribute value missed!!');
67876                 } //                    console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
67877
67878
67879                 return p;
67880
67881               /*xml space '\x20' | #x9 | #xD | #xA; */
67882
67883               case "\x80":
67884                 c = ' ';
67885
67886               default:
67887                 if (c <= ' ') {
67888                   //space
67889                   switch (s) {
67890                     case S_TAG:
67891                       el.setTagName(source.slice(start, p)); //tagName
67892
67893                       s = S_TAG_SPACE;
67894                       break;
67895
67896                     case S_ATTR:
67897                       attrName = source.slice(start, p);
67898                       s = S_ATTR_SPACE;
67899                       break;
67900
67901                     case S_ATTR_NOQUOT_VALUE:
67902                       var value = source.slice(start, p).replace(/&#?\w+;/g, entityReplacer);
67903                       errorHandler.warning('attribute "' + value + '" missed quot(")!!');
67904                       el.add(attrName, value, start);
67905
67906                     case S_ATTR_END:
67907                       s = S_TAG_SPACE;
67908                       break;
67909                     //case S_TAG_SPACE:
67910                     //case S_EQ:
67911                     //case S_ATTR_SPACE:
67912                     //  void();break;
67913                     //case S_TAG_CLOSE:
67914                     //ignore warning
67915                   }
67916                 } else {
67917                   //not space
67918                   //S_TAG,      S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
67919                   //S_ATTR_SPACE,       S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
67920                   switch (s) {
67921                     //case S_TAG:void();break;
67922                     //case S_ATTR:void();break;
67923                     //case S_ATTR_NOQUOT_VALUE:void();break;
67924                     case S_ATTR_SPACE:
67925                       var tagName = el.tagName;
67926
67927                       if (currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
67928                         errorHandler.warning('attribute "' + attrName + '" missed value!! "' + attrName + '" instead2!!');
67929                       }
67930
67931                       el.add(attrName, attrName, start);
67932                       start = p;
67933                       s = S_ATTR;
67934                       break;
67935
67936                     case S_ATTR_END:
67937                       errorHandler.warning('attribute space is required"' + attrName + '"!!');
67938
67939                     case S_TAG_SPACE:
67940                       s = S_ATTR;
67941                       start = p;
67942                       break;
67943
67944                     case S_EQ:
67945                       s = S_ATTR_NOQUOT_VALUE;
67946                       start = p;
67947                       break;
67948
67949                     case S_TAG_CLOSE:
67950                       throw new Error("elements closed character '/' and '>' must be connected to");
67951                   }
67952                 }
67953
67954             } //end outer switch
67955             //console.log('p++',p)
67956
67957
67958             p++;
67959           }
67960         }
67961         /**
67962          * @return true if has new namespace define
67963          */
67964
67965
67966         function appendElement(el, domBuilder, currentNSMap) {
67967           var tagName = el.tagName;
67968           var localNSMap = null; //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
67969
67970           var i = el.length;
67971
67972           while (i--) {
67973             var a = el[i];
67974             var qName = a.qName;
67975             var value = a.value;
67976             var nsp = qName.indexOf(':');
67977
67978             if (nsp > 0) {
67979               var prefix = a.prefix = qName.slice(0, nsp);
67980               var localName = qName.slice(nsp + 1);
67981               var nsPrefix = prefix === 'xmlns' && localName;
67982             } else {
67983               localName = qName;
67984               prefix = null;
67985               nsPrefix = qName === 'xmlns' && '';
67986             } //can not set prefix,because prefix !== ''
67987
67988
67989             a.localName = localName; //prefix == null for no ns prefix attribute 
67990
67991             if (nsPrefix !== false) {
67992               //hack!!
67993               if (localNSMap == null) {
67994                 localNSMap = {}; //console.log(currentNSMap,0)
67995
67996                 _copy(currentNSMap, currentNSMap = {}); //console.log(currentNSMap,1)
67997
67998               }
67999
68000               currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
68001               a.uri = 'http://www.w3.org/2000/xmlns/';
68002               domBuilder.startPrefixMapping(nsPrefix, value);
68003             }
68004           }
68005
68006           var i = el.length;
68007
68008           while (i--) {
68009             a = el[i];
68010             var prefix = a.prefix;
68011
68012             if (prefix) {
68013               //no prefix attribute has no namespace
68014               if (prefix === 'xml') {
68015                 a.uri = 'http://www.w3.org/XML/1998/namespace';
68016               }
68017
68018               if (prefix !== 'xmlns') {
68019                 a.uri = currentNSMap[prefix || '']; //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
68020               }
68021             }
68022           }
68023
68024           var nsp = tagName.indexOf(':');
68025
68026           if (nsp > 0) {
68027             prefix = el.prefix = tagName.slice(0, nsp);
68028             localName = el.localName = tagName.slice(nsp + 1);
68029           } else {
68030             prefix = null; //important!!
68031
68032             localName = el.localName = tagName;
68033           } //no prefix element has default namespace
68034
68035
68036           var ns = el.uri = currentNSMap[prefix || ''];
68037           domBuilder.startElement(ns, localName, tagName, el); //endPrefixMapping and startPrefixMapping have not any help for dom builder
68038           //localNSMap = null
68039
68040           if (el.closed) {
68041             domBuilder.endElement(ns, localName, tagName);
68042
68043             if (localNSMap) {
68044               for (prefix in localNSMap) {
68045                 domBuilder.endPrefixMapping(prefix);
68046               }
68047             }
68048           } else {
68049             el.currentNSMap = currentNSMap;
68050             el.localNSMap = localNSMap; //parseStack.push(el);
68051
68052             return true;
68053           }
68054         }
68055
68056         function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
68057           if (/^(?:script|textarea)$/i.test(tagName)) {
68058             var elEndStart = source.indexOf('</' + tagName + '>', elStartEnd);
68059             var text = source.substring(elStartEnd + 1, elEndStart);
68060
68061             if (/[&<]/.test(text)) {
68062               if (/^script$/i.test(tagName)) {
68063                 //if(!/\]\]>/.test(text)){
68064                 //lexHandler.startCDATA();
68065                 domBuilder.characters(text, 0, text.length); //lexHandler.endCDATA();
68066
68067                 return elEndStart; //}
68068               } //}else{//text area
68069
68070
68071               text = text.replace(/&#?\w+;/g, entityReplacer);
68072               domBuilder.characters(text, 0, text.length);
68073               return elEndStart; //}
68074             }
68075           }
68076
68077           return elStartEnd + 1;
68078         }
68079
68080         function fixSelfClosed(source, elStartEnd, tagName, closeMap) {
68081           //if(tagName in closeMap){
68082           var pos = closeMap[tagName];
68083
68084           if (pos == null) {
68085             //console.log(tagName)
68086             pos = source.lastIndexOf('</' + tagName + '>');
68087
68088             if (pos < elStartEnd) {
68089               //忘记闭合
68090               pos = source.lastIndexOf('</' + tagName);
68091             }
68092
68093             closeMap[tagName] = pos;
68094           }
68095
68096           return pos < elStartEnd; //} 
68097         }
68098
68099         function _copy(source, target) {
68100           for (var n in source) {
68101             target[n] = source[n];
68102           }
68103         }
68104
68105         function parseDCC(source, start, domBuilder, errorHandler) {
68106           //sure start with '<!'
68107           var next = source.charAt(start + 2);
68108
68109           switch (next) {
68110             case '-':
68111               if (source.charAt(start + 3) === '-') {
68112                 var end = source.indexOf('-->', start + 4); //append comment source.substring(4,end)//<!--
68113
68114                 if (end > start) {
68115                   domBuilder.comment(source, start + 4, end - start - 4);
68116                   return end + 3;
68117                 } else {
68118                   errorHandler.error("Unclosed comment");
68119                   return -1;
68120                 }
68121               } else {
68122                 //error
68123                 return -1;
68124               }
68125
68126             default:
68127               if (source.substr(start + 3, 6) == 'CDATA[') {
68128                 var end = source.indexOf(']]>', start + 9);
68129                 domBuilder.startCDATA();
68130                 domBuilder.characters(source, start + 9, end - start - 9);
68131                 domBuilder.endCDATA();
68132                 return end + 3;
68133               } //<!DOCTYPE
68134               //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
68135
68136
68137               var matchs = split$1(source, start);
68138               var len = matchs.length;
68139
68140               if (len > 1 && /!doctype/i.test(matchs[0][0])) {
68141                 var name = matchs[1][0];
68142                 var pubid = len > 3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
68143                 var sysid = len > 4 && matchs[4][0];
68144                 var lastMatch = matchs[len - 1];
68145                 domBuilder.startDTD(name, pubid && pubid.replace(/^(['"])(.*?)\1$/, '$2'), sysid && sysid.replace(/^(['"])(.*?)\1$/, '$2'));
68146                 domBuilder.endDTD();
68147                 return lastMatch.index + lastMatch[0].length;
68148               }
68149
68150           }
68151
68152           return -1;
68153         }
68154
68155         function parseInstruction(source, start, domBuilder) {
68156           var end = source.indexOf('?>', start);
68157
68158           if (end) {
68159             var match = source.substring(start, end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
68160
68161             if (match) {
68162               var len = match[0].length;
68163               domBuilder.processingInstruction(match[1], match[2]);
68164               return end + 2;
68165             } else {
68166               //error
68167               return -1;
68168             }
68169           }
68170
68171           return -1;
68172         }
68173         /**
68174          * @param source
68175          */
68176
68177
68178         function ElementAttributes(source) {}
68179
68180         ElementAttributes.prototype = {
68181           setTagName: function setTagName(tagName) {
68182             if (!tagNamePattern.test(tagName)) {
68183               throw new Error('invalid tagName:' + tagName);
68184             }
68185
68186             this.tagName = tagName;
68187           },
68188           add: function add(qName, value, offset) {
68189             if (!tagNamePattern.test(qName)) {
68190               throw new Error('invalid attribute:' + qName);
68191             }
68192
68193             this[this.length++] = {
68194               qName: qName,
68195               value: value,
68196               offset: offset
68197             };
68198           },
68199           length: 0,
68200           getLocalName: function getLocalName(i) {
68201             return this[i].localName;
68202           },
68203           getLocator: function getLocator(i) {
68204             return this[i].locator;
68205           },
68206           getQName: function getQName(i) {
68207             return this[i].qName;
68208           },
68209           getURI: function getURI(i) {
68210             return this[i].uri;
68211           },
68212           getValue: function getValue(i) {
68213             return this[i].value;
68214           } //  ,getIndex:function(uri, localName)){
68215           //            if(localName){
68216           //                    
68217           //            }else{
68218           //                    var qName = uri
68219           //            }
68220           //    },
68221           //    getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
68222           //    getType:function(uri,localName){}
68223           //    getType:function(i){},
68224
68225         };
68226
68227         function _set_proto_(thiz, parent) {
68228           thiz.__proto__ = parent;
68229           return thiz;
68230         }
68231
68232         if (!(_set_proto_({}, _set_proto_.prototype) instanceof _set_proto_)) {
68233           _set_proto_ = function _set_proto_(thiz, parent) {
68234             function p() {}
68235             p.prototype = parent;
68236             p = new p();
68237
68238             for (parent in thiz) {
68239               p[parent] = thiz[parent];
68240             }
68241
68242             return p;
68243           };
68244         }
68245
68246         function split$1(source, start) {
68247           var match;
68248           var buf = [];
68249           var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
68250           reg.lastIndex = start;
68251           reg.exec(source); //skip <
68252
68253           while (match = reg.exec(source)) {
68254             buf.push(match);
68255             if (match[1]) return buf;
68256           }
68257         }
68258
68259         var XMLReader_1 = XMLReader;
68260         var sax = {
68261           XMLReader: XMLReader_1
68262         };
68263
68264         /*
68265          * DOM Level 2
68266          * Object DOMException
68267          * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
68268          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
68269          */
68270         function copy$1(src, dest) {
68271           for (var p in src) {
68272             dest[p] = src[p];
68273           }
68274         }
68275         /**
68276         ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
68277         ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
68278          */
68279
68280
68281         function _extends(Class, Super) {
68282           var pt = Class.prototype;
68283
68284           if (Object.create) {
68285             var ppt = Object.create(Super.prototype);
68286             pt.__proto__ = ppt;
68287           }
68288
68289           if (!(pt instanceof Super)) {
68290             var t = function t() {};
68291             t.prototype = Super.prototype;
68292             t = new t();
68293             copy$1(pt, t);
68294             Class.prototype = pt = t;
68295           }
68296
68297           if (pt.constructor != Class) {
68298             if (typeof Class != 'function') {
68299               console.error("unknow Class:" + Class);
68300             }
68301
68302             pt.constructor = Class;
68303           }
68304         }
68305
68306         var htmlns = 'http://www.w3.org/1999/xhtml'; // Node Types
68307
68308         var NodeType = {};
68309         var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
68310         var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
68311         var TEXT_NODE = NodeType.TEXT_NODE = 3;
68312         var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
68313         var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
68314         var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
68315         var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
68316         var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
68317         var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
68318         var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
68319         var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
68320         var NOTATION_NODE = NodeType.NOTATION_NODE = 12; // ExceptionCode
68321
68322         var ExceptionCode = {};
68323         var ExceptionMessage = {};
68324         var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = (ExceptionMessage[1] = "Index size error", 1);
68325         var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = (ExceptionMessage[2] = "DOMString size error", 2);
68326         var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = (ExceptionMessage[3] = "Hierarchy request error", 3);
68327         var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = (ExceptionMessage[4] = "Wrong document", 4);
68328         var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = (ExceptionMessage[5] = "Invalid character", 5);
68329         var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = (ExceptionMessage[6] = "No data allowed", 6);
68330         var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = (ExceptionMessage[7] = "No modification allowed", 7);
68331         var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = (ExceptionMessage[8] = "Not found", 8);
68332         var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = (ExceptionMessage[9] = "Not supported", 9);
68333         var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = (ExceptionMessage[10] = "Attribute in use", 10); //level2
68334
68335         var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = (ExceptionMessage[11] = "Invalid state", 11);
68336         var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = (ExceptionMessage[12] = "Syntax error", 12);
68337         var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = (ExceptionMessage[13] = "Invalid modification", 13);
68338         var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = (ExceptionMessage[14] = "Invalid namespace", 14);
68339         var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = (ExceptionMessage[15] = "Invalid access", 15);
68340
68341         function DOMException$2(code, message) {
68342           if (message instanceof Error) {
68343             var error = message;
68344           } else {
68345             error = this;
68346             Error.call(this, ExceptionMessage[code]);
68347             this.message = ExceptionMessage[code];
68348             if (Error.captureStackTrace) Error.captureStackTrace(this, DOMException$2);
68349           }
68350
68351           error.code = code;
68352           if (message) this.message = this.message + ": " + message;
68353           return error;
68354         }
68355         DOMException$2.prototype = Error.prototype;
68356         copy$1(ExceptionCode, DOMException$2);
68357         /**
68358          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
68359          * 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.
68360          * The items in the NodeList are accessible via an integral index, starting from 0.
68361          */
68362
68363         function NodeList() {}
68364         NodeList.prototype = {
68365           /**
68366            * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
68367            * @standard level1
68368            */
68369           length: 0,
68370
68371           /**
68372            * 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.
68373            * @standard level1
68374            * @param index  unsigned long 
68375            *   Index into the collection.
68376            * @return Node
68377            *    The node at the indexth position in the NodeList, or null if that is not a valid index. 
68378            */
68379           item: function item(index) {
68380             return this[index] || null;
68381           },
68382           toString: function toString(isHTML, nodeFilter) {
68383             for (var buf = [], i = 0; i < this.length; i++) {
68384               serializeToString(this[i], buf, isHTML, nodeFilter);
68385             }
68386
68387             return buf.join('');
68388           }
68389         };
68390
68391         function LiveNodeList(node, refresh) {
68392           this._node = node;
68393           this._refresh = refresh;
68394
68395           _updateLiveList(this);
68396         }
68397
68398         function _updateLiveList(list) {
68399           var inc = list._node._inc || list._node.ownerDocument._inc;
68400
68401           if (list._inc != inc) {
68402             var ls = list._refresh(list._node); //console.log(ls.length)
68403
68404
68405             __set__(list, 'length', ls.length);
68406
68407             copy$1(ls, list);
68408             list._inc = inc;
68409           }
68410         }
68411
68412         LiveNodeList.prototype.item = function (i) {
68413           _updateLiveList(this);
68414
68415           return this[i];
68416         };
68417
68418         _extends(LiveNodeList, NodeList);
68419         /**
68420          * 
68421          * 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.
68422          * NamedNodeMap objects in the DOM are live.
68423          * used for attributes or DocumentType entities 
68424          */
68425
68426
68427         function NamedNodeMap() {}
68428
68429         function _findNodeIndex(list, node) {
68430           var i = list.length;
68431
68432           while (i--) {
68433             if (list[i] === node) {
68434               return i;
68435             }
68436           }
68437         }
68438
68439         function _addNamedNode(el, list, newAttr, oldAttr) {
68440           if (oldAttr) {
68441             list[_findNodeIndex(list, oldAttr)] = newAttr;
68442           } else {
68443             list[list.length++] = newAttr;
68444           }
68445
68446           if (el) {
68447             newAttr.ownerElement = el;
68448             var doc = el.ownerDocument;
68449
68450             if (doc) {
68451               oldAttr && _onRemoveAttribute(doc, el, oldAttr);
68452
68453               _onAddAttribute(doc, el, newAttr);
68454             }
68455           }
68456         }
68457
68458         function _removeNamedNode(el, list, attr) {
68459           //console.log('remove attr:'+attr)
68460           var i = _findNodeIndex(list, attr);
68461
68462           if (i >= 0) {
68463             var lastIndex = list.length - 1;
68464
68465             while (i < lastIndex) {
68466               list[i] = list[++i];
68467             }
68468
68469             list.length = lastIndex;
68470
68471             if (el) {
68472               var doc = el.ownerDocument;
68473
68474               if (doc) {
68475                 _onRemoveAttribute(doc, el, attr);
68476
68477                 attr.ownerElement = null;
68478               }
68479             }
68480           } else {
68481             throw DOMException$2(NOT_FOUND_ERR, new Error(el.tagName + '@' + attr));
68482           }
68483         }
68484
68485         NamedNodeMap.prototype = {
68486           length: 0,
68487           item: NodeList.prototype.item,
68488           getNamedItem: function getNamedItem(key) {
68489             //          if(key.indexOf(':')>0 || key == 'xmlns'){
68490             //                  return null;
68491             //          }
68492             //console.log()
68493             var i = this.length;
68494
68495             while (i--) {
68496               var attr = this[i]; //console.log(attr.nodeName,key)
68497
68498               if (attr.nodeName == key) {
68499                 return attr;
68500               }
68501             }
68502           },
68503           setNamedItem: function setNamedItem(attr) {
68504             var el = attr.ownerElement;
68505
68506             if (el && el != this._ownerElement) {
68507               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
68508             }
68509
68510             var oldAttr = this.getNamedItem(attr.nodeName);
68511
68512             _addNamedNode(this._ownerElement, this, attr, oldAttr);
68513
68514             return oldAttr;
68515           },
68516
68517           /* returns Node */
68518           setNamedItemNS: function setNamedItemNS(attr) {
68519             // raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
68520             var el = attr.ownerElement,
68521                 oldAttr;
68522
68523             if (el && el != this._ownerElement) {
68524               throw new DOMException$2(INUSE_ATTRIBUTE_ERR);
68525             }
68526
68527             oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName);
68528
68529             _addNamedNode(this._ownerElement, this, attr, oldAttr);
68530
68531             return oldAttr;
68532           },
68533
68534           /* returns Node */
68535           removeNamedItem: function removeNamedItem(key) {
68536             var attr = this.getNamedItem(key);
68537
68538             _removeNamedNode(this._ownerElement, this, attr);
68539
68540             return attr;
68541           },
68542           // raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
68543           //for level2
68544           removeNamedItemNS: function removeNamedItemNS(namespaceURI, localName) {
68545             var attr = this.getNamedItemNS(namespaceURI, localName);
68546
68547             _removeNamedNode(this._ownerElement, this, attr);
68548
68549             return attr;
68550           },
68551           getNamedItemNS: function getNamedItemNS(namespaceURI, localName) {
68552             var i = this.length;
68553
68554             while (i--) {
68555               var node = this[i];
68556
68557               if (node.localName == localName && node.namespaceURI == namespaceURI) {
68558                 return node;
68559               }
68560             }
68561
68562             return null;
68563           }
68564         };
68565         /**
68566          * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
68567          */
68568
68569         function DOMImplementation(
68570         /* Object */
68571         features) {
68572           this._features = {};
68573
68574           if (features) {
68575             for (var feature in features) {
68576               this._features = features[feature];
68577             }
68578           }
68579         }
68580         DOMImplementation.prototype = {
68581           hasFeature: function hasFeature(
68582           /* string */
68583           feature,
68584           /* string */
68585           version) {
68586             var versions = this._features[feature.toLowerCase()];
68587
68588             if (versions && (!version || version in versions)) {
68589               return true;
68590             } else {
68591               return false;
68592             }
68593           },
68594           // Introduced in DOM Level 2:
68595           createDocument: function createDocument(namespaceURI, qualifiedName, doctype) {
68596             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
68597             var doc = new Document();
68598             doc.implementation = this;
68599             doc.childNodes = new NodeList();
68600             doc.doctype = doctype;
68601
68602             if (doctype) {
68603               doc.appendChild(doctype);
68604             }
68605
68606             if (qualifiedName) {
68607               var root = doc.createElementNS(namespaceURI, qualifiedName);
68608               doc.appendChild(root);
68609             }
68610
68611             return doc;
68612           },
68613           // Introduced in DOM Level 2:
68614           createDocumentType: function createDocumentType(qualifiedName, publicId, systemId) {
68615             // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
68616             var node = new DocumentType();
68617             node.name = qualifiedName;
68618             node.nodeName = qualifiedName;
68619             node.publicId = publicId;
68620             node.systemId = systemId; // Introduced in DOM Level 2:
68621             //readonly attribute DOMString        internalSubset;
68622             //TODO:..
68623             //  readonly attribute NamedNodeMap     entities;
68624             //  readonly attribute NamedNodeMap     notations;
68625
68626             return node;
68627           }
68628         };
68629         /**
68630          * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
68631          */
68632
68633         function Node() {}
68634         Node.prototype = {
68635           firstChild: null,
68636           lastChild: null,
68637           previousSibling: null,
68638           nextSibling: null,
68639           attributes: null,
68640           parentNode: null,
68641           childNodes: null,
68642           ownerDocument: null,
68643           nodeValue: null,
68644           namespaceURI: null,
68645           prefix: null,
68646           localName: null,
68647           // Modified in DOM Level 2:
68648           insertBefore: function insertBefore(newChild, refChild) {
68649             //raises 
68650             return _insertBefore(this, newChild, refChild);
68651           },
68652           replaceChild: function replaceChild(newChild, oldChild) {
68653             //raises 
68654             this.insertBefore(newChild, oldChild);
68655
68656             if (oldChild) {
68657               this.removeChild(oldChild);
68658             }
68659           },
68660           removeChild: function removeChild(oldChild) {
68661             return _removeChild(this, oldChild);
68662           },
68663           appendChild: function appendChild(newChild) {
68664             return this.insertBefore(newChild, null);
68665           },
68666           hasChildNodes: function hasChildNodes() {
68667             return this.firstChild != null;
68668           },
68669           cloneNode: function cloneNode(deep) {
68670             return _cloneNode(this.ownerDocument || this, this, deep);
68671           },
68672           // Modified in DOM Level 2:
68673           normalize: function normalize() {
68674             var child = this.firstChild;
68675
68676             while (child) {
68677               var next = child.nextSibling;
68678
68679               if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {
68680                 this.removeChild(next);
68681                 child.appendData(next.data);
68682               } else {
68683                 child.normalize();
68684                 child = next;
68685               }
68686             }
68687           },
68688           // Introduced in DOM Level 2:
68689           isSupported: function isSupported(feature, version) {
68690             return this.ownerDocument.implementation.hasFeature(feature, version);
68691           },
68692           // Introduced in DOM Level 2:
68693           hasAttributes: function hasAttributes() {
68694             return this.attributes.length > 0;
68695           },
68696           lookupPrefix: function lookupPrefix(namespaceURI) {
68697             var el = this;
68698
68699             while (el) {
68700               var map = el._nsMap; //console.dir(map)
68701
68702               if (map) {
68703                 for (var n in map) {
68704                   if (map[n] == namespaceURI) {
68705                     return n;
68706                   }
68707                 }
68708               }
68709
68710               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
68711             }
68712
68713             return null;
68714           },
68715           // Introduced in DOM Level 3:
68716           lookupNamespaceURI: function lookupNamespaceURI(prefix) {
68717             var el = this;
68718
68719             while (el) {
68720               var map = el._nsMap; //console.dir(map)
68721
68722               if (map) {
68723                 if (prefix in map) {
68724                   return map[prefix];
68725                 }
68726               }
68727
68728               el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode;
68729             }
68730
68731             return null;
68732           },
68733           // Introduced in DOM Level 3:
68734           isDefaultNamespace: function isDefaultNamespace(namespaceURI) {
68735             var prefix = this.lookupPrefix(namespaceURI);
68736             return prefix == null;
68737           }
68738         };
68739
68740         function _xmlEncoder(c) {
68741           return c == '<' && '&lt;' || c == '>' && '&gt;' || c == '&' && '&amp;' || c == '"' && '&quot;' || '&#' + c.charCodeAt() + ';';
68742         }
68743
68744         copy$1(NodeType, Node);
68745         copy$1(NodeType, Node.prototype);
68746         /**
68747          * @param callback return true for continue,false for break
68748          * @return boolean true: break visit;
68749          */
68750
68751         function _visitNode(node, callback) {
68752           if (callback(node)) {
68753             return true;
68754           }
68755
68756           if (node = node.firstChild) {
68757             do {
68758               if (_visitNode(node, callback)) {
68759                 return true;
68760               }
68761             } while (node = node.nextSibling);
68762           }
68763         }
68764
68765         function Document() {}
68766
68767         function _onAddAttribute(doc, el, newAttr) {
68768           doc && doc._inc++;
68769           var ns = newAttr.namespaceURI;
68770
68771           if (ns == 'http://www.w3.org/2000/xmlns/') {
68772             //update namespace
68773             el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value;
68774           }
68775         }
68776
68777         function _onRemoveAttribute(doc, el, newAttr, remove) {
68778           doc && doc._inc++;
68779           var ns = newAttr.namespaceURI;
68780
68781           if (ns == 'http://www.w3.org/2000/xmlns/') {
68782             //update namespace
68783             delete el._nsMap[newAttr.prefix ? newAttr.localName : ''];
68784           }
68785         }
68786
68787         function _onUpdateChild(doc, el, newChild) {
68788           if (doc && doc._inc) {
68789             doc._inc++; //update childNodes
68790
68791             var cs = el.childNodes;
68792
68793             if (newChild) {
68794               cs[cs.length++] = newChild;
68795             } else {
68796               //console.log(1)
68797               var child = el.firstChild;
68798               var i = 0;
68799
68800               while (child) {
68801                 cs[i++] = child;
68802                 child = child.nextSibling;
68803               }
68804
68805               cs.length = i;
68806             }
68807           }
68808         }
68809         /**
68810          * attributes;
68811          * children;
68812          * 
68813          * writeable properties:
68814          * nodeValue,Attr:value,CharacterData:data
68815          * prefix
68816          */
68817
68818
68819         function _removeChild(parentNode, child) {
68820           var previous = child.previousSibling;
68821           var next = child.nextSibling;
68822
68823           if (previous) {
68824             previous.nextSibling = next;
68825           } else {
68826             parentNode.firstChild = next;
68827           }
68828
68829           if (next) {
68830             next.previousSibling = previous;
68831           } else {
68832             parentNode.lastChild = previous;
68833           }
68834
68835           _onUpdateChild(parentNode.ownerDocument, parentNode);
68836
68837           return child;
68838         }
68839         /**
68840          * preformance key(refChild == null)
68841          */
68842
68843
68844         function _insertBefore(parentNode, newChild, nextChild) {
68845           var cp = newChild.parentNode;
68846
68847           if (cp) {
68848             cp.removeChild(newChild); //remove and update
68849           }
68850
68851           if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
68852             var newFirst = newChild.firstChild;
68853
68854             if (newFirst == null) {
68855               return newChild;
68856             }
68857
68858             var newLast = newChild.lastChild;
68859           } else {
68860             newFirst = newLast = newChild;
68861           }
68862
68863           var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
68864           newFirst.previousSibling = pre;
68865           newLast.nextSibling = nextChild;
68866
68867           if (pre) {
68868             pre.nextSibling = newFirst;
68869           } else {
68870             parentNode.firstChild = newFirst;
68871           }
68872
68873           if (nextChild == null) {
68874             parentNode.lastChild = newLast;
68875           } else {
68876             nextChild.previousSibling = newLast;
68877           }
68878
68879           do {
68880             newFirst.parentNode = parentNode;
68881           } while (newFirst !== newLast && (newFirst = newFirst.nextSibling));
68882
68883           _onUpdateChild(parentNode.ownerDocument || parentNode, parentNode); //console.log(parentNode.lastChild.nextSibling == null)
68884
68885
68886           if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
68887             newChild.firstChild = newChild.lastChild = null;
68888           }
68889
68890           return newChild;
68891         }
68892
68893         function _appendSingleChild(parentNode, newChild) {
68894           var cp = newChild.parentNode;
68895
68896           if (cp) {
68897             var pre = parentNode.lastChild;
68898             cp.removeChild(newChild); //remove and update
68899
68900             var pre = parentNode.lastChild;
68901           }
68902
68903           var pre = parentNode.lastChild;
68904           newChild.parentNode = parentNode;
68905           newChild.previousSibling = pre;
68906           newChild.nextSibling = null;
68907
68908           if (pre) {
68909             pre.nextSibling = newChild;
68910           } else {
68911             parentNode.firstChild = newChild;
68912           }
68913
68914           parentNode.lastChild = newChild;
68915
68916           _onUpdateChild(parentNode.ownerDocument, parentNode, newChild);
68917
68918           return newChild; //console.log("__aa",parentNode.lastChild.nextSibling == null)
68919         }
68920
68921         Document.prototype = {
68922           //implementation : null,
68923           nodeName: '#document',
68924           nodeType: DOCUMENT_NODE,
68925           doctype: null,
68926           documentElement: null,
68927           _inc: 1,
68928           insertBefore: function insertBefore(newChild, refChild) {
68929             //raises 
68930             if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
68931               var child = newChild.firstChild;
68932
68933               while (child) {
68934                 var next = child.nextSibling;
68935                 this.insertBefore(child, refChild);
68936                 child = next;
68937               }
68938
68939               return newChild;
68940             }
68941
68942             if (this.documentElement == null && newChild.nodeType == ELEMENT_NODE) {
68943               this.documentElement = newChild;
68944             }
68945
68946             return _insertBefore(this, newChild, refChild), newChild.ownerDocument = this, newChild;
68947           },
68948           removeChild: function removeChild(oldChild) {
68949             if (this.documentElement == oldChild) {
68950               this.documentElement = null;
68951             }
68952
68953             return _removeChild(this, oldChild);
68954           },
68955           // Introduced in DOM Level 2:
68956           importNode: function importNode(importedNode, deep) {
68957             return _importNode(this, importedNode, deep);
68958           },
68959           // Introduced in DOM Level 2:
68960           getElementById: function getElementById(id) {
68961             var rtv = null;
68962
68963             _visitNode(this.documentElement, function (node) {
68964               if (node.nodeType == ELEMENT_NODE) {
68965                 if (node.getAttribute('id') == id) {
68966                   rtv = node;
68967                   return true;
68968                 }
68969               }
68970             });
68971
68972             return rtv;
68973           },
68974           //document factory method:
68975           createElement: function createElement(tagName) {
68976             var node = new Element();
68977             node.ownerDocument = this;
68978             node.nodeName = tagName;
68979             node.tagName = tagName;
68980             node.childNodes = new NodeList();
68981             var attrs = node.attributes = new NamedNodeMap();
68982             attrs._ownerElement = node;
68983             return node;
68984           },
68985           createDocumentFragment: function createDocumentFragment() {
68986             var node = new DocumentFragment();
68987             node.ownerDocument = this;
68988             node.childNodes = new NodeList();
68989             return node;
68990           },
68991           createTextNode: function createTextNode(data) {
68992             var node = new Text();
68993             node.ownerDocument = this;
68994             node.appendData(data);
68995             return node;
68996           },
68997           createComment: function createComment(data) {
68998             var node = new Comment();
68999             node.ownerDocument = this;
69000             node.appendData(data);
69001             return node;
69002           },
69003           createCDATASection: function createCDATASection(data) {
69004             var node = new CDATASection();
69005             node.ownerDocument = this;
69006             node.appendData(data);
69007             return node;
69008           },
69009           createProcessingInstruction: function createProcessingInstruction(target, data) {
69010             var node = new ProcessingInstruction();
69011             node.ownerDocument = this;
69012             node.tagName = node.target = target;
69013             node.nodeValue = node.data = data;
69014             return node;
69015           },
69016           createAttribute: function createAttribute(name) {
69017             var node = new Attr();
69018             node.ownerDocument = this;
69019             node.name = name;
69020             node.nodeName = name;
69021             node.localName = name;
69022             node.specified = true;
69023             return node;
69024           },
69025           createEntityReference: function createEntityReference(name) {
69026             var node = new EntityReference();
69027             node.ownerDocument = this;
69028             node.nodeName = name;
69029             return node;
69030           },
69031           // Introduced in DOM Level 2:
69032           createElementNS: function createElementNS(namespaceURI, qualifiedName) {
69033             var node = new Element();
69034             var pl = qualifiedName.split(':');
69035             var attrs = node.attributes = new NamedNodeMap();
69036             node.childNodes = new NodeList();
69037             node.ownerDocument = this;
69038             node.nodeName = qualifiedName;
69039             node.tagName = qualifiedName;
69040             node.namespaceURI = namespaceURI;
69041
69042             if (pl.length == 2) {
69043               node.prefix = pl[0];
69044               node.localName = pl[1];
69045             } else {
69046               //el.prefix = null;
69047               node.localName = qualifiedName;
69048             }
69049
69050             attrs._ownerElement = node;
69051             return node;
69052           },
69053           // Introduced in DOM Level 2:
69054           createAttributeNS: function createAttributeNS(namespaceURI, qualifiedName) {
69055             var node = new Attr();
69056             var pl = qualifiedName.split(':');
69057             node.ownerDocument = this;
69058             node.nodeName = qualifiedName;
69059             node.name = qualifiedName;
69060             node.namespaceURI = namespaceURI;
69061             node.specified = true;
69062
69063             if (pl.length == 2) {
69064               node.prefix = pl[0];
69065               node.localName = pl[1];
69066             } else {
69067               //el.prefix = null;
69068               node.localName = qualifiedName;
69069             }
69070
69071             return node;
69072           }
69073         };
69074
69075         _extends(Document, Node);
69076
69077         function Element() {
69078           this._nsMap = {};
69079         }
69080         Element.prototype = {
69081           nodeType: ELEMENT_NODE,
69082           hasAttribute: function hasAttribute(name) {
69083             return this.getAttributeNode(name) != null;
69084           },
69085           getAttribute: function getAttribute(name) {
69086             var attr = this.getAttributeNode(name);
69087             return attr && attr.value || '';
69088           },
69089           getAttributeNode: function getAttributeNode(name) {
69090             return this.attributes.getNamedItem(name);
69091           },
69092           setAttribute: function setAttribute(name, value) {
69093             var attr = this.ownerDocument.createAttribute(name);
69094             attr.value = attr.nodeValue = "" + value;
69095             this.setAttributeNode(attr);
69096           },
69097           removeAttribute: function removeAttribute(name) {
69098             var attr = this.getAttributeNode(name);
69099             attr && this.removeAttributeNode(attr);
69100           },
69101           //four real opeartion method
69102           appendChild: function appendChild(newChild) {
69103             if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) {
69104               return this.insertBefore(newChild, null);
69105             } else {
69106               return _appendSingleChild(this, newChild);
69107             }
69108           },
69109           setAttributeNode: function setAttributeNode(newAttr) {
69110             return this.attributes.setNamedItem(newAttr);
69111           },
69112           setAttributeNodeNS: function setAttributeNodeNS(newAttr) {
69113             return this.attributes.setNamedItemNS(newAttr);
69114           },
69115           removeAttributeNode: function removeAttributeNode(oldAttr) {
69116             //console.log(this == oldAttr.ownerElement)
69117             return this.attributes.removeNamedItem(oldAttr.nodeName);
69118           },
69119           //get real attribute name,and remove it by removeAttributeNode
69120           removeAttributeNS: function removeAttributeNS(namespaceURI, localName) {
69121             var old = this.getAttributeNodeNS(namespaceURI, localName);
69122             old && this.removeAttributeNode(old);
69123           },
69124           hasAttributeNS: function hasAttributeNS(namespaceURI, localName) {
69125             return this.getAttributeNodeNS(namespaceURI, localName) != null;
69126           },
69127           getAttributeNS: function getAttributeNS(namespaceURI, localName) {
69128             var attr = this.getAttributeNodeNS(namespaceURI, localName);
69129             return attr && attr.value || '';
69130           },
69131           setAttributeNS: function setAttributeNS(namespaceURI, qualifiedName, value) {
69132             var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
69133             attr.value = attr.nodeValue = "" + value;
69134             this.setAttributeNode(attr);
69135           },
69136           getAttributeNodeNS: function getAttributeNodeNS(namespaceURI, localName) {
69137             return this.attributes.getNamedItemNS(namespaceURI, localName);
69138           },
69139           getElementsByTagName: function getElementsByTagName(tagName) {
69140             return new LiveNodeList(this, function (base) {
69141               var ls = [];
69142
69143               _visitNode(base, function (node) {
69144                 if (node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)) {
69145                   ls.push(node);
69146                 }
69147               });
69148
69149               return ls;
69150             });
69151           },
69152           getElementsByTagNameNS: function getElementsByTagNameNS(namespaceURI, localName) {
69153             return new LiveNodeList(this, function (base) {
69154               var ls = [];
69155
69156               _visitNode(base, function (node) {
69157                 if (node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)) {
69158                   ls.push(node);
69159                 }
69160               });
69161
69162               return ls;
69163             });
69164           }
69165         };
69166         Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
69167         Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
69168
69169         _extends(Element, Node);
69170
69171         function Attr() {}
69172         Attr.prototype.nodeType = ATTRIBUTE_NODE;
69173
69174         _extends(Attr, Node);
69175
69176         function CharacterData() {}
69177         CharacterData.prototype = {
69178           data: '',
69179           substringData: function substringData(offset, count) {
69180             return this.data.substring(offset, offset + count);
69181           },
69182           appendData: function appendData(text) {
69183             text = this.data + text;
69184             this.nodeValue = this.data = text;
69185             this.length = text.length;
69186           },
69187           insertData: function insertData(offset, text) {
69188             this.replaceData(offset, 0, text);
69189           },
69190           appendChild: function appendChild(newChild) {
69191             throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]);
69192           },
69193           deleteData: function deleteData(offset, count) {
69194             this.replaceData(offset, count, "");
69195           },
69196           replaceData: function replaceData(offset, count, text) {
69197             var start = this.data.substring(0, offset);
69198             var end = this.data.substring(offset + count);
69199             text = start + text + end;
69200             this.nodeValue = this.data = text;
69201             this.length = text.length;
69202           }
69203         };
69204
69205         _extends(CharacterData, Node);
69206
69207         function Text() {}
69208         Text.prototype = {
69209           nodeName: "#text",
69210           nodeType: TEXT_NODE,
69211           splitText: function splitText(offset) {
69212             var text = this.data;
69213             var newText = text.substring(offset);
69214             text = text.substring(0, offset);
69215             this.data = this.nodeValue = text;
69216             this.length = text.length;
69217             var newNode = this.ownerDocument.createTextNode(newText);
69218
69219             if (this.parentNode) {
69220               this.parentNode.insertBefore(newNode, this.nextSibling);
69221             }
69222
69223             return newNode;
69224           }
69225         };
69226
69227         _extends(Text, CharacterData);
69228
69229         function Comment() {}
69230         Comment.prototype = {
69231           nodeName: "#comment",
69232           nodeType: COMMENT_NODE
69233         };
69234
69235         _extends(Comment, CharacterData);
69236
69237         function CDATASection() {}
69238         CDATASection.prototype = {
69239           nodeName: "#cdata-section",
69240           nodeType: CDATA_SECTION_NODE
69241         };
69242
69243         _extends(CDATASection, CharacterData);
69244
69245         function DocumentType() {}
69246         DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
69247
69248         _extends(DocumentType, Node);
69249
69250         function Notation() {}
69251         Notation.prototype.nodeType = NOTATION_NODE;
69252
69253         _extends(Notation, Node);
69254
69255         function Entity() {}
69256         Entity.prototype.nodeType = ENTITY_NODE;
69257
69258         _extends(Entity, Node);
69259
69260         function EntityReference() {}
69261         EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
69262
69263         _extends(EntityReference, Node);
69264
69265         function DocumentFragment() {}
69266         DocumentFragment.prototype.nodeName = "#document-fragment";
69267         DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE;
69268
69269         _extends(DocumentFragment, Node);
69270
69271         function ProcessingInstruction() {}
69272
69273         ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
69274
69275         _extends(ProcessingInstruction, Node);
69276
69277         function XMLSerializer$1() {}
69278
69279         XMLSerializer$1.prototype.serializeToString = function (node, isHtml, nodeFilter) {
69280           return nodeSerializeToString.call(node, isHtml, nodeFilter);
69281         };
69282
69283         Node.prototype.toString = nodeSerializeToString;
69284
69285         function nodeSerializeToString(isHtml, nodeFilter) {
69286           var buf = [];
69287           var refNode = this.nodeType == 9 ? this.documentElement : this;
69288           var prefix = refNode.prefix;
69289           var uri = refNode.namespaceURI;
69290
69291           if (uri && prefix == null) {
69292             //console.log(prefix)
69293             var prefix = refNode.lookupPrefix(uri);
69294
69295             if (prefix == null) {
69296               //isHTML = true;
69297               var visibleNamespaces = [{
69298                 namespace: uri,
69299                 prefix: null
69300               } //{namespace:uri,prefix:''}
69301               ];
69302             }
69303           }
69304
69305           serializeToString(this, buf, isHtml, nodeFilter, visibleNamespaces); //console.log('###',this.nodeType,uri,prefix,buf.join(''))
69306
69307           return buf.join('');
69308         }
69309
69310         function needNamespaceDefine(node, isHTML, visibleNamespaces) {
69311           var prefix = node.prefix || '';
69312           var uri = node.namespaceURI;
69313
69314           if (!prefix && !uri) {
69315             return false;
69316           }
69317
69318           if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" || uri == 'http://www.w3.org/2000/xmlns/') {
69319             return false;
69320           }
69321
69322           var i = visibleNamespaces.length; //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
69323
69324           while (i--) {
69325             var ns = visibleNamespaces[i]; // get namespace prefix
69326             //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
69327
69328             if (ns.prefix == prefix) {
69329               return ns.namespace != uri;
69330             }
69331           } //console.log(isHTML,uri,prefix=='')
69332           //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
69333           //    return false;
69334           //}
69335           //node.flag = '11111'
69336           //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
69337
69338
69339           return true;
69340         }
69341
69342         function serializeToString(node, buf, isHTML, nodeFilter, visibleNamespaces) {
69343           if (nodeFilter) {
69344             node = nodeFilter(node);
69345
69346             if (node) {
69347               if (typeof node == 'string') {
69348                 buf.push(node);
69349                 return;
69350               }
69351             } else {
69352               return;
69353             } //buf.sort.apply(attrs, attributeSorter);
69354
69355           }
69356
69357           switch (node.nodeType) {
69358             case ELEMENT_NODE:
69359               if (!visibleNamespaces) visibleNamespaces = [];
69360               var startVisibleNamespaces = visibleNamespaces.length;
69361               var attrs = node.attributes;
69362               var len = attrs.length;
69363               var child = node.firstChild;
69364               var nodeName = node.tagName;
69365               isHTML = htmlns === node.namespaceURI || isHTML;
69366               buf.push('<', nodeName);
69367
69368               for (var i = 0; i < len; i++) {
69369                 // add namespaces for attributes
69370                 var attr = attrs.item(i);
69371
69372                 if (attr.prefix == 'xmlns') {
69373                   visibleNamespaces.push({
69374                     prefix: attr.localName,
69375                     namespace: attr.value
69376                   });
69377                 } else if (attr.nodeName == 'xmlns') {
69378                   visibleNamespaces.push({
69379                     prefix: '',
69380                     namespace: attr.value
69381                   });
69382                 }
69383               }
69384
69385               for (var i = 0; i < len; i++) {
69386                 var attr = attrs.item(i);
69387
69388                 if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) {
69389                   var prefix = attr.prefix || '';
69390                   var uri = attr.namespaceURI;
69391                   var ns = prefix ? ' xmlns:' + prefix : " xmlns";
69392                   buf.push(ns, '="', uri, '"');
69393                   visibleNamespaces.push({
69394                     prefix: prefix,
69395                     namespace: uri
69396                   });
69397                 }
69398
69399                 serializeToString(attr, buf, isHTML, nodeFilter, visibleNamespaces);
69400               } // add namespace for current node               
69401
69402
69403               if (needNamespaceDefine(node, isHTML, visibleNamespaces)) {
69404                 var prefix = node.prefix || '';
69405                 var uri = node.namespaceURI;
69406                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
69407                 buf.push(ns, '="', uri, '"');
69408                 visibleNamespaces.push({
69409                   prefix: prefix,
69410                   namespace: uri
69411                 });
69412               }
69413
69414               if (child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)) {
69415                 buf.push('>'); //if is cdata child node
69416
69417                 if (isHTML && /^script$/i.test(nodeName)) {
69418                   while (child) {
69419                     if (child.data) {
69420                       buf.push(child.data);
69421                     } else {
69422                       serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69423                     }
69424
69425                     child = child.nextSibling;
69426                   }
69427                 } else {
69428                   while (child) {
69429                     serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69430                     child = child.nextSibling;
69431                   }
69432                 }
69433
69434                 buf.push('</', nodeName, '>');
69435               } else {
69436                 buf.push('/>');
69437               } // remove added visible namespaces
69438               //visibleNamespaces.length = startVisibleNamespaces;
69439
69440
69441               return;
69442
69443             case DOCUMENT_NODE:
69444             case DOCUMENT_FRAGMENT_NODE:
69445               var child = node.firstChild;
69446
69447               while (child) {
69448                 serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces);
69449                 child = child.nextSibling;
69450               }
69451
69452               return;
69453
69454             case ATTRIBUTE_NODE:
69455               return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g, _xmlEncoder), '"');
69456
69457             case TEXT_NODE:
69458               return buf.push(node.data.replace(/[<&]/g, _xmlEncoder));
69459
69460             case CDATA_SECTION_NODE:
69461               return buf.push('<![CDATA[', node.data, ']]>');
69462
69463             case COMMENT_NODE:
69464               return buf.push("<!--", node.data, "-->");
69465
69466             case DOCUMENT_TYPE_NODE:
69467               var pubid = node.publicId;
69468               var sysid = node.systemId;
69469               buf.push('<!DOCTYPE ', node.name);
69470
69471               if (pubid) {
69472                 buf.push(' PUBLIC "', pubid);
69473
69474                 if (sysid && sysid != '.') {
69475                   buf.push('" "', sysid);
69476                 }
69477
69478                 buf.push('">');
69479               } else if (sysid && sysid != '.') {
69480                 buf.push(' SYSTEM "', sysid, '">');
69481               } else {
69482                 var sub = node.internalSubset;
69483
69484                 if (sub) {
69485                   buf.push(" [", sub, "]");
69486                 }
69487
69488                 buf.push(">");
69489               }
69490
69491               return;
69492
69493             case PROCESSING_INSTRUCTION_NODE:
69494               return buf.push("<?", node.target, " ", node.data, "?>");
69495
69496             case ENTITY_REFERENCE_NODE:
69497               return buf.push('&', node.nodeName, ';');
69498             //case ENTITY_NODE:
69499             //case NOTATION_NODE:
69500
69501             default:
69502               buf.push('??', node.nodeName);
69503           }
69504         }
69505
69506         function _importNode(doc, node, deep) {
69507           var node2;
69508
69509           switch (node.nodeType) {
69510             case ELEMENT_NODE:
69511               node2 = node.cloneNode(false);
69512               node2.ownerDocument = doc;
69513             //var attrs = node2.attributes;
69514             //var len = attrs.length;
69515             //for(var i=0;i<len;i++){
69516             //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
69517             //}
69518
69519             case DOCUMENT_FRAGMENT_NODE:
69520               break;
69521
69522             case ATTRIBUTE_NODE:
69523               deep = true;
69524               break;
69525             //case ENTITY_REFERENCE_NODE:
69526             //case PROCESSING_INSTRUCTION_NODE:
69527             ////case TEXT_NODE:
69528             //case CDATA_SECTION_NODE:
69529             //case COMMENT_NODE:
69530             //  deep = false;
69531             //  break;
69532             //case DOCUMENT_NODE:
69533             //case DOCUMENT_TYPE_NODE:
69534             //cannot be imported.
69535             //case ENTITY_NODE:
69536             //case NOTATION_NODE:
69537             //can not hit in level3
69538             //default:throw e;
69539           }
69540
69541           if (!node2) {
69542             node2 = node.cloneNode(false); //false
69543           }
69544
69545           node2.ownerDocument = doc;
69546           node2.parentNode = null;
69547
69548           if (deep) {
69549             var child = node.firstChild;
69550
69551             while (child) {
69552               node2.appendChild(_importNode(doc, child, deep));
69553               child = child.nextSibling;
69554             }
69555           }
69556
69557           return node2;
69558         } //
69559         //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
69560         //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
69561
69562
69563         function _cloneNode(doc, node, deep) {
69564           var node2 = new node.constructor();
69565
69566           for (var n in node) {
69567             var v = node[n];
69568
69569             if (_typeof(v) != 'object') {
69570               if (v != node2[n]) {
69571                 node2[n] = v;
69572               }
69573             }
69574           }
69575
69576           if (node.childNodes) {
69577             node2.childNodes = new NodeList();
69578           }
69579
69580           node2.ownerDocument = doc;
69581
69582           switch (node2.nodeType) {
69583             case ELEMENT_NODE:
69584               var attrs = node.attributes;
69585               var attrs2 = node2.attributes = new NamedNodeMap();
69586               var len = attrs.length;
69587               attrs2._ownerElement = node2;
69588
69589               for (var i = 0; i < len; i++) {
69590                 node2.setAttributeNode(_cloneNode(doc, attrs.item(i), true));
69591               }
69592
69593               break;
69594
69595             case ATTRIBUTE_NODE:
69596               deep = true;
69597           }
69598
69599           if (deep) {
69600             var child = node.firstChild;
69601
69602             while (child) {
69603               node2.appendChild(_cloneNode(doc, child, deep));
69604               child = child.nextSibling;
69605             }
69606           }
69607
69608           return node2;
69609         }
69610
69611         function __set__(object, key, value) {
69612           object[key] = value;
69613         } //do dynamic
69614
69615
69616         try {
69617           if (Object.defineProperty) {
69618             var getTextContent = function getTextContent(node) {
69619               switch (node.nodeType) {
69620                 case ELEMENT_NODE:
69621                 case DOCUMENT_FRAGMENT_NODE:
69622                   var buf = [];
69623                   node = node.firstChild;
69624
69625                   while (node) {
69626                     if (node.nodeType !== 7 && node.nodeType !== 8) {
69627                       buf.push(getTextContent(node));
69628                     }
69629
69630                     node = node.nextSibling;
69631                   }
69632
69633                   return buf.join('');
69634
69635                 default:
69636                   return node.nodeValue;
69637               }
69638             };
69639
69640             Object.defineProperty(LiveNodeList.prototype, 'length', {
69641               get: function get() {
69642                 _updateLiveList(this);
69643
69644                 return this.$$length;
69645               }
69646             });
69647             Object.defineProperty(Node.prototype, 'textContent', {
69648               get: function get() {
69649                 return getTextContent(this);
69650               },
69651               set: function set(data) {
69652                 switch (this.nodeType) {
69653                   case ELEMENT_NODE:
69654                   case DOCUMENT_FRAGMENT_NODE:
69655                     while (this.firstChild) {
69656                       this.removeChild(this.firstChild);
69657                     }
69658
69659                     if (data || String(data)) {
69660                       this.appendChild(this.ownerDocument.createTextNode(data));
69661                     }
69662
69663                     break;
69664
69665                   default:
69666                     //TODO:
69667                     this.data = data;
69668                     this.value = data;
69669                     this.nodeValue = data;
69670                 }
69671               }
69672             });
69673
69674             __set__ = function __set__(object, key, value) {
69675               //console.log(value)
69676               object['$$' + key] = value;
69677             };
69678           }
69679         } catch (e) {//ie8
69680         } //if(typeof require == 'function'){
69681
69682
69683         var DOMImplementation_1 = DOMImplementation;
69684         var XMLSerializer_1 = XMLSerializer$1; //}
69685
69686         var dom = {
69687           DOMImplementation: DOMImplementation_1,
69688           XMLSerializer: XMLSerializer_1
69689         };
69690
69691         var domParser = createCommonjsModule(function (module, exports) {
69692           function DOMParser(options) {
69693             this.options = options || {
69694               locator: {}
69695             };
69696           }
69697
69698           DOMParser.prototype.parseFromString = function (source, mimeType) {
69699             var options = this.options;
69700             var sax = new XMLReader();
69701             var domBuilder = options.domBuilder || new DOMHandler(); //contentHandler and LexicalHandler
69702
69703             var errorHandler = options.errorHandler;
69704             var locator = options.locator;
69705             var defaultNSMap = options.xmlns || {};
69706             var entityMap = {
69707               'lt': '<',
69708               'gt': '>',
69709               'amp': '&',
69710               'quot': '"',
69711               'apos': "'"
69712             };
69713
69714             if (locator) {
69715               domBuilder.setDocumentLocator(locator);
69716             }
69717
69718             sax.errorHandler = buildErrorHandler(errorHandler, domBuilder, locator);
69719             sax.domBuilder = options.domBuilder || domBuilder;
69720
69721             if (/\/x?html?$/.test(mimeType)) {
69722               entityMap.nbsp = '\xa0';
69723               entityMap.copy = '\xa9';
69724               defaultNSMap[''] = 'http://www.w3.org/1999/xhtml';
69725             }
69726
69727             defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
69728
69729             if (source) {
69730               sax.parse(source, defaultNSMap, entityMap);
69731             } else {
69732               sax.errorHandler.error("invalid doc source");
69733             }
69734
69735             return domBuilder.doc;
69736           };
69737
69738           function buildErrorHandler(errorImpl, domBuilder, locator) {
69739             if (!errorImpl) {
69740               if (domBuilder instanceof DOMHandler) {
69741                 return domBuilder;
69742               }
69743
69744               errorImpl = domBuilder;
69745             }
69746
69747             var errorHandler = {};
69748             var isCallback = errorImpl instanceof Function;
69749             locator = locator || {};
69750
69751             function build(key) {
69752               var fn = errorImpl[key];
69753
69754               if (!fn && isCallback) {
69755                 fn = errorImpl.length == 2 ? function (msg) {
69756                   errorImpl(key, msg);
69757                 } : errorImpl;
69758               }
69759
69760               errorHandler[key] = fn && function (msg) {
69761                 fn('[xmldom ' + key + ']\t' + msg + _locator(locator));
69762               } || function () {};
69763             }
69764
69765             build('warning');
69766             build('error');
69767             build('fatalError');
69768             return errorHandler;
69769           } //console.log('#\n\n\n\n\n\n\n####')
69770
69771           /**
69772            * +ContentHandler+ErrorHandler
69773            * +LexicalHandler+EntityResolver2
69774            * -DeclHandler-DTDHandler 
69775            * 
69776            * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
69777            * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
69778            * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
69779            */
69780
69781
69782           function DOMHandler() {
69783             this.cdata = false;
69784           }
69785
69786           function position(locator, node) {
69787             node.lineNumber = locator.lineNumber;
69788             node.columnNumber = locator.columnNumber;
69789           }
69790           /**
69791            * @see org.xml.sax.ContentHandler#startDocument
69792            * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
69793            */
69794
69795
69796           DOMHandler.prototype = {
69797             startDocument: function startDocument() {
69798               this.doc = new DOMImplementation().createDocument(null, null, null);
69799
69800               if (this.locator) {
69801                 this.doc.documentURI = this.locator.systemId;
69802               }
69803             },
69804             startElement: function startElement(namespaceURI, localName, qName, attrs) {
69805               var doc = this.doc;
69806               var el = doc.createElementNS(namespaceURI, qName || localName);
69807               var len = attrs.length;
69808               appendElement(this, el);
69809               this.currentElement = el;
69810               this.locator && position(this.locator, el);
69811
69812               for (var i = 0; i < len; i++) {
69813                 var namespaceURI = attrs.getURI(i);
69814                 var value = attrs.getValue(i);
69815                 var qName = attrs.getQName(i);
69816                 var attr = doc.createAttributeNS(namespaceURI, qName);
69817                 this.locator && position(attrs.getLocator(i), attr);
69818                 attr.value = attr.nodeValue = value;
69819                 el.setAttributeNode(attr);
69820               }
69821             },
69822             endElement: function endElement(namespaceURI, localName, qName) {
69823               var current = this.currentElement;
69824               var tagName = current.tagName;
69825               this.currentElement = current.parentNode;
69826             },
69827             startPrefixMapping: function startPrefixMapping(prefix, uri) {},
69828             endPrefixMapping: function endPrefixMapping(prefix) {},
69829             processingInstruction: function processingInstruction(target, data) {
69830               var ins = this.doc.createProcessingInstruction(target, data);
69831               this.locator && position(this.locator, ins);
69832               appendElement(this, ins);
69833             },
69834             ignorableWhitespace: function ignorableWhitespace(ch, start, length) {},
69835             characters: function characters(chars, start, length) {
69836               chars = _toString.apply(this, arguments); //console.log(chars)
69837
69838               if (chars) {
69839                 if (this.cdata) {
69840                   var charNode = this.doc.createCDATASection(chars);
69841                 } else {
69842                   var charNode = this.doc.createTextNode(chars);
69843                 }
69844
69845                 if (this.currentElement) {
69846                   this.currentElement.appendChild(charNode);
69847                 } else if (/^\s*$/.test(chars)) {
69848                   this.doc.appendChild(charNode); //process xml
69849                 }
69850
69851                 this.locator && position(this.locator, charNode);
69852               }
69853             },
69854             skippedEntity: function skippedEntity(name) {},
69855             endDocument: function endDocument() {
69856               this.doc.normalize();
69857             },
69858             setDocumentLocator: function setDocumentLocator(locator) {
69859               if (this.locator = locator) {
69860                 // && !('lineNumber' in locator)){
69861                 locator.lineNumber = 0;
69862               }
69863             },
69864             //LexicalHandler
69865             comment: function comment(chars, start, length) {
69866               chars = _toString.apply(this, arguments);
69867               var comm = this.doc.createComment(chars);
69868               this.locator && position(this.locator, comm);
69869               appendElement(this, comm);
69870             },
69871             startCDATA: function startCDATA() {
69872               //used in characters() methods
69873               this.cdata = true;
69874             },
69875             endCDATA: function endCDATA() {
69876               this.cdata = false;
69877             },
69878             startDTD: function startDTD(name, publicId, systemId) {
69879               var impl = this.doc.implementation;
69880
69881               if (impl && impl.createDocumentType) {
69882                 var dt = impl.createDocumentType(name, publicId, systemId);
69883                 this.locator && position(this.locator, dt);
69884                 appendElement(this, dt);
69885               }
69886             },
69887
69888             /**
69889              * @see org.xml.sax.ErrorHandler
69890              * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
69891              */
69892             warning: function warning(error) {
69893               console.warn('[xmldom warning]\t' + error, _locator(this.locator));
69894             },
69895             error: function error(_error) {
69896               console.error('[xmldom error]\t' + _error, _locator(this.locator));
69897             },
69898             fatalError: function fatalError(error) {
69899               console.error('[xmldom fatalError]\t' + error, _locator(this.locator));
69900               throw error;
69901             }
69902           };
69903
69904           function _locator(l) {
69905             if (l) {
69906               return '\n@' + (l.systemId || '') + '#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']';
69907             }
69908           }
69909
69910           function _toString(chars, start, length) {
69911             if (typeof chars == 'string') {
69912               return chars.substr(start, length);
69913             } else {
69914               //java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
69915               if (chars.length >= start + length || start) {
69916                 return new java.lang.String(chars, start, length) + '';
69917               }
69918
69919               return chars;
69920             }
69921           }
69922           /*
69923            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
69924            * used method of org.xml.sax.ext.LexicalHandler:
69925            *  #comment(chars, start, length)
69926            *  #startCDATA()
69927            *  #endCDATA()
69928            *  #startDTD(name, publicId, systemId)
69929            *
69930            *
69931            * IGNORED method of org.xml.sax.ext.LexicalHandler:
69932            *  #endDTD()
69933            *  #startEntity(name)
69934            *  #endEntity(name)
69935            *
69936            *
69937            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
69938            * IGNORED method of org.xml.sax.ext.DeclHandler
69939            *    #attributeDecl(eName, aName, type, mode, value)
69940            *  #elementDecl(name, model)
69941            *  #externalEntityDecl(name, publicId, systemId)
69942            *  #internalEntityDecl(name, value)
69943            * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
69944            * IGNORED method of org.xml.sax.EntityResolver2
69945            *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
69946            *  #resolveEntity(publicId, systemId)
69947            *  #getExternalSubset(name, baseURI)
69948            * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
69949            * IGNORED method of org.xml.sax.DTDHandler
69950            *  #notationDecl(name, publicId, systemId) {};
69951            *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
69952            */
69953
69954
69955           "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g, function (key) {
69956             DOMHandler.prototype[key] = function () {
69957               return null;
69958             };
69959           });
69960           /* 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 */
69961
69962           function appendElement(hander, node) {
69963             if (!hander.currentElement) {
69964               hander.doc.appendChild(node);
69965             } else {
69966               hander.currentElement.appendChild(node);
69967             }
69968           } //appendChild and setAttributeNS are preformance key
69969           //if(typeof require == 'function'){
69970
69971
69972           var XMLReader = sax.XMLReader;
69973           var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
69974           exports.XMLSerializer = dom.XMLSerializer;
69975           exports.DOMParser = DOMParser; //}
69976         });
69977
69978         var togeojson = createCommonjsModule(function (module, exports) {
69979           var toGeoJSON = function () {
69980
69981             var removeSpace = /\s*/g,
69982                 trimSpace = /^\s*|\s*$/g,
69983                 splitSpace = /\s+/; // generate a short, numeric hash of a string
69984
69985             function okhash(x) {
69986               if (!x || !x.length) return 0;
69987
69988               for (var i = 0, h = 0; i < x.length; i++) {
69989                 h = (h << 5) - h + x.charCodeAt(i) | 0;
69990               }
69991
69992               return h;
69993             } // all Y children of X
69994
69995
69996             function get(x, y) {
69997               return x.getElementsByTagName(y);
69998             }
69999
70000             function attr(x, y) {
70001               return x.getAttribute(y);
70002             }
70003
70004             function attrf(x, y) {
70005               return parseFloat(attr(x, y));
70006             } // one Y child of X, if any, otherwise null
70007
70008
70009             function get1(x, y) {
70010               var n = get(x, y);
70011               return n.length ? n[0] : null;
70012             } // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
70013
70014
70015             function norm(el) {
70016               if (el.normalize) {
70017                 el.normalize();
70018               }
70019
70020               return el;
70021             } // cast array x into numbers
70022
70023
70024             function numarray(x) {
70025               for (var j = 0, o = []; j < x.length; j++) {
70026                 o[j] = parseFloat(x[j]);
70027               }
70028
70029               return o;
70030             } // get the content of a text node, if any
70031
70032
70033             function nodeVal(x) {
70034               if (x) {
70035                 norm(x);
70036               }
70037
70038               return x && x.textContent || '';
70039             } // get the contents of multiple text nodes, if present
70040
70041
70042             function getMulti(x, ys) {
70043               var o = {},
70044                   n,
70045                   k;
70046
70047               for (k = 0; k < ys.length; k++) {
70048                 n = get1(x, ys[k]);
70049                 if (n) o[ys[k]] = nodeVal(n);
70050               }
70051
70052               return o;
70053             } // add properties of Y to X, overwriting if present in both
70054
70055
70056             function extend(x, y) {
70057               for (var k in y) {
70058                 x[k] = y[k];
70059               }
70060             } // get one coordinate from a coordinate array, if any
70061
70062
70063             function coord1(v) {
70064               return numarray(v.replace(removeSpace, '').split(','));
70065             } // get all coordinates from a coordinate array as [[],[]]
70066
70067
70068             function coord(v) {
70069               var coords = v.replace(trimSpace, '').split(splitSpace),
70070                   o = [];
70071
70072               for (var i = 0; i < coords.length; i++) {
70073                 o.push(coord1(coords[i]));
70074               }
70075
70076               return o;
70077             }
70078
70079             function coordPair(x) {
70080               var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
70081                   ele = get1(x, 'ele'),
70082                   // handle namespaced attribute in browser
70083               heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
70084                   time = get1(x, 'time'),
70085                   e;
70086
70087               if (ele) {
70088                 e = parseFloat(nodeVal(ele));
70089
70090                 if (!isNaN(e)) {
70091                   ll.push(e);
70092                 }
70093               }
70094
70095               return {
70096                 coordinates: ll,
70097                 time: time ? nodeVal(time) : null,
70098                 heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
70099               };
70100             } // create a new feature collection parent object
70101
70102
70103             function fc() {
70104               return {
70105                 type: 'FeatureCollection',
70106                 features: []
70107               };
70108             }
70109
70110             var serializer;
70111
70112             if (typeof XMLSerializer !== 'undefined') {
70113               /* istanbul ignore next */
70114               serializer = new XMLSerializer(); // only require xmldom in a node environment
70115             } else if ( (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && !process.browser) {
70116               serializer = new domParser.XMLSerializer();
70117             }
70118
70119             function xml2str(str) {
70120               // IE9 will create a new XMLSerializer but it'll crash immediately.
70121               // This line is ignored because we don't run coverage tests in IE9
70122
70123               /* istanbul ignore next */
70124               if (str.xml !== undefined) return str.xml;
70125               return serializer.serializeToString(str);
70126             }
70127
70128             var t = {
70129               kml: function kml(doc) {
70130                 var gj = fc(),
70131                     // styleindex keeps track of hashed styles in order to match features
70132                 styleIndex = {},
70133                     styleByHash = {},
70134                     // stylemapindex keeps track of style maps to expose in properties
70135                 styleMapIndex = {},
70136                     // atomic geospatial types supported by KML - MultiGeometry is
70137                 // handled separately
70138                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
70139                     // all root placemarks in the file
70140                 placemarks = get(doc, 'Placemark'),
70141                     styles = get(doc, 'Style'),
70142                     styleMaps = get(doc, 'StyleMap');
70143
70144                 for (var k = 0; k < styles.length; k++) {
70145                   var hash = okhash(xml2str(styles[k])).toString(16);
70146                   styleIndex['#' + attr(styles[k], 'id')] = hash;
70147                   styleByHash[hash] = styles[k];
70148                 }
70149
70150                 for (var l = 0; l < styleMaps.length; l++) {
70151                   styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
70152                   var pairs = get(styleMaps[l], 'Pair');
70153                   var pairsMap = {};
70154
70155                   for (var m = 0; m < pairs.length; m++) {
70156                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
70157                   }
70158
70159                   styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
70160                 }
70161
70162                 for (var j = 0; j < placemarks.length; j++) {
70163                   gj.features = gj.features.concat(getPlacemark(placemarks[j]));
70164                 }
70165
70166                 function kmlColor(v) {
70167                   var color, opacity;
70168                   v = v || '';
70169
70170                   if (v.substr(0, 1) === '#') {
70171                     v = v.substr(1);
70172                   }
70173
70174                   if (v.length === 6 || v.length === 3) {
70175                     color = v;
70176                   }
70177
70178                   if (v.length === 8) {
70179                     opacity = parseInt(v.substr(0, 2), 16) / 255;
70180                     color = '#' + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
70181                   }
70182
70183                   return [color, isNaN(opacity) ? undefined : opacity];
70184                 }
70185
70186                 function gxCoord(v) {
70187                   return numarray(v.split(' '));
70188                 }
70189
70190                 function gxCoords(root) {
70191                   var elems = get(root, 'coord'),
70192                       coords = [],
70193                       times = [];
70194                   if (elems.length === 0) elems = get(root, 'gx:coord');
70195
70196                   for (var i = 0; i < elems.length; i++) {
70197                     coords.push(gxCoord(nodeVal(elems[i])));
70198                   }
70199
70200                   var timeElems = get(root, 'when');
70201
70202                   for (var j = 0; j < timeElems.length; j++) {
70203                     times.push(nodeVal(timeElems[j]));
70204                   }
70205
70206                   return {
70207                     coords: coords,
70208                     times: times
70209                   };
70210                 }
70211
70212                 function getGeometry(root) {
70213                   var geomNode,
70214                       geomNodes,
70215                       i,
70216                       j,
70217                       k,
70218                       geoms = [],
70219                       coordTimes = [];
70220
70221                   if (get1(root, 'MultiGeometry')) {
70222                     return getGeometry(get1(root, 'MultiGeometry'));
70223                   }
70224
70225                   if (get1(root, 'MultiTrack')) {
70226                     return getGeometry(get1(root, 'MultiTrack'));
70227                   }
70228
70229                   if (get1(root, 'gx:MultiTrack')) {
70230                     return getGeometry(get1(root, 'gx:MultiTrack'));
70231                   }
70232
70233                   for (i = 0; i < geotypes.length; i++) {
70234                     geomNodes = get(root, geotypes[i]);
70235
70236                     if (geomNodes) {
70237                       for (j = 0; j < geomNodes.length; j++) {
70238                         geomNode = geomNodes[j];
70239
70240                         if (geotypes[i] === 'Point') {
70241                           geoms.push({
70242                             type: 'Point',
70243                             coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
70244                           });
70245                         } else if (geotypes[i] === 'LineString') {
70246                           geoms.push({
70247                             type: 'LineString',
70248                             coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
70249                           });
70250                         } else if (geotypes[i] === 'Polygon') {
70251                           var rings = get(geomNode, 'LinearRing'),
70252                               coords = [];
70253
70254                           for (k = 0; k < rings.length; k++) {
70255                             coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
70256                           }
70257
70258                           geoms.push({
70259                             type: 'Polygon',
70260                             coordinates: coords
70261                           });
70262                         } else if (geotypes[i] === 'Track' || geotypes[i] === 'gx:Track') {
70263                           var track = gxCoords(geomNode);
70264                           geoms.push({
70265                             type: 'LineString',
70266                             coordinates: track.coords
70267                           });
70268                           if (track.times.length) coordTimes.push(track.times);
70269                         }
70270                       }
70271                     }
70272                   }
70273
70274                   return {
70275                     geoms: geoms,
70276                     coordTimes: coordTimes
70277                   };
70278                 }
70279
70280                 function getPlacemark(root) {
70281                   var geomsAndTimes = getGeometry(root),
70282                       i,
70283                       properties = {},
70284                       name = nodeVal(get1(root, 'name')),
70285                       address = nodeVal(get1(root, 'address')),
70286                       styleUrl = nodeVal(get1(root, 'styleUrl')),
70287                       description = nodeVal(get1(root, 'description')),
70288                       timeSpan = get1(root, 'TimeSpan'),
70289                       timeStamp = get1(root, 'TimeStamp'),
70290                       extendedData = get1(root, 'ExtendedData'),
70291                       lineStyle = get1(root, 'LineStyle'),
70292                       polyStyle = get1(root, 'PolyStyle'),
70293                       visibility = get1(root, 'visibility');
70294                   if (!geomsAndTimes.geoms.length) return [];
70295                   if (name) properties.name = name;
70296                   if (address) properties.address = address;
70297
70298                   if (styleUrl) {
70299                     if (styleUrl[0] !== '#') {
70300                       styleUrl = '#' + styleUrl;
70301                     }
70302
70303                     properties.styleUrl = styleUrl;
70304
70305                     if (styleIndex[styleUrl]) {
70306                       properties.styleHash = styleIndex[styleUrl];
70307                     }
70308
70309                     if (styleMapIndex[styleUrl]) {
70310                       properties.styleMapHash = styleMapIndex[styleUrl];
70311                       properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
70312                     } // Try to populate the lineStyle or polyStyle since we got the style hash
70313
70314
70315                     var style = styleByHash[properties.styleHash];
70316
70317                     if (style) {
70318                       if (!lineStyle) lineStyle = get1(style, 'LineStyle');
70319                       if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
70320                     }
70321                   }
70322
70323                   if (description) properties.description = description;
70324
70325                   if (timeSpan) {
70326                     var begin = nodeVal(get1(timeSpan, 'begin'));
70327                     var end = nodeVal(get1(timeSpan, 'end'));
70328                     properties.timespan = {
70329                       begin: begin,
70330                       end: end
70331                     };
70332                   }
70333
70334                   if (timeStamp) {
70335                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
70336                   }
70337
70338                   if (lineStyle) {
70339                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
70340                         color = linestyles[0],
70341                         opacity = linestyles[1],
70342                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
70343                     if (color) properties.stroke = color;
70344                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
70345                     if (!isNaN(width)) properties['stroke-width'] = width;
70346                   }
70347
70348                   if (polyStyle) {
70349                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
70350                         pcolor = polystyles[0],
70351                         popacity = polystyles[1],
70352                         fill = nodeVal(get1(polyStyle, 'fill')),
70353                         outline = nodeVal(get1(polyStyle, 'outline'));
70354                     if (pcolor) properties.fill = pcolor;
70355                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
70356                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
70357                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
70358                   }
70359
70360                   if (extendedData) {
70361                     var datas = get(extendedData, 'Data'),
70362                         simpleDatas = get(extendedData, 'SimpleData');
70363
70364                     for (i = 0; i < datas.length; i++) {
70365                       properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
70366                     }
70367
70368                     for (i = 0; i < simpleDatas.length; i++) {
70369                       properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
70370                     }
70371                   }
70372
70373                   if (visibility) {
70374                     properties.visibility = nodeVal(visibility);
70375                   }
70376
70377                   if (geomsAndTimes.coordTimes.length) {
70378                     properties.coordTimes = geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
70379                   }
70380
70381                   var feature = {
70382                     type: 'Feature',
70383                     geometry: geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
70384                       type: 'GeometryCollection',
70385                       geometries: geomsAndTimes.geoms
70386                     },
70387                     properties: properties
70388                   };
70389                   if (attr(root, 'id')) feature.id = attr(root, 'id');
70390                   return [feature];
70391                 }
70392
70393                 return gj;
70394               },
70395               gpx: function gpx(doc) {
70396                 var i,
70397                     tracks = get(doc, 'trk'),
70398                     routes = get(doc, 'rte'),
70399                     waypoints = get(doc, 'wpt'),
70400                     // a feature collection
70401                 gj = fc(),
70402                     feature;
70403
70404                 for (i = 0; i < tracks.length; i++) {
70405                   feature = getTrack(tracks[i]);
70406                   if (feature) gj.features.push(feature);
70407                 }
70408
70409                 for (i = 0; i < routes.length; i++) {
70410                   feature = getRoute(routes[i]);
70411                   if (feature) gj.features.push(feature);
70412                 }
70413
70414                 for (i = 0; i < waypoints.length; i++) {
70415                   gj.features.push(getPoint(waypoints[i]));
70416                 }
70417
70418                 function getPoints(node, pointname) {
70419                   var pts = get(node, pointname),
70420                       line = [],
70421                       times = [],
70422                       heartRates = [],
70423                       l = pts.length;
70424                   if (l < 2) return {}; // Invalid line in GeoJSON
70425
70426                   for (var i = 0; i < l; i++) {
70427                     var c = coordPair(pts[i]);
70428                     line.push(c.coordinates);
70429                     if (c.time) times.push(c.time);
70430                     if (c.heartRate) heartRates.push(c.heartRate);
70431                   }
70432
70433                   return {
70434                     line: line,
70435                     times: times,
70436                     heartRates: heartRates
70437                   };
70438                 }
70439
70440                 function getTrack(node) {
70441                   var segments = get(node, 'trkseg'),
70442                       track = [],
70443                       times = [],
70444                       heartRates = [],
70445                       line;
70446
70447                   for (var i = 0; i < segments.length; i++) {
70448                     line = getPoints(segments[i], 'trkpt');
70449
70450                     if (line) {
70451                       if (line.line) track.push(line.line);
70452                       if (line.times && line.times.length) times.push(line.times);
70453                       if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
70454                     }
70455                   }
70456
70457                   if (track.length === 0) return;
70458                   var properties = getProperties(node);
70459                   extend(properties, getLineStyle(get1(node, 'extensions')));
70460                   if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
70461                   if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
70462                   return {
70463                     type: 'Feature',
70464                     properties: properties,
70465                     geometry: {
70466                       type: track.length === 1 ? 'LineString' : 'MultiLineString',
70467                       coordinates: track.length === 1 ? track[0] : track
70468                     }
70469                   };
70470                 }
70471
70472                 function getRoute(node) {
70473                   var line = getPoints(node, 'rtept');
70474                   if (!line.line) return;
70475                   var prop = getProperties(node);
70476                   extend(prop, getLineStyle(get1(node, 'extensions')));
70477                   var routeObj = {
70478                     type: 'Feature',
70479                     properties: prop,
70480                     geometry: {
70481                       type: 'LineString',
70482                       coordinates: line.line
70483                     }
70484                   };
70485                   return routeObj;
70486                 }
70487
70488                 function getPoint(node) {
70489                   var prop = getProperties(node);
70490                   extend(prop, getMulti(node, ['sym']));
70491                   return {
70492                     type: 'Feature',
70493                     properties: prop,
70494                     geometry: {
70495                       type: 'Point',
70496                       coordinates: coordPair(node).coordinates
70497                     }
70498                   };
70499                 }
70500
70501                 function getLineStyle(extensions) {
70502                   var style = {};
70503
70504                   if (extensions) {
70505                     var lineStyle = get1(extensions, 'line');
70506
70507                     if (lineStyle) {
70508                       var color = nodeVal(get1(lineStyle, 'color')),
70509                           opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
70510                           width = parseFloat(nodeVal(get1(lineStyle, 'width')));
70511                       if (color) style.stroke = color;
70512                       if (!isNaN(opacity)) style['stroke-opacity'] = opacity; // GPX width is in mm, convert to px with 96 px per inch
70513
70514                       if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
70515                     }
70516                   }
70517
70518                   return style;
70519                 }
70520
70521                 function getProperties(node) {
70522                   var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
70523                       links = get(node, 'link');
70524                   if (links.length) prop.links = [];
70525
70526                   for (var i = 0, link; i < links.length; i++) {
70527                     link = {
70528                       href: attr(links[i], 'href')
70529                     };
70530                     extend(link, getMulti(links[i], ['text', 'type']));
70531                     prop.links.push(link);
70532                   }
70533
70534                   return prop;
70535                 }
70536
70537                 return gj;
70538               }
70539             };
70540             return t;
70541           }();
70542
70543           module.exports = toGeoJSON;
70544         });
70545
70546         var _initialized = false;
70547         var _enabled = false;
70548
70549         var _geojson;
70550
70551         function svgData(projection, context, dispatch) {
70552           var throttledRedraw = throttle(function () {
70553             dispatch.call('change');
70554           }, 1000);
70555
70556           var _showLabels = true;
70557           var detected = utilDetect();
70558           var layer = select(null);
70559
70560           var _vtService;
70561
70562           var _fileList;
70563
70564           var _template;
70565
70566           var _src;
70567
70568           function init() {
70569             if (_initialized) return; // run once
70570
70571             _geojson = {};
70572             _enabled = true;
70573
70574             function over(d3_event) {
70575               d3_event.stopPropagation();
70576               d3_event.preventDefault();
70577               d3_event.dataTransfer.dropEffect = 'copy';
70578             }
70579
70580             context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
70581               d3_event.stopPropagation();
70582               d3_event.preventDefault();
70583               if (!detected.filedrop) return;
70584               drawData.fileList(d3_event.dataTransfer.files);
70585             }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
70586             _initialized = true;
70587           }
70588
70589           function getService() {
70590             if (services.vectorTile && !_vtService) {
70591               _vtService = services.vectorTile;
70592
70593               _vtService.event.on('loadedData', throttledRedraw);
70594             } else if (!services.vectorTile && _vtService) {
70595               _vtService = null;
70596             }
70597
70598             return _vtService;
70599           }
70600
70601           function showLayer() {
70602             layerOn();
70603             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
70604               dispatch.call('change');
70605             });
70606           }
70607
70608           function hideLayer() {
70609             throttledRedraw.cancel();
70610             layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
70611           }
70612
70613           function layerOn() {
70614             layer.style('display', 'block');
70615           }
70616
70617           function layerOff() {
70618             layer.selectAll('.viewfield-group').remove();
70619             layer.style('display', 'none');
70620           } // ensure that all geojson features in a collection have IDs
70621
70622
70623           function ensureIDs(gj) {
70624             if (!gj) return null;
70625
70626             if (gj.type === 'FeatureCollection') {
70627               for (var i = 0; i < gj.features.length; i++) {
70628                 ensureFeatureID(gj.features[i]);
70629               }
70630             } else {
70631               ensureFeatureID(gj);
70632             }
70633
70634             return gj;
70635           } // ensure that each single Feature object has a unique ID
70636
70637
70638           function ensureFeatureID(feature) {
70639             if (!feature) return;
70640             feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
70641             return feature;
70642           } // Prefer an array of Features instead of a FeatureCollection
70643
70644
70645           function getFeatures(gj) {
70646             if (!gj) return [];
70647
70648             if (gj.type === 'FeatureCollection') {
70649               return gj.features;
70650             } else {
70651               return [gj];
70652             }
70653           }
70654
70655           function featureKey(d) {
70656             return d.__featurehash__;
70657           }
70658
70659           function isPolygon(d) {
70660             return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
70661           }
70662
70663           function clipPathID(d) {
70664             return 'ideditor-data-' + d.__featurehash__ + '-clippath';
70665           }
70666
70667           function featureClasses(d) {
70668             return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
70669           }
70670
70671           function drawData(selection) {
70672             var vtService = getService();
70673             var getPath = svgPath(projection).geojson;
70674             var getAreaPath = svgPath(projection, null, true).geojson;
70675             var hasData = drawData.hasData();
70676             layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
70677             layer.exit().remove();
70678             layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
70679             var surface = context.surface();
70680             if (!surface || surface.empty()) return; // not ready to draw yet, starting up
70681             // Gather data
70682
70683             var geoData, polygonData;
70684
70685             if (_template && vtService) {
70686               // fetch data from vector tile service
70687               var sourceID = _template;
70688               vtService.loadTiles(sourceID, _template, projection);
70689               geoData = vtService.data(sourceID, projection);
70690             } else {
70691               geoData = getFeatures(_geojson);
70692             }
70693
70694             geoData = geoData.filter(getPath);
70695             polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
70696
70697             var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
70698             clipPaths.exit().remove();
70699             var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
70700             clipPathsEnter.append('path');
70701             clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
70702
70703             var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
70704             datagroups = datagroups.enter().append('g').attr('class', function (d) {
70705               return 'datagroup datagroup-' + d;
70706             }).merge(datagroups); // Draw paths
70707
70708             var pathData = {
70709               fill: polygonData,
70710               shadow: geoData,
70711               stroke: geoData
70712             };
70713             var paths = datagroups.selectAll('path').data(function (layer) {
70714               return pathData[layer];
70715             }, featureKey); // exit
70716
70717             paths.exit().remove(); // enter/update
70718
70719             paths = paths.enter().append('path').attr('class', function (d) {
70720               var datagroup = this.parentNode.__data__;
70721               return 'pathdata ' + datagroup + ' ' + featureClasses(d);
70722             }).attr('clip-path', function (d) {
70723               var datagroup = this.parentNode.__data__;
70724               return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
70725             }).merge(paths).attr('d', function (d) {
70726               var datagroup = this.parentNode.__data__;
70727               return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
70728             }); // Draw labels
70729
70730             layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
70731
70732             function drawLabels(selection, textClass, data) {
70733               var labelPath = d3_geoPath(projection);
70734               var labelData = data.filter(function (d) {
70735                 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
70736               });
70737               var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
70738
70739               labels.exit().remove(); // enter/update
70740
70741               labels = labels.enter().append('text').attr('class', function (d) {
70742                 return textClass + ' ' + featureClasses(d);
70743               }).merge(labels).text(function (d) {
70744                 return d.properties.desc || d.properties.name;
70745               }).attr('x', function (d) {
70746                 var centroid = labelPath.centroid(d);
70747                 return centroid[0] + 11;
70748               }).attr('y', function (d) {
70749                 var centroid = labelPath.centroid(d);
70750                 return centroid[1];
70751               });
70752             }
70753           }
70754
70755           function getExtension(fileName) {
70756             if (!fileName) return;
70757             var re = /\.(gpx|kml|(geo)?json)$/i;
70758             var match = fileName.toLowerCase().match(re);
70759             return match && match.length && match[0];
70760           }
70761
70762           function xmlToDom(textdata) {
70763             return new DOMParser().parseFromString(textdata, 'text/xml');
70764           }
70765
70766           drawData.setFile = function (extension, data) {
70767             _template = null;
70768             _fileList = null;
70769             _geojson = null;
70770             _src = null;
70771             var gj;
70772
70773             switch (extension) {
70774               case '.gpx':
70775                 gj = togeojson.gpx(xmlToDom(data));
70776                 break;
70777
70778               case '.kml':
70779                 gj = togeojson.kml(xmlToDom(data));
70780                 break;
70781
70782               case '.geojson':
70783               case '.json':
70784                 gj = JSON.parse(data);
70785                 break;
70786             }
70787
70788             gj = gj || {};
70789
70790             if (Object.keys(gj).length) {
70791               _geojson = ensureIDs(gj);
70792               _src = extension + ' data file';
70793               this.fitZoom();
70794             }
70795
70796             dispatch.call('change');
70797             return this;
70798           };
70799
70800           drawData.showLabels = function (val) {
70801             if (!arguments.length) return _showLabels;
70802             _showLabels = val;
70803             return this;
70804           };
70805
70806           drawData.enabled = function (val) {
70807             if (!arguments.length) return _enabled;
70808             _enabled = val;
70809
70810             if (_enabled) {
70811               showLayer();
70812             } else {
70813               hideLayer();
70814             }
70815
70816             dispatch.call('change');
70817             return this;
70818           };
70819
70820           drawData.hasData = function () {
70821             var gj = _geojson || {};
70822             return !!(_template || Object.keys(gj).length);
70823           };
70824
70825           drawData.template = function (val, src) {
70826             if (!arguments.length) return _template; // test source against OSM imagery blocklists..
70827
70828             var osm = context.connection();
70829
70830             if (osm) {
70831               var blocklists = osm.imageryBlocklists();
70832               var fail = false;
70833               var tested = 0;
70834               var regex;
70835
70836               for (var i = 0; i < blocklists.length; i++) {
70837                 regex = blocklists[i];
70838                 fail = regex.test(val);
70839                 tested++;
70840                 if (fail) break;
70841               } // ensure at least one test was run.
70842
70843
70844               if (!tested) {
70845                 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
70846                 fail = regex.test(val);
70847               }
70848             }
70849
70850             _template = val;
70851             _fileList = null;
70852             _geojson = null; // strip off the querystring/hash from the template,
70853             // it often includes the access token
70854
70855             _src = src || 'vectortile:' + val.split(/[?#]/)[0];
70856             dispatch.call('change');
70857             return this;
70858           };
70859
70860           drawData.geojson = function (gj, src) {
70861             if (!arguments.length) return _geojson;
70862             _template = null;
70863             _fileList = null;
70864             _geojson = null;
70865             _src = null;
70866             gj = gj || {};
70867
70868             if (Object.keys(gj).length) {
70869               _geojson = ensureIDs(gj);
70870               _src = src || 'unknown.geojson';
70871             }
70872
70873             dispatch.call('change');
70874             return this;
70875           };
70876
70877           drawData.fileList = function (fileList) {
70878             if (!arguments.length) return _fileList;
70879             _template = null;
70880             _fileList = fileList;
70881             _geojson = null;
70882             _src = null;
70883             if (!fileList || !fileList.length) return this;
70884             var f = fileList[0];
70885             var extension = getExtension(f.name);
70886             var reader = new FileReader();
70887
70888             reader.onload = function () {
70889               return function (e) {
70890                 drawData.setFile(extension, e.target.result);
70891               };
70892             }();
70893
70894             reader.readAsText(f);
70895             return this;
70896           };
70897
70898           drawData.url = function (url, defaultExtension) {
70899             _template = null;
70900             _fileList = null;
70901             _geojson = null;
70902             _src = null; // strip off any querystring/hash from the url before checking extension
70903
70904             var testUrl = url.split(/[?#]/)[0];
70905             var extension = getExtension(testUrl) || defaultExtension;
70906
70907             if (extension) {
70908               _template = null;
70909               d3_text(url).then(function (data) {
70910                 drawData.setFile(extension, data);
70911               })["catch"](function () {
70912                 /* ignore */
70913               });
70914             } else {
70915               drawData.template(url);
70916             }
70917
70918             return this;
70919           };
70920
70921           drawData.getSrc = function () {
70922             return _src || '';
70923           };
70924
70925           drawData.fitZoom = function () {
70926             var features = getFeatures(_geojson);
70927             if (!features.length) return;
70928             var map = context.map();
70929             var viewport = map.trimmedExtent().polygon();
70930             var coords = features.reduce(function (coords, feature) {
70931               var geom = feature.geometry;
70932               if (!geom) return coords;
70933               var c = geom.coordinates;
70934               /* eslint-disable no-fallthrough */
70935
70936               switch (geom.type) {
70937                 case 'Point':
70938                   c = [c];
70939
70940                 case 'MultiPoint':
70941                 case 'LineString':
70942                   break;
70943
70944                 case 'MultiPolygon':
70945                   c = utilArrayFlatten(c);
70946
70947                 case 'Polygon':
70948                 case 'MultiLineString':
70949                   c = utilArrayFlatten(c);
70950                   break;
70951               }
70952               /* eslint-enable no-fallthrough */
70953
70954
70955               return utilArrayUnion(coords, c);
70956             }, []);
70957
70958             if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
70959               var extent = geoExtent(d3_geoBounds({
70960                 type: 'LineString',
70961                 coordinates: coords
70962               }));
70963               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
70964             }
70965
70966             return this;
70967           };
70968
70969           init();
70970           return drawData;
70971         }
70972
70973         function svgDebug(projection, context) {
70974           function drawDebug(selection) {
70975             var showTile = context.getDebug('tile');
70976             var showCollision = context.getDebug('collision');
70977             var showImagery = context.getDebug('imagery');
70978             var showTouchTargets = context.getDebug('target');
70979             var showDownloaded = context.getDebug('downloaded');
70980             var debugData = [];
70981
70982             if (showTile) {
70983               debugData.push({
70984                 "class": 'red',
70985                 label: 'tile'
70986               });
70987             }
70988
70989             if (showCollision) {
70990               debugData.push({
70991                 "class": 'yellow',
70992                 label: 'collision'
70993               });
70994             }
70995
70996             if (showImagery) {
70997               debugData.push({
70998                 "class": 'orange',
70999                 label: 'imagery'
71000               });
71001             }
71002
71003             if (showTouchTargets) {
71004               debugData.push({
71005                 "class": 'pink',
71006                 label: 'touchTargets'
71007               });
71008             }
71009
71010             if (showDownloaded) {
71011               debugData.push({
71012                 "class": 'purple',
71013                 label: 'downloaded'
71014               });
71015             }
71016
71017             var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
71018             legend.exit().remove();
71019             legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
71020             var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
71021               return d.label;
71022             });
71023             legendItems.exit().remove();
71024             legendItems.enter().append('span').attr('class', function (d) {
71025               return "debug-legend-item ".concat(d["class"]);
71026             }).text(function (d) {
71027               return d.label;
71028             });
71029             var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
71030             layer.exit().remove();
71031             layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
71032
71033             var extent = context.map().extent();
71034             _mainFileFetcher.get('imagery').then(function (d) {
71035               var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
71036               var features = hits.map(function (d) {
71037                 return d.features[d.id];
71038               });
71039               var imagery = layer.selectAll('path.debug-imagery').data(features);
71040               imagery.exit().remove();
71041               imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
71042             })["catch"](function () {
71043               /* ignore */
71044             }); // downloaded
71045
71046             var osm = context.connection();
71047             var dataDownloaded = [];
71048
71049             if (osm && showDownloaded) {
71050               var rtree = osm.caches('get').tile.rtree;
71051               dataDownloaded = rtree.all().map(function (bbox) {
71052                 return {
71053                   type: 'Feature',
71054                   properties: {
71055                     id: bbox.id
71056                   },
71057                   geometry: {
71058                     type: 'Polygon',
71059                     coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
71060                   }
71061                 };
71062               });
71063             }
71064
71065             var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
71066             downloaded.exit().remove();
71067             downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
71068
71069             layer.selectAll('path').attr('d', svgPath(projection).geojson);
71070           } // This looks strange because `enabled` methods on other layers are
71071           // chainable getter/setters, and this one is just a getter.
71072
71073
71074           drawDebug.enabled = function () {
71075             if (!arguments.length) {
71076               return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
71077             } else {
71078               return this;
71079             }
71080           };
71081
71082           return drawDebug;
71083         }
71084
71085         /*
71086             A standalone SVG element that contains only a `defs` sub-element. To be
71087             used once globally, since defs IDs must be unique within a document.
71088         */
71089
71090         function svgDefs(context) {
71091           var _defsSelection = select(null);
71092
71093           var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
71094
71095           function drawDefs(selection) {
71096             _defsSelection = selection.append('defs'); // add markers
71097
71098             _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
71099             // (they can't inherit it from the line they're attached to),
71100             // so we need to manually define markers for each color of tag
71101             // (also, it's slightly nicer if we can control the
71102             // positioning for different tags)
71103
71104
71105             function addSidedMarker(name, color, offset) {
71106               _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);
71107             }
71108
71109             addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
71110             // the water side, so let's color them blue (with a gap) to
71111             // give a stronger indication
71112
71113             addSidedMarker('coastline', '#77dede', 1);
71114             addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
71115             // from the line visually suits that
71116
71117             addSidedMarker('barrier', '#ddd', 1);
71118             addSidedMarker('man_made', '#fff', 0);
71119
71120             _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');
71121
71122             _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
71123
71124
71125             var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
71126             ['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) {
71127               return 'ideditor-pattern-' + d[0];
71128             }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
71129
71130             patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
71131               return 'pattern-color-' + d[0];
71132             });
71133             patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
71134               return context.imagePath('pattern/' + d[1] + '.png');
71135             }); // add clip paths
71136
71137             _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
71138               return 'ideditor-clip-square-' + d;
71139             }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
71140               return d;
71141             }).attr('height', function (d) {
71142               return d;
71143             }); // add symbol spritesheets
71144
71145
71146             addSprites(_spritesheetIds, true);
71147           }
71148
71149           function addSprites(ids, overrideColors) {
71150             _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
71151
71152             var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
71153
71154             spritesheets.enter().append('g').attr('class', function (d) {
71155               return 'spritesheet spritesheet-' + d;
71156             }).each(function (d) {
71157               var url = context.imagePath(d + '.svg');
71158               var node = select(this).node();
71159               svg(url).then(function (svg) {
71160                 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
71161
71162                 if (overrideColors && d !== 'iD-sprite') {
71163                   // allow icon colors to be overridden..
71164                   select(node).selectAll('path').attr('fill', 'currentColor');
71165                 }
71166               })["catch"](function () {
71167                 /* ignore */
71168               });
71169             });
71170             spritesheets.exit().remove();
71171           }
71172
71173           drawDefs.addSprites = addSprites;
71174           return drawDefs;
71175         }
71176
71177         var _layerEnabled = false;
71178
71179         var _qaService;
71180
71181         function svgKeepRight(projection, context, dispatch) {
71182           var throttledRedraw = throttle(function () {
71183             return dispatch.call('change');
71184           }, 1000);
71185
71186           var minZoom = 12;
71187           var touchLayer = select(null);
71188           var drawLayer = select(null);
71189           var layerVisible = false;
71190
71191           function markerPath(selection, klass) {
71192             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');
71193           } // Loosely-coupled keepRight service for fetching issues.
71194
71195
71196           function getService() {
71197             if (services.keepRight && !_qaService) {
71198               _qaService = services.keepRight;
71199
71200               _qaService.on('loaded', throttledRedraw);
71201             } else if (!services.keepRight && _qaService) {
71202               _qaService = null;
71203             }
71204
71205             return _qaService;
71206           } // Show the markers
71207
71208
71209           function editOn() {
71210             if (!layerVisible) {
71211               layerVisible = true;
71212               drawLayer.style('display', 'block');
71213             }
71214           } // Immediately remove the markers and their touch targets
71215
71216
71217           function editOff() {
71218             if (layerVisible) {
71219               layerVisible = false;
71220               drawLayer.style('display', 'none');
71221               drawLayer.selectAll('.qaItem.keepRight').remove();
71222               touchLayer.selectAll('.qaItem.keepRight').remove();
71223             }
71224           } // Enable the layer.  This shows the markers and transitions them to visible.
71225
71226
71227           function layerOn() {
71228             editOn();
71229             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
71230               return dispatch.call('change');
71231             });
71232           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
71233
71234
71235           function layerOff() {
71236             throttledRedraw.cancel();
71237             drawLayer.interrupt();
71238             touchLayer.selectAll('.qaItem.keepRight').remove();
71239             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
71240               editOff();
71241               dispatch.call('change');
71242             });
71243           } // Update the issue markers
71244
71245
71246           function updateMarkers() {
71247             if (!layerVisible || !_layerEnabled) return;
71248             var service = getService();
71249             var selectedID = context.selectedErrorID();
71250             var data = service ? service.getItems(projection) : [];
71251             var getTransform = svgPointTransform(projection); // Draw markers..
71252
71253             var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
71254               return d.id;
71255             }); // exit
71256
71257             markers.exit().remove(); // enter
71258
71259             var markersEnter = markers.enter().append('g').attr('class', function (d) {
71260               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
71261             });
71262             markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
71263             markersEnter.append('path').call(markerPath, 'shadow');
71264             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
71265
71266             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
71267               return d.id === selectedID;
71268             }).attr('transform', getTransform); // Draw targets..
71269
71270             if (touchLayer.empty()) return;
71271             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
71272             var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
71273               return d.id;
71274             }); // exit
71275
71276             targets.exit().remove(); // enter/update
71277
71278             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
71279               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
71280             }).attr('transform', getTransform);
71281
71282             function sortY(a, b) {
71283               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];
71284             }
71285           } // Draw the keepRight layer and schedule loading issues and updating markers.
71286
71287
71288           function drawKeepRight(selection) {
71289             var service = getService();
71290             var surface = context.surface();
71291
71292             if (surface && !surface.empty()) {
71293               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
71294             }
71295
71296             drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
71297             drawLayer.exit().remove();
71298             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
71299
71300             if (_layerEnabled) {
71301               if (service && ~~context.map().zoom() >= minZoom) {
71302                 editOn();
71303                 service.loadIssues(projection);
71304                 updateMarkers();
71305               } else {
71306                 editOff();
71307               }
71308             }
71309           } // Toggles the layer on and off
71310
71311
71312           drawKeepRight.enabled = function (val) {
71313             if (!arguments.length) return _layerEnabled;
71314             _layerEnabled = val;
71315
71316             if (_layerEnabled) {
71317               layerOn();
71318             } else {
71319               layerOff();
71320
71321               if (context.selectedErrorID()) {
71322                 context.enter(modeBrowse(context));
71323               }
71324             }
71325
71326             dispatch.call('change');
71327             return this;
71328           };
71329
71330           drawKeepRight.supported = function () {
71331             return !!getService();
71332           };
71333
71334           return drawKeepRight;
71335         }
71336
71337         function svgGeolocate(projection) {
71338           var layer = select(null);
71339
71340           var _position;
71341
71342           function init() {
71343             if (svgGeolocate.initialized) return; // run once
71344
71345             svgGeolocate.enabled = false;
71346             svgGeolocate.initialized = true;
71347           }
71348
71349           function showLayer() {
71350             layer.style('display', 'block');
71351           }
71352
71353           function hideLayer() {
71354             layer.transition().duration(250).style('opacity', 0);
71355           }
71356
71357           function layerOn() {
71358             layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
71359           }
71360
71361           function layerOff() {
71362             layer.style('display', 'none');
71363           }
71364
71365           function transform(d) {
71366             return svgPointTransform(projection)(d);
71367           }
71368
71369           function accuracy(accuracy, loc) {
71370             // converts accuracy to pixels...
71371             var degreesRadius = geoMetersToLat(accuracy),
71372                 tangentLoc = [loc[0], loc[1] + degreesRadius],
71373                 projectedTangent = projection(tangentLoc),
71374                 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
71375
71376             return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
71377           }
71378
71379           function update() {
71380             var geolocation = {
71381               loc: [_position.coords.longitude, _position.coords.latitude]
71382             };
71383             var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
71384             groups.exit().remove();
71385             var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
71386             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');
71387             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');
71388             groups.merge(pointsEnter).attr('transform', transform);
71389             layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
71390           }
71391
71392           function drawLocation(selection) {
71393             var enabled = svgGeolocate.enabled;
71394             layer = selection.selectAll('.layer-geolocate').data([0]);
71395             layer.exit().remove();
71396             var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
71397             layerEnter.append('g').attr('class', 'geolocations');
71398             layer = layerEnter.merge(layer);
71399
71400             if (enabled) {
71401               update();
71402             } else {
71403               layerOff();
71404             }
71405           }
71406
71407           drawLocation.enabled = function (position, enabled) {
71408             if (!arguments.length) return svgGeolocate.enabled;
71409             _position = position;
71410             svgGeolocate.enabled = enabled;
71411
71412             if (svgGeolocate.enabled) {
71413               showLayer();
71414               layerOn();
71415             } else {
71416               hideLayer();
71417             }
71418
71419             return this;
71420           };
71421
71422           init();
71423           return drawLocation;
71424         }
71425
71426         function svgLabels(projection, context) {
71427           var path = d3_geoPath(projection);
71428           var detected = utilDetect();
71429           var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
71430
71431           var _rdrawn = new RBush();
71432
71433           var _rskipped = new RBush();
71434
71435           var _textWidthCache = {};
71436           var _entitybboxes = {}; // Listed from highest to lowest priority
71437
71438           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]];
71439
71440           function shouldSkipIcon(preset) {
71441             var noIcons = ['building', 'landuse', 'natural'];
71442             return noIcons.some(function (s) {
71443               return preset.id.indexOf(s) >= 0;
71444             });
71445           }
71446
71447           function get(array, prop) {
71448             return function (d, i) {
71449               return array[i][prop];
71450             };
71451           }
71452
71453           function textWidth(text, size, elem) {
71454             var c = _textWidthCache[size];
71455             if (!c) c = _textWidthCache[size] = {};
71456
71457             if (c[text]) {
71458               return c[text];
71459             } else if (elem) {
71460               c[text] = elem.getComputedTextLength();
71461               return c[text];
71462             } else {
71463               var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
71464
71465               if (str === null) {
71466                 return size / 3 * 2 * text.length;
71467               } else {
71468                 return size / 3 * (2 * text.length + str.length);
71469               }
71470             }
71471           }
71472
71473           function drawLinePaths(selection, entities, filter, classes, labels) {
71474             var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
71475
71476             paths.exit().remove(); // enter/update
71477
71478             paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
71479               return 'ideditor-labelpath-' + d.id;
71480             }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
71481           }
71482
71483           function drawLineLabels(selection, entities, filter, classes, labels) {
71484             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71485
71486             texts.exit().remove(); // enter
71487
71488             texts.enter().append('text').attr('class', function (d, i) {
71489               return classes + ' ' + labels[i].classes + ' ' + d.id;
71490             }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
71491
71492             selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
71493               return '#ideditor-labelpath-' + d.id;
71494             }).text(utilDisplayNameForPath);
71495           }
71496
71497           function drawPointLabels(selection, entities, filter, classes, labels) {
71498             var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71499
71500             texts.exit().remove(); // enter/update
71501
71502             texts.enter().append('text').attr('class', function (d, i) {
71503               return classes + ' ' + labels[i].classes + ' ' + d.id;
71504             }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
71505               textWidth(utilDisplayName(d), labels[i].height, this);
71506             });
71507           }
71508
71509           function drawAreaLabels(selection, entities, filter, classes, labels) {
71510             entities = entities.filter(hasText);
71511             labels = labels.filter(hasText);
71512             drawPointLabels(selection, entities, filter, classes, labels);
71513
71514             function hasText(d, i) {
71515               return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
71516             }
71517           }
71518
71519           function drawAreaIcons(selection, entities, filter, classes, labels) {
71520             var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
71521
71522             icons.exit().remove(); // enter/update
71523
71524             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) {
71525               var preset = _mainPresetIndex.match(d, context.graph());
71526               var picon = preset && preset.icon;
71527
71528               if (!picon) {
71529                 return '';
71530               } else {
71531                 var isMaki = /^maki-/.test(picon);
71532                 return '#' + picon + (isMaki ? '-15' : '');
71533               }
71534             });
71535           }
71536
71537           function drawCollisionBoxes(selection, rtree, which) {
71538             var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
71539             var gj = [];
71540
71541             if (context.getDebug('collision')) {
71542               gj = rtree.all().map(function (d) {
71543                 return {
71544                   type: 'Polygon',
71545                   coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
71546                 };
71547               });
71548             }
71549
71550             var boxes = selection.selectAll('.' + which).data(gj); // exit
71551
71552             boxes.exit().remove(); // enter/update
71553
71554             boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
71555           }
71556
71557           function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
71558             var wireframe = context.surface().classed('fill-wireframe');
71559             var zoom = geoScaleToZoom(projection.scale());
71560             var labelable = [];
71561             var renderNodeAs = {};
71562             var i, j, k, entity, geometry;
71563
71564             for (i = 0; i < labelStack.length; i++) {
71565               labelable.push([]);
71566             }
71567
71568             if (fullRedraw) {
71569               _rdrawn.clear();
71570
71571               _rskipped.clear();
71572
71573               _entitybboxes = {};
71574             } else {
71575               for (i = 0; i < entities.length; i++) {
71576                 entity = entities[i];
71577                 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
71578
71579                 for (j = 0; j < toRemove.length; j++) {
71580                   _rdrawn.remove(toRemove[j]);
71581
71582                   _rskipped.remove(toRemove[j]);
71583                 }
71584               }
71585             } // Loop through all the entities to do some preprocessing
71586
71587
71588             for (i = 0; i < entities.length; i++) {
71589               entity = entities[i];
71590               geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
71591
71592               if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
71593                 var hasDirections = entity.directions(graph, projection).length;
71594                 var markerPadding;
71595
71596                 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
71597                   renderNodeAs[entity.id] = 'point';
71598                   markerPadding = 20; // extra y for marker height
71599                 } else {
71600                   renderNodeAs[entity.id] = 'vertex';
71601                   markerPadding = 0;
71602                 }
71603
71604                 var coord = projection(entity.loc);
71605                 var nodePadding = 10;
71606                 var bbox = {
71607                   minX: coord[0] - nodePadding,
71608                   minY: coord[1] - nodePadding - markerPadding,
71609                   maxX: coord[0] + nodePadding,
71610                   maxY: coord[1] + nodePadding
71611                 };
71612                 doInsert(bbox, entity.id + 'P');
71613               } // From here on, treat vertices like points
71614
71615
71616               if (geometry === 'vertex') {
71617                 geometry = 'point';
71618               } // Determine which entities are label-able
71619
71620
71621               var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
71622               var icon = preset && !shouldSkipIcon(preset) && preset.icon;
71623               if (!icon && !utilDisplayName(entity)) continue;
71624
71625               for (k = 0; k < labelStack.length; k++) {
71626                 var matchGeom = labelStack[k][0];
71627                 var matchKey = labelStack[k][1];
71628                 var matchVal = labelStack[k][2];
71629                 var hasVal = entity.tags[matchKey];
71630
71631                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
71632                   labelable[k].push(entity);
71633                   break;
71634                 }
71635               }
71636             }
71637
71638             var positions = {
71639               point: [],
71640               line: [],
71641               area: []
71642             };
71643             var labelled = {
71644               point: [],
71645               line: [],
71646               area: []
71647             }; // Try and find a valid label for labellable entities
71648
71649             for (k = 0; k < labelable.length; k++) {
71650               var fontSize = labelStack[k][3];
71651
71652               for (i = 0; i < labelable[k].length; i++) {
71653                 entity = labelable[k][i];
71654                 geometry = entity.geometry(graph);
71655                 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
71656                 var name = getName(entity);
71657                 var width = name && textWidth(name, fontSize);
71658                 var p = null;
71659
71660                 if (geometry === 'point' || geometry === 'vertex') {
71661                   // no point or vertex labels in wireframe mode
71662                   // no vertex labels at low zooms (vertices have no icons)
71663                   if (wireframe) continue;
71664                   var renderAs = renderNodeAs[entity.id];
71665                   if (renderAs === 'vertex' && zoom < 17) continue;
71666                   p = getPointLabel(entity, width, fontSize, renderAs);
71667                 } else if (geometry === 'line') {
71668                   p = getLineLabel(entity, width, fontSize);
71669                 } else if (geometry === 'area') {
71670                   p = getAreaLabel(entity, width, fontSize);
71671                 }
71672
71673                 if (p) {
71674                   if (geometry === 'vertex') {
71675                     geometry = 'point';
71676                   } // treat vertex like point
71677
71678
71679                   p.classes = geometry + ' tag-' + labelStack[k][1];
71680                   positions[geometry].push(p);
71681                   labelled[geometry].push(entity);
71682                 }
71683               }
71684             }
71685
71686             function isInterestingVertex(entity) {
71687               var selectedIDs = context.selectedIDs();
71688               return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
71689                 return selectedIDs.indexOf(parent.id) !== -1;
71690               });
71691             }
71692
71693             function getPointLabel(entity, width, height, geometry) {
71694               var y = geometry === 'point' ? -12 : 0;
71695               var pointOffsets = {
71696                 ltr: [15, y, 'start'],
71697                 rtl: [-15, y, 'end']
71698               };
71699               var textDirection = _mainLocalizer.textDirection();
71700               var coord = projection(entity.loc);
71701               var textPadding = 2;
71702               var offset = pointOffsets[textDirection];
71703               var p = {
71704                 height: height,
71705                 width: width,
71706                 x: coord[0] + offset[0],
71707                 y: coord[1] + offset[1],
71708                 textAnchor: offset[2]
71709               }; // insert a collision box for the text label..
71710
71711               var bbox;
71712
71713               if (textDirection === 'rtl') {
71714                 bbox = {
71715                   minX: p.x - width - textPadding,
71716                   minY: p.y - height / 2 - textPadding,
71717                   maxX: p.x + textPadding,
71718                   maxY: p.y + height / 2 + textPadding
71719                 };
71720               } else {
71721                 bbox = {
71722                   minX: p.x - textPadding,
71723                   minY: p.y - height / 2 - textPadding,
71724                   maxX: p.x + width + textPadding,
71725                   maxY: p.y + height / 2 + textPadding
71726                 };
71727               }
71728
71729               if (tryInsert([bbox], entity.id, true)) {
71730                 return p;
71731               }
71732             }
71733
71734             function getLineLabel(entity, width, height) {
71735               var viewport = geoExtent(context.projection.clipExtent()).polygon();
71736               var points = graph.childNodes(entity).map(function (node) {
71737                 return projection(node.loc);
71738               });
71739               var length = geoPathLength(points);
71740               if (length < width + 20) return; // % along the line to attempt to place the label
71741
71742               var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
71743               var padding = 3;
71744
71745               for (var i = 0; i < lineOffsets.length; i++) {
71746                 var offset = lineOffsets[i];
71747                 var middle = offset / 100 * length;
71748                 var start = middle - width / 2;
71749                 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
71750
71751                 var sub = subpath(points, start, start + width);
71752
71753                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
71754                   continue;
71755                 }
71756
71757                 var isReverse = reverse(sub);
71758
71759                 if (isReverse) {
71760                   sub = sub.reverse();
71761                 }
71762
71763                 var bboxes = [];
71764                 var boxsize = (height + 2) / 2;
71765
71766                 for (var j = 0; j < sub.length - 1; j++) {
71767                   var a = sub[j];
71768                   var b = sub[j + 1]; // split up the text into small collision boxes
71769
71770                   var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
71771
71772                   for (var box = 0; box < num; box++) {
71773                     var p = geoVecInterp(a, b, box / num);
71774                     var x0 = p[0] - boxsize - padding;
71775                     var y0 = p[1] - boxsize - padding;
71776                     var x1 = p[0] + boxsize + padding;
71777                     var y1 = p[1] + boxsize + padding;
71778                     bboxes.push({
71779                       minX: Math.min(x0, x1),
71780                       minY: Math.min(y0, y1),
71781                       maxX: Math.max(x0, x1),
71782                       maxY: Math.max(y0, y1)
71783                     });
71784                   }
71785                 }
71786
71787                 if (tryInsert(bboxes, entity.id, false)) {
71788                   // accept this one
71789                   return {
71790                     'font-size': height + 2,
71791                     lineString: lineString(sub),
71792                     startOffset: offset + '%'
71793                   };
71794                 }
71795               }
71796
71797               function reverse(p) {
71798                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
71799                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
71800               }
71801
71802               function lineString(points) {
71803                 return 'M' + points.join('L');
71804               }
71805
71806               function subpath(points, from, to) {
71807                 var sofar = 0;
71808                 var start, end, i0, i1;
71809
71810                 for (var i = 0; i < points.length - 1; i++) {
71811                   var a = points[i];
71812                   var b = points[i + 1];
71813                   var current = geoVecLength(a, b);
71814                   var portion;
71815
71816                   if (!start && sofar + current >= from) {
71817                     portion = (from - sofar) / current;
71818                     start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
71819                     i0 = i + 1;
71820                   }
71821
71822                   if (!end && sofar + current >= to) {
71823                     portion = (to - sofar) / current;
71824                     end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
71825                     i1 = i + 1;
71826                   }
71827
71828                   sofar += current;
71829                 }
71830
71831                 var result = points.slice(i0, i1);
71832                 result.unshift(start);
71833                 result.push(end);
71834                 return result;
71835               }
71836             }
71837
71838             function getAreaLabel(entity, width, height) {
71839               var centroid = path.centroid(entity.asGeoJSON(graph, true));
71840               var extent = entity.extent(graph);
71841               var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
71842               if (isNaN(centroid[0]) || areaWidth < 20) return;
71843               var preset = _mainPresetIndex.match(entity, context.graph());
71844               var picon = preset && preset.icon;
71845               var iconSize = 17;
71846               var padding = 2;
71847               var p = {};
71848
71849               if (picon) {
71850                 // icon and label..
71851                 if (addIcon()) {
71852                   addLabel(iconSize + padding);
71853                   return p;
71854                 }
71855               } else {
71856                 // label only..
71857                 if (addLabel(0)) {
71858                   return p;
71859                 }
71860               }
71861
71862               function addIcon() {
71863                 var iconX = centroid[0] - iconSize / 2;
71864                 var iconY = centroid[1] - iconSize / 2;
71865                 var bbox = {
71866                   minX: iconX,
71867                   minY: iconY,
71868                   maxX: iconX + iconSize,
71869                   maxY: iconY + iconSize
71870                 };
71871
71872                 if (tryInsert([bbox], entity.id + 'I', true)) {
71873                   p.transform = 'translate(' + iconX + ',' + iconY + ')';
71874                   return true;
71875                 }
71876
71877                 return false;
71878               }
71879
71880               function addLabel(yOffset) {
71881                 if (width && areaWidth >= width + 20) {
71882                   var labelX = centroid[0];
71883                   var labelY = centroid[1] + yOffset;
71884                   var bbox = {
71885                     minX: labelX - width / 2 - padding,
71886                     minY: labelY - height / 2 - padding,
71887                     maxX: labelX + width / 2 + padding,
71888                     maxY: labelY + height / 2 + padding
71889                   };
71890
71891                   if (tryInsert([bbox], entity.id, true)) {
71892                     p.x = labelX;
71893                     p.y = labelY;
71894                     p.textAnchor = 'middle';
71895                     p.height = height;
71896                     return true;
71897                   }
71898                 }
71899
71900                 return false;
71901               }
71902             } // force insert a singular bounding box
71903             // singular box only, no array, id better be unique
71904
71905
71906             function doInsert(bbox, id) {
71907               bbox.id = id;
71908               var oldbox = _entitybboxes[id];
71909
71910               if (oldbox) {
71911                 _rdrawn.remove(oldbox);
71912               }
71913
71914               _entitybboxes[id] = bbox;
71915
71916               _rdrawn.insert(bbox);
71917             }
71918
71919             function tryInsert(bboxes, id, saveSkipped) {
71920               var skipped = false;
71921
71922               for (var i = 0; i < bboxes.length; i++) {
71923                 var bbox = bboxes[i];
71924                 bbox.id = id; // Check that label is visible
71925
71926                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
71927                   skipped = true;
71928                   break;
71929                 }
71930
71931                 if (_rdrawn.collides(bbox)) {
71932                   skipped = true;
71933                   break;
71934                 }
71935               }
71936
71937               _entitybboxes[id] = bboxes;
71938
71939               if (skipped) {
71940                 if (saveSkipped) {
71941                   _rskipped.load(bboxes);
71942                 }
71943               } else {
71944                 _rdrawn.load(bboxes);
71945               }
71946
71947               return !skipped;
71948             }
71949
71950             var layer = selection.selectAll('.layer-osm.labels');
71951             layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
71952               return 'labels-group ' + d;
71953             });
71954             var halo = layer.selectAll('.labels-group.halo');
71955             var label = layer.selectAll('.labels-group.label');
71956             var debug = layer.selectAll('.labels-group.debug'); // points
71957
71958             drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
71959             drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
71960
71961             drawLinePaths(layer, labelled.line, filter, '', positions.line);
71962             drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
71963             drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
71964
71965             drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
71966             drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
71967             drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
71968             drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
71969
71970             drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
71971             drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
71972             layer.call(filterLabels);
71973           }
71974
71975           function filterLabels(selection) {
71976             var drawLayer = selection.selectAll('.layer-osm.labels');
71977             var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
71978             layers.selectAll('.nolabel').classed('nolabel', false);
71979             var mouse = context.map().mouse();
71980             var graph = context.graph();
71981             var selectedIDs = context.selectedIDs();
71982             var ids = [];
71983             var pad, bbox; // hide labels near the mouse
71984
71985             if (mouse) {
71986               pad = 20;
71987               bbox = {
71988                 minX: mouse[0] - pad,
71989                 minY: mouse[1] - pad,
71990                 maxX: mouse[0] + pad,
71991                 maxY: mouse[1] + pad
71992               };
71993
71994               var nearMouse = _rdrawn.search(bbox).map(function (entity) {
71995                 return entity.id;
71996               });
71997
71998               ids.push.apply(ids, nearMouse);
71999             } // hide labels on selected nodes (they look weird when dragging / haloed)
72000
72001
72002             for (var i = 0; i < selectedIDs.length; i++) {
72003               var entity = graph.hasEntity(selectedIDs[i]);
72004
72005               if (entity && entity.type === 'node') {
72006                 ids.push(selectedIDs[i]);
72007               }
72008             }
72009
72010             layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
72011
72012             var debug = selection.selectAll('.labels-group.debug');
72013             var gj = [];
72014
72015             if (context.getDebug('collision')) {
72016               gj = bbox ? [{
72017                 type: 'Polygon',
72018                 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
72019               }] : [];
72020             }
72021
72022             var box = debug.selectAll('.debug-mouse').data(gj); // exit
72023
72024             box.exit().remove(); // enter/update
72025
72026             box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
72027           }
72028
72029           var throttleFilterLabels = throttle(filterLabels, 100);
72030
72031           drawLabels.observe = function (selection) {
72032             var listener = function listener() {
72033               throttleFilterLabels(selection);
72034             };
72035
72036             selection.on('mousemove.hidelabels', listener);
72037             context.on('enter.hidelabels', listener);
72038           };
72039
72040           drawLabels.off = function (selection) {
72041             throttleFilterLabels.cancel();
72042             selection.on('mousemove.hidelabels', null);
72043             context.on('enter.hidelabels', null);
72044           };
72045
72046           return drawLabels;
72047         }
72048
72049         var _layerEnabled$1 = false;
72050
72051         var _qaService$1;
72052
72053         function svgImproveOSM(projection, context, dispatch) {
72054           var throttledRedraw = throttle(function () {
72055             return dispatch.call('change');
72056           }, 1000);
72057
72058           var minZoom = 12;
72059           var touchLayer = select(null);
72060           var drawLayer = select(null);
72061           var layerVisible = false;
72062
72063           function markerPath(selection, klass) {
72064             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');
72065           } // Loosely-coupled improveOSM service for fetching issues
72066
72067
72068           function getService() {
72069             if (services.improveOSM && !_qaService$1) {
72070               _qaService$1 = services.improveOSM;
72071
72072               _qaService$1.on('loaded', throttledRedraw);
72073             } else if (!services.improveOSM && _qaService$1) {
72074               _qaService$1 = null;
72075             }
72076
72077             return _qaService$1;
72078           } // Show the markers
72079
72080
72081           function editOn() {
72082             if (!layerVisible) {
72083               layerVisible = true;
72084               drawLayer.style('display', 'block');
72085             }
72086           } // Immediately remove the markers and their touch targets
72087
72088
72089           function editOff() {
72090             if (layerVisible) {
72091               layerVisible = false;
72092               drawLayer.style('display', 'none');
72093               drawLayer.selectAll('.qaItem.improveOSM').remove();
72094               touchLayer.selectAll('.qaItem.improveOSM').remove();
72095             }
72096           } // Enable the layer.  This shows the markers and transitions them to visible.
72097
72098
72099           function layerOn() {
72100             editOn();
72101             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72102               return dispatch.call('change');
72103             });
72104           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
72105
72106
72107           function layerOff() {
72108             throttledRedraw.cancel();
72109             drawLayer.interrupt();
72110             touchLayer.selectAll('.qaItem.improveOSM').remove();
72111             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72112               editOff();
72113               dispatch.call('change');
72114             });
72115           } // Update the issue markers
72116
72117
72118           function updateMarkers() {
72119             if (!layerVisible || !_layerEnabled$1) return;
72120             var service = getService();
72121             var selectedID = context.selectedErrorID();
72122             var data = service ? service.getItems(projection) : [];
72123             var getTransform = svgPointTransform(projection); // Draw markers..
72124
72125             var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
72126               return d.id;
72127             }); // exit
72128
72129             markers.exit().remove(); // enter
72130
72131             var markersEnter = markers.enter().append('g').attr('class', function (d) {
72132               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
72133             });
72134             markersEnter.append('polygon').call(markerPath, 'shadow');
72135             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
72136             markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
72137             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
72138               var picon = d.icon;
72139
72140               if (!picon) {
72141                 return '';
72142               } else {
72143                 var isMaki = /^maki-/.test(picon);
72144                 return "#".concat(picon).concat(isMaki ? '-11' : '');
72145               }
72146             }); // update
72147
72148             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
72149               return d.id === selectedID;
72150             }).attr('transform', getTransform); // Draw targets..
72151
72152             if (touchLayer.empty()) return;
72153             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
72154             var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
72155               return d.id;
72156             }); // exit
72157
72158             targets.exit().remove(); // enter/update
72159
72160             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
72161               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
72162             }).attr('transform', getTransform);
72163
72164             function sortY(a, b) {
72165               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72166             }
72167           } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
72168
72169
72170           function drawImproveOSM(selection) {
72171             var service = getService();
72172             var surface = context.surface();
72173
72174             if (surface && !surface.empty()) {
72175               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72176             }
72177
72178             drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
72179             drawLayer.exit().remove();
72180             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
72181
72182             if (_layerEnabled$1) {
72183               if (service && ~~context.map().zoom() >= minZoom) {
72184                 editOn();
72185                 service.loadIssues(projection);
72186                 updateMarkers();
72187               } else {
72188                 editOff();
72189               }
72190             }
72191           } // Toggles the layer on and off
72192
72193
72194           drawImproveOSM.enabled = function (val) {
72195             if (!arguments.length) return _layerEnabled$1;
72196             _layerEnabled$1 = val;
72197
72198             if (_layerEnabled$1) {
72199               layerOn();
72200             } else {
72201               layerOff();
72202
72203               if (context.selectedErrorID()) {
72204                 context.enter(modeBrowse(context));
72205               }
72206             }
72207
72208             dispatch.call('change');
72209             return this;
72210           };
72211
72212           drawImproveOSM.supported = function () {
72213             return !!getService();
72214           };
72215
72216           return drawImproveOSM;
72217         }
72218
72219         var _layerEnabled$2 = false;
72220
72221         var _qaService$2;
72222
72223         function svgOsmose(projection, context, dispatch) {
72224           var throttledRedraw = throttle(function () {
72225             return dispatch.call('change');
72226           }, 1000);
72227
72228           var minZoom = 12;
72229           var touchLayer = select(null);
72230           var drawLayer = select(null);
72231           var layerVisible = false;
72232
72233           function markerPath(selection, klass) {
72234             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');
72235           } // Loosely-coupled osmose service for fetching issues
72236
72237
72238           function getService() {
72239             if (services.osmose && !_qaService$2) {
72240               _qaService$2 = services.osmose;
72241
72242               _qaService$2.on('loaded', throttledRedraw);
72243             } else if (!services.osmose && _qaService$2) {
72244               _qaService$2 = null;
72245             }
72246
72247             return _qaService$2;
72248           } // Show the markers
72249
72250
72251           function editOn() {
72252             if (!layerVisible) {
72253               layerVisible = true;
72254               drawLayer.style('display', 'block');
72255             }
72256           } // Immediately remove the markers and their touch targets
72257
72258
72259           function editOff() {
72260             if (layerVisible) {
72261               layerVisible = false;
72262               drawLayer.style('display', 'none');
72263               drawLayer.selectAll('.qaItem.osmose').remove();
72264               touchLayer.selectAll('.qaItem.osmose').remove();
72265             }
72266           } // Enable the layer.  This shows the markers and transitions them to visible.
72267
72268
72269           function layerOn() {
72270             editOn();
72271             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
72272               return dispatch.call('change');
72273             });
72274           } // Disable the layer.  This transitions the layer invisible and then hides the markers.
72275
72276
72277           function layerOff() {
72278             throttledRedraw.cancel();
72279             drawLayer.interrupt();
72280             touchLayer.selectAll('.qaItem.osmose').remove();
72281             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
72282               editOff();
72283               dispatch.call('change');
72284             });
72285           } // Update the issue markers
72286
72287
72288           function updateMarkers() {
72289             if (!layerVisible || !_layerEnabled$2) return;
72290             var service = getService();
72291             var selectedID = context.selectedErrorID();
72292             var data = service ? service.getItems(projection) : [];
72293             var getTransform = svgPointTransform(projection); // Draw markers..
72294
72295             var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
72296               return d.id;
72297             }); // exit
72298
72299             markers.exit().remove(); // enter
72300
72301             var markersEnter = markers.enter().append('g').attr('class', function (d) {
72302               return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
72303             });
72304             markersEnter.append('polygon').call(markerPath, 'shadow');
72305             markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
72306             markersEnter.append('polygon').attr('fill', function (d) {
72307               return service.getColor(d.item);
72308             }).call(markerPath, 'qaItem-fill');
72309             markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
72310               var picon = d.icon;
72311
72312               if (!picon) {
72313                 return '';
72314               } else {
72315                 var isMaki = /^maki-/.test(picon);
72316                 return "#".concat(picon).concat(isMaki ? '-11' : '');
72317               }
72318             }); // update
72319
72320             markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
72321               return d.id === selectedID;
72322             }).attr('transform', getTransform); // Draw targets..
72323
72324             if (touchLayer.empty()) return;
72325             var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
72326             var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
72327               return d.id;
72328             }); // exit
72329
72330             targets.exit().remove(); // enter/update
72331
72332             targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
72333               return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
72334             }).attr('transform', getTransform);
72335
72336             function sortY(a, b) {
72337               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
72338             }
72339           } // Draw the Osmose layer and schedule loading issues and updating markers.
72340
72341
72342           function drawOsmose(selection) {
72343             var service = getService();
72344             var surface = context.surface();
72345
72346             if (surface && !surface.empty()) {
72347               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
72348             }
72349
72350             drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
72351             drawLayer.exit().remove();
72352             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
72353
72354             if (_layerEnabled$2) {
72355               if (service && ~~context.map().zoom() >= minZoom) {
72356                 editOn();
72357                 service.loadIssues(projection);
72358                 updateMarkers();
72359               } else {
72360                 editOff();
72361               }
72362             }
72363           } // Toggles the layer on and off
72364
72365
72366           drawOsmose.enabled = function (val) {
72367             if (!arguments.length) return _layerEnabled$2;
72368             _layerEnabled$2 = val;
72369
72370             if (_layerEnabled$2) {
72371               // Strings supplied by Osmose fetched before showing layer for first time
72372               // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
72373               // Also, If layer is toggled quickly multiple requests are sent
72374               getService().loadStrings().then(layerOn)["catch"](function (err) {
72375                 console.log(err); // eslint-disable-line no-console
72376               });
72377             } else {
72378               layerOff();
72379
72380               if (context.selectedErrorID()) {
72381                 context.enter(modeBrowse(context));
72382               }
72383             }
72384
72385             dispatch.call('change');
72386             return this;
72387           };
72388
72389           drawOsmose.supported = function () {
72390             return !!getService();
72391           };
72392
72393           return drawOsmose;
72394         }
72395
72396         function svgStreetside(projection, context, dispatch) {
72397           var throttledRedraw = throttle(function () {
72398             dispatch.call('change');
72399           }, 1000);
72400
72401           var minZoom = 14;
72402           var minMarkerZoom = 16;
72403           var minViewfieldZoom = 18;
72404           var layer = select(null);
72405           var _viewerYaw = 0;
72406           var _selectedSequence = null;
72407
72408           var _streetside;
72409           /**
72410            * init().
72411            */
72412
72413
72414           function init() {
72415             if (svgStreetside.initialized) return; // run once
72416
72417             svgStreetside.enabled = false;
72418             svgStreetside.initialized = true;
72419           }
72420           /**
72421            * getService().
72422            */
72423
72424
72425           function getService() {
72426             if (services.streetside && !_streetside) {
72427               _streetside = services.streetside;
72428
72429               _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
72430             } else if (!services.streetside && _streetside) {
72431               _streetside = null;
72432             }
72433
72434             return _streetside;
72435           }
72436           /**
72437            * showLayer().
72438            */
72439
72440
72441           function showLayer() {
72442             var service = getService();
72443             if (!service) return;
72444             editOn();
72445             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72446               dispatch.call('change');
72447             });
72448           }
72449           /**
72450            * hideLayer().
72451            */
72452
72453
72454           function hideLayer() {
72455             throttledRedraw.cancel();
72456             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72457           }
72458           /**
72459            * editOn().
72460            */
72461
72462
72463           function editOn() {
72464             layer.style('display', 'block');
72465           }
72466           /**
72467            * editOff().
72468            */
72469
72470
72471           function editOff() {
72472             layer.selectAll('.viewfield-group').remove();
72473             layer.style('display', 'none');
72474           }
72475           /**
72476            * click() Handles 'bubble' point click event.
72477            */
72478
72479
72480           function click(d3_event, d) {
72481             var service = getService();
72482             if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
72483
72484             if (d.sequenceKey !== _selectedSequence) {
72485               _viewerYaw = 0; // reset
72486             }
72487
72488             _selectedSequence = d.sequenceKey;
72489             service.ensureViewerLoaded(context).then(function () {
72490               service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
72491             });
72492             context.map().centerEase(d.loc);
72493           }
72494           /**
72495            * mouseover().
72496            */
72497
72498
72499           function mouseover(d3_event, d) {
72500             var service = getService();
72501             if (service) service.setStyles(context, d);
72502           }
72503           /**
72504            * mouseout().
72505            */
72506
72507
72508           function mouseout() {
72509             var service = getService();
72510             if (service) service.setStyles(context, null);
72511           }
72512           /**
72513            * transform().
72514            */
72515
72516
72517           function transform(d) {
72518             var t = svgPointTransform(projection)(d);
72519             var rot = d.ca + _viewerYaw;
72520
72521             if (rot) {
72522               t += ' rotate(' + Math.floor(rot) + ',0,0)';
72523             }
72524
72525             return t;
72526           }
72527
72528           function viewerChanged() {
72529             var service = getService();
72530             if (!service) return;
72531             var viewer = service.viewer();
72532             if (!viewer) return; // update viewfield rotation
72533
72534             _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
72535             // e.g. during drags or easing.
72536
72537             if (context.map().isTransformed()) return;
72538             layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
72539           }
72540
72541           function filterBubbles(bubbles) {
72542             var fromDate = context.photos().fromDate();
72543             var toDate = context.photos().toDate();
72544             var usernames = context.photos().usernames();
72545
72546             if (fromDate) {
72547               var fromTimestamp = new Date(fromDate).getTime();
72548               bubbles = bubbles.filter(function (bubble) {
72549                 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
72550               });
72551             }
72552
72553             if (toDate) {
72554               var toTimestamp = new Date(toDate).getTime();
72555               bubbles = bubbles.filter(function (bubble) {
72556                 return new Date(bubble.captured_at).getTime() <= toTimestamp;
72557               });
72558             }
72559
72560             if (usernames) {
72561               bubbles = bubbles.filter(function (bubble) {
72562                 return usernames.indexOf(bubble.captured_by) !== -1;
72563               });
72564             }
72565
72566             return bubbles;
72567           }
72568
72569           function filterSequences(sequences) {
72570             var fromDate = context.photos().fromDate();
72571             var toDate = context.photos().toDate();
72572             var usernames = context.photos().usernames();
72573
72574             if (fromDate) {
72575               var fromTimestamp = new Date(fromDate).getTime();
72576               sequences = sequences.filter(function (sequences) {
72577                 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
72578               });
72579             }
72580
72581             if (toDate) {
72582               var toTimestamp = new Date(toDate).getTime();
72583               sequences = sequences.filter(function (sequences) {
72584                 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
72585               });
72586             }
72587
72588             if (usernames) {
72589               sequences = sequences.filter(function (sequences) {
72590                 return usernames.indexOf(sequences.properties.captured_by) !== -1;
72591               });
72592             }
72593
72594             return sequences;
72595           }
72596           /**
72597            * update().
72598            */
72599
72600
72601           function update() {
72602             var viewer = context.container().select('.photoviewer');
72603             var selected = viewer.empty() ? undefined : viewer.datum();
72604             var z = ~~context.map().zoom();
72605             var showMarkers = z >= minMarkerZoom;
72606             var showViewfields = z >= minViewfieldZoom;
72607             var service = getService();
72608             var sequences = [];
72609             var bubbles = [];
72610
72611             if (context.photos().showsPanoramic()) {
72612               sequences = service ? service.sequences(projection) : [];
72613               bubbles = service && showMarkers ? service.bubbles(projection) : [];
72614               sequences = filterSequences(sequences);
72615               bubbles = filterBubbles(bubbles);
72616             }
72617
72618             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72619               return d.properties.key;
72620             }); // exit
72621
72622             traces.exit().remove(); // enter/update
72623
72624             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72625             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
72626               // force reenter once bubbles are attached to a sequence
72627               return d.key + (d.sequenceKey ? 'v1' : 'v0');
72628             }); // exit
72629
72630             groups.exit().remove(); // enter
72631
72632             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72633             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72634
72635             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72636               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
72637             }).attr('transform', transform).select('.viewfield-scale');
72638             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72639             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72640             viewfields.exit().remove(); // viewfields may or may not be drawn...
72641             // but if they are, draw below the circles
72642
72643             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72644
72645             function viewfieldPath() {
72646               var d = this.parentNode.__data__;
72647
72648               if (d.pano) {
72649                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72650               } else {
72651                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72652               }
72653             }
72654           }
72655           /**
72656            * drawImages()
72657            * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
72658            * 'svgStreetside()' is called from index.js
72659            */
72660
72661
72662           function drawImages(selection) {
72663             var enabled = svgStreetside.enabled;
72664             var service = getService();
72665             layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
72666             layer.exit().remove();
72667             var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
72668             layerEnter.append('g').attr('class', 'sequences');
72669             layerEnter.append('g').attr('class', 'markers');
72670             layer = layerEnter.merge(layer);
72671
72672             if (enabled) {
72673               if (service && ~~context.map().zoom() >= minZoom) {
72674                 editOn();
72675                 update();
72676                 service.loadBubbles(projection);
72677               } else {
72678                 editOff();
72679               }
72680             }
72681           }
72682           /**
72683            * drawImages.enabled().
72684            */
72685
72686
72687           drawImages.enabled = function (_) {
72688             if (!arguments.length) return svgStreetside.enabled;
72689             svgStreetside.enabled = _;
72690
72691             if (svgStreetside.enabled) {
72692               showLayer();
72693               context.photos().on('change.streetside', update);
72694             } else {
72695               hideLayer();
72696               context.photos().on('change.streetside', null);
72697             }
72698
72699             dispatch.call('change');
72700             return this;
72701           };
72702           /**
72703            * drawImages.supported().
72704            */
72705
72706
72707           drawImages.supported = function () {
72708             return !!getService();
72709           };
72710
72711           init();
72712           return drawImages;
72713         }
72714
72715         function svgMapillaryImages(projection, context, dispatch) {
72716           var throttledRedraw = throttle(function () {
72717             dispatch.call('change');
72718           }, 1000);
72719
72720           var minZoom = 12;
72721           var minMarkerZoom = 16;
72722           var minViewfieldZoom = 18;
72723           var layer = select(null);
72724
72725           var _mapillary;
72726
72727           var viewerCompassAngle;
72728
72729           function init() {
72730             if (svgMapillaryImages.initialized) return; // run once
72731
72732             svgMapillaryImages.enabled = false;
72733             svgMapillaryImages.initialized = true;
72734           }
72735
72736           function getService() {
72737             if (services.mapillary && !_mapillary) {
72738               _mapillary = services.mapillary;
72739
72740               _mapillary.event.on('loadedImages', throttledRedraw);
72741             } else if (!services.mapillary && _mapillary) {
72742               _mapillary = null;
72743             }
72744
72745             return _mapillary;
72746           }
72747
72748           function showLayer() {
72749             var service = getService();
72750             if (!service) return;
72751             editOn();
72752             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
72753               dispatch.call('change');
72754             });
72755           }
72756
72757           function hideLayer() {
72758             throttledRedraw.cancel();
72759             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
72760           }
72761
72762           function editOn() {
72763             layer.style('display', 'block');
72764           }
72765
72766           function editOff() {
72767             layer.selectAll('.viewfield-group').remove();
72768             layer.style('display', 'none');
72769           }
72770
72771           function click(d3_event, d) {
72772             var service = getService();
72773             if (!service) return;
72774             service.ensureViewerLoaded(context).then(function () {
72775               service.selectImage(context, d.key).showViewer(context);
72776             });
72777             context.map().centerEase(d.loc);
72778           }
72779
72780           function mouseover(d) {
72781             var service = getService();
72782             if (service) service.setStyles(context, d);
72783           }
72784
72785           function mouseout() {
72786             var service = getService();
72787             if (service) service.setStyles(context, null);
72788           }
72789
72790           function transform(d) {
72791             var t = svgPointTransform(projection)(d);
72792
72793             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
72794               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
72795             } else if (d.ca) {
72796               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
72797             }
72798
72799             return t;
72800           }
72801
72802           function filterImages(images) {
72803             var showsPano = context.photos().showsPanoramic();
72804             var showsFlat = context.photos().showsFlat();
72805             var fromDate = context.photos().fromDate();
72806             var toDate = context.photos().toDate();
72807             var usernames = context.photos().usernames();
72808
72809             if (!showsPano || !showsFlat) {
72810               images = images.filter(function (image) {
72811                 if (image.pano) return showsPano;
72812                 return showsFlat;
72813               });
72814             }
72815
72816             if (fromDate) {
72817               var fromTimestamp = new Date(fromDate).getTime();
72818               images = images.filter(function (image) {
72819                 return new Date(image.captured_at).getTime() >= fromTimestamp;
72820               });
72821             }
72822
72823             if (toDate) {
72824               var toTimestamp = new Date(toDate).getTime();
72825               images = images.filter(function (image) {
72826                 return new Date(image.captured_at).getTime() <= toTimestamp;
72827               });
72828             }
72829
72830             if (usernames) {
72831               images = images.filter(function (image) {
72832                 return usernames.indexOf(image.captured_by) !== -1;
72833               });
72834             }
72835
72836             return images;
72837           }
72838
72839           function filterSequences(sequences, service) {
72840             var showsPano = context.photos().showsPanoramic();
72841             var showsFlat = context.photos().showsFlat();
72842             var fromDate = context.photos().fromDate();
72843             var toDate = context.photos().toDate();
72844             var usernames = context.photos().usernames();
72845
72846             if (!showsPano || !showsFlat) {
72847               sequences = sequences.filter(function (sequence) {
72848                 if (sequence.properties.hasOwnProperty('pano')) {
72849                   if (sequence.properties.pano) return showsPano;
72850                   return showsFlat;
72851                 } else {
72852                   // if the sequence doesn't specify pano or not, search its images
72853                   var cProps = sequence.properties.coordinateProperties;
72854
72855                   if (cProps && cProps.image_keys && cProps.image_keys.length > 0) {
72856                     for (var index in cProps.image_keys) {
72857                       var imageKey = cProps.image_keys[index];
72858                       var image = service.cachedImage(imageKey);
72859
72860                       if (image && image.hasOwnProperty('pano')) {
72861                         if (image.pano) return showsPano;
72862                         return showsFlat;
72863                       }
72864                     }
72865                   }
72866                 }
72867
72868                 return false;
72869               });
72870             }
72871
72872             if (fromDate) {
72873               var fromTimestamp = new Date(fromDate).getTime();
72874               sequences = sequences.filter(function (sequence) {
72875                 return new Date(sequence.properties.captured_at).getTime() >= fromTimestamp;
72876               });
72877             }
72878
72879             if (toDate) {
72880               var toTimestamp = new Date(toDate).getTime();
72881               sequences = sequences.filter(function (sequence) {
72882                 return new Date(sequence.properties.captured_at).getTime() <= toTimestamp;
72883               });
72884             }
72885
72886             if (usernames) {
72887               sequences = sequences.filter(function (sequence) {
72888                 return usernames.indexOf(sequence.properties.username) !== -1;
72889               });
72890             }
72891
72892             return sequences;
72893           }
72894
72895           function update() {
72896             var z = ~~context.map().zoom();
72897             var showMarkers = z >= minMarkerZoom;
72898             var showViewfields = z >= minViewfieldZoom;
72899             var service = getService();
72900             var sequences = service ? service.sequences(projection) : [];
72901             var images = service && showMarkers ? service.images(projection) : [];
72902             images = filterImages(images);
72903             sequences = filterSequences(sequences, service);
72904             service.filterViewer(context);
72905             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
72906               return d.properties.key;
72907             }); // exit
72908
72909             traces.exit().remove(); // enter/update
72910
72911             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
72912             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
72913               return d.key;
72914             }); // exit
72915
72916             groups.exit().remove(); // enter
72917
72918             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
72919             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
72920
72921             var markers = groups.merge(groupsEnter).sort(function (a, b) {
72922               return b.loc[1] - a.loc[1]; // sort Y
72923             }).attr('transform', transform).select('.viewfield-scale');
72924             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
72925             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
72926             viewfields.exit().remove();
72927             viewfields.enter() // viewfields may or may not be drawn...
72928             .insert('path', 'circle') // but if they are, draw below the circles
72929             .attr('class', 'viewfield').classed('pano', function () {
72930               return this.parentNode.__data__.pano;
72931             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
72932
72933             function viewfieldPath() {
72934               var d = this.parentNode.__data__;
72935
72936               if (d.pano) {
72937                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
72938               } else {
72939                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
72940               }
72941             }
72942           }
72943
72944           function drawImages(selection) {
72945             var enabled = svgMapillaryImages.enabled;
72946             var service = getService();
72947             layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
72948             layer.exit().remove();
72949             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
72950             layerEnter.append('g').attr('class', 'sequences');
72951             layerEnter.append('g').attr('class', 'markers');
72952             layer = layerEnter.merge(layer);
72953
72954             if (enabled) {
72955               if (service && ~~context.map().zoom() >= minZoom) {
72956                 editOn();
72957                 update();
72958                 service.loadImages(projection);
72959               } else {
72960                 editOff();
72961               }
72962             }
72963           }
72964
72965           drawImages.enabled = function (_) {
72966             if (!arguments.length) return svgMapillaryImages.enabled;
72967             svgMapillaryImages.enabled = _;
72968
72969             if (svgMapillaryImages.enabled) {
72970               showLayer();
72971               context.photos().on('change.mapillary_images', update);
72972             } else {
72973               hideLayer();
72974               context.photos().on('change.mapillary_images', null);
72975             }
72976
72977             dispatch.call('change');
72978             return this;
72979           };
72980
72981           drawImages.supported = function () {
72982             return !!getService();
72983           };
72984
72985           init();
72986           return drawImages;
72987         }
72988
72989         function svgMapillaryPosition(projection, context) {
72990           var throttledRedraw = throttle(function () {
72991             update();
72992           }, 1000);
72993
72994           var minZoom = 12;
72995           var minViewfieldZoom = 18;
72996           var layer = select(null);
72997
72998           var _mapillary;
72999
73000           var viewerCompassAngle;
73001
73002           function init() {
73003             if (svgMapillaryPosition.initialized) return; // run once
73004
73005             svgMapillaryPosition.initialized = true;
73006           }
73007
73008           function getService() {
73009             if (services.mapillary && !_mapillary) {
73010               _mapillary = services.mapillary;
73011
73012               _mapillary.event.on('nodeChanged', throttledRedraw);
73013
73014               _mapillary.event.on('bearingChanged', function (e) {
73015                 viewerCompassAngle = e;
73016                 if (context.map().isTransformed()) return;
73017                 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
73018                   return d.pano;
73019                 }).attr('transform', transform);
73020               });
73021             } else if (!services.mapillary && _mapillary) {
73022               _mapillary = null;
73023             }
73024
73025             return _mapillary;
73026           }
73027
73028           function editOn() {
73029             layer.style('display', 'block');
73030           }
73031
73032           function editOff() {
73033             layer.selectAll('.viewfield-group').remove();
73034             layer.style('display', 'none');
73035           }
73036
73037           function transform(d) {
73038             var t = svgPointTransform(projection)(d);
73039
73040             if (d.pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
73041               t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
73042             } else if (d.ca) {
73043               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
73044             }
73045
73046             return t;
73047           }
73048
73049           function update() {
73050             var z = ~~context.map().zoom();
73051             var showViewfields = z >= minViewfieldZoom;
73052             var service = getService();
73053             var node = service && service.getActiveImage();
73054             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(node ? [node] : [], function (d) {
73055               return d.key;
73056             }); // exit
73057
73058             groups.exit().remove(); // enter
73059
73060             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
73061             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
73062
73063             var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
73064             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
73065             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
73066             viewfields.exit().remove();
73067             viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').classed('pano', function () {
73068               return this.parentNode.__data__.pano;
73069             }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
73070
73071             function viewfieldPath() {
73072               var d = this.parentNode.__data__;
73073
73074               if (d.pano) {
73075                 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
73076               } else {
73077                 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
73078               }
73079             }
73080           }
73081
73082           function drawImages(selection) {
73083             var service = getService();
73084             layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
73085             layer.exit().remove();
73086             var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
73087             layerEnter.append('g').attr('class', 'markers');
73088             layer = layerEnter.merge(layer);
73089
73090             if (service && ~~context.map().zoom() >= minZoom) {
73091               editOn();
73092               update();
73093             } else {
73094               editOff();
73095             }
73096           }
73097
73098           drawImages.enabled = function () {
73099             update();
73100             return this;
73101           };
73102
73103           drawImages.supported = function () {
73104             return !!getService();
73105           };
73106
73107           init();
73108           return drawImages;
73109         }
73110
73111         function svgMapillarySigns(projection, context, dispatch) {
73112           var throttledRedraw = throttle(function () {
73113             dispatch.call('change');
73114           }, 1000);
73115
73116           var minZoom = 12;
73117           var layer = select(null);
73118
73119           var _mapillary;
73120
73121           function init() {
73122             if (svgMapillarySigns.initialized) return; // run once
73123
73124             svgMapillarySigns.enabled = false;
73125             svgMapillarySigns.initialized = true;
73126           }
73127
73128           function getService() {
73129             if (services.mapillary && !_mapillary) {
73130               _mapillary = services.mapillary;
73131
73132               _mapillary.event.on('loadedSigns', throttledRedraw);
73133             } else if (!services.mapillary && _mapillary) {
73134               _mapillary = null;
73135             }
73136
73137             return _mapillary;
73138           }
73139
73140           function showLayer() {
73141             var service = getService();
73142             if (!service) return;
73143             service.loadSignResources(context);
73144             editOn();
73145           }
73146
73147           function hideLayer() {
73148             throttledRedraw.cancel();
73149             editOff();
73150           }
73151
73152           function editOn() {
73153             layer.style('display', 'block');
73154           }
73155
73156           function editOff() {
73157             layer.selectAll('.icon-sign').remove();
73158             layer.style('display', 'none');
73159           }
73160
73161           function click(d3_event, d) {
73162             var service = getService();
73163             if (!service) return;
73164             context.map().centerEase(d.loc);
73165             var selectedImageKey = service.getSelectedImageKey();
73166             var imageKey;
73167             var highlightedDetection; // Pick one of the images the sign was detected in,
73168             // preference given to an image already selected.
73169
73170             d.detections.forEach(function (detection) {
73171               if (!imageKey || selectedImageKey === detection.image_key) {
73172                 imageKey = detection.image_key;
73173                 highlightedDetection = detection;
73174               }
73175             });
73176
73177             if (imageKey === selectedImageKey) {
73178               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
73179             } else {
73180               service.ensureViewerLoaded(context).then(function () {
73181                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
73182               });
73183             }
73184           }
73185
73186           function filterData(detectedFeatures) {
73187             var service = getService();
73188             var fromDate = context.photos().fromDate();
73189             var toDate = context.photos().toDate();
73190             var usernames = context.photos().usernames();
73191
73192             if (fromDate) {
73193               var fromTimestamp = new Date(fromDate).getTime();
73194               detectedFeatures = detectedFeatures.filter(function (feature) {
73195                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
73196               });
73197             }
73198
73199             if (toDate) {
73200               var toTimestamp = new Date(toDate).getTime();
73201               detectedFeatures = detectedFeatures.filter(function (feature) {
73202                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
73203               });
73204             }
73205
73206             if (usernames && service) {
73207               detectedFeatures = detectedFeatures.filter(function (feature) {
73208                 return feature.detections.some(function (detection) {
73209                   var imageKey = detection.image_key;
73210                   var image = service.cachedImage(imageKey);
73211                   return image && usernames.indexOf(image.captured_by) !== -1;
73212                 });
73213               });
73214             }
73215
73216             return detectedFeatures;
73217           }
73218
73219           function update() {
73220             var service = getService();
73221             var data = service ? service.signs(projection) : [];
73222             data = filterData(data);
73223             var selectedImageKey = service.getSelectedImageKey();
73224             var transform = svgPointTransform(projection);
73225             var signs = layer.selectAll('.icon-sign').data(data, function (d) {
73226               return d.key;
73227             }); // exit
73228
73229             signs.exit().remove(); // enter
73230
73231             var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
73232             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
73233               return '#' + d.value;
73234             });
73235             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
73236
73237             signs.merge(enter).attr('transform', transform).classed('currentView', function (d) {
73238               return d.detections.some(function (detection) {
73239                 return detection.image_key === selectedImageKey;
73240               });
73241             }).sort(function (a, b) {
73242               var aSelected = a.detections.some(function (detection) {
73243                 return detection.image_key === selectedImageKey;
73244               });
73245               var bSelected = b.detections.some(function (detection) {
73246                 return detection.image_key === selectedImageKey;
73247               });
73248
73249               if (aSelected === bSelected) {
73250                 return b.loc[1] - a.loc[1]; // sort Y
73251               } else if (aSelected) {
73252                 return 1;
73253               }
73254
73255               return -1;
73256             });
73257           }
73258
73259           function drawSigns(selection) {
73260             var enabled = svgMapillarySigns.enabled;
73261             var service = getService();
73262             layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
73263             layer.exit().remove();
73264             layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
73265
73266             if (enabled) {
73267               if (service && ~~context.map().zoom() >= minZoom) {
73268                 editOn();
73269                 update();
73270                 service.loadSigns(projection);
73271                 service.showSignDetections(true);
73272               } else {
73273                 editOff();
73274               }
73275             } else if (service) {
73276               service.showSignDetections(false);
73277             }
73278           }
73279
73280           drawSigns.enabled = function (_) {
73281             if (!arguments.length) return svgMapillarySigns.enabled;
73282             svgMapillarySigns.enabled = _;
73283
73284             if (svgMapillarySigns.enabled) {
73285               showLayer();
73286               context.photos().on('change.mapillary_signs', update);
73287             } else {
73288               hideLayer();
73289               context.photos().on('change.mapillary_signs', null);
73290             }
73291
73292             dispatch.call('change');
73293             return this;
73294           };
73295
73296           drawSigns.supported = function () {
73297             return !!getService();
73298           };
73299
73300           init();
73301           return drawSigns;
73302         }
73303
73304         function svgMapillaryMapFeatures(projection, context, dispatch) {
73305           var throttledRedraw = throttle(function () {
73306             dispatch.call('change');
73307           }, 1000);
73308
73309           var minZoom = 12;
73310           var layer = select(null);
73311
73312           var _mapillary;
73313
73314           function init() {
73315             if (svgMapillaryMapFeatures.initialized) return; // run once
73316
73317             svgMapillaryMapFeatures.enabled = false;
73318             svgMapillaryMapFeatures.initialized = true;
73319           }
73320
73321           function getService() {
73322             if (services.mapillary && !_mapillary) {
73323               _mapillary = services.mapillary;
73324
73325               _mapillary.event.on('loadedMapFeatures', throttledRedraw);
73326             } else if (!services.mapillary && _mapillary) {
73327               _mapillary = null;
73328             }
73329
73330             return _mapillary;
73331           }
73332
73333           function showLayer() {
73334             var service = getService();
73335             if (!service) return;
73336             service.loadObjectResources(context);
73337             editOn();
73338           }
73339
73340           function hideLayer() {
73341             throttledRedraw.cancel();
73342             editOff();
73343           }
73344
73345           function editOn() {
73346             layer.style('display', 'block');
73347           }
73348
73349           function editOff() {
73350             layer.selectAll('.icon-map-feature').remove();
73351             layer.style('display', 'none');
73352           }
73353
73354           function click(d3_event, d) {
73355             var service = getService();
73356             if (!service) return;
73357             context.map().centerEase(d.loc);
73358             var selectedImageKey = service.getSelectedImageKey();
73359             var imageKey;
73360             var highlightedDetection; // Pick one of the images the map feature was detected in,
73361             // preference given to an image already selected.
73362
73363             d.detections.forEach(function (detection) {
73364               if (!imageKey || selectedImageKey === detection.image_key) {
73365                 imageKey = detection.image_key;
73366                 highlightedDetection = detection;
73367               }
73368             });
73369
73370             if (imageKey === selectedImageKey) {
73371               service.highlightDetection(highlightedDetection).selectImage(context, imageKey);
73372             } else {
73373               service.ensureViewerLoaded(context).then(function () {
73374                 service.highlightDetection(highlightedDetection).selectImage(context, imageKey).showViewer(context);
73375               });
73376             }
73377           }
73378
73379           function filterData(detectedFeatures) {
73380             var service = getService();
73381             var fromDate = context.photos().fromDate();
73382             var toDate = context.photos().toDate();
73383             var usernames = context.photos().usernames();
73384
73385             if (fromDate) {
73386               var fromTimestamp = new Date(fromDate).getTime();
73387               detectedFeatures = detectedFeatures.filter(function (feature) {
73388                 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
73389               });
73390             }
73391
73392             if (toDate) {
73393               var toTimestamp = new Date(toDate).getTime();
73394               detectedFeatures = detectedFeatures.filter(function (feature) {
73395                 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
73396               });
73397             }
73398
73399             if (usernames && service) {
73400               detectedFeatures = detectedFeatures.filter(function (feature) {
73401                 return feature.detections.some(function (detection) {
73402                   var imageKey = detection.image_key;
73403                   var image = service.cachedImage(imageKey);
73404                   return image && usernames.indexOf(image.captured_by) !== -1;
73405                 });
73406               });
73407             }
73408
73409             return detectedFeatures;
73410           }
73411
73412           function update() {
73413             var service = getService();
73414             var data = service ? service.mapFeatures(projection) : [];
73415             data = filterData(data);
73416             var selectedImageKey = service && service.getSelectedImageKey();
73417             var transform = svgPointTransform(projection);
73418             var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
73419               return d.key;
73420             }); // exit
73421
73422             mapFeatures.exit().remove(); // enter
73423
73424             var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
73425             enter.append('title').text(function (d) {
73426               var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
73427               return _t('mapillary_map_features.' + id);
73428             });
73429             enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
73430               if (d.value === 'object--billboard') {
73431                 // no billboard icon right now, so use the advertisement icon
73432                 return '#object--sign--advertisement';
73433               }
73434
73435               return '#' + d.value;
73436             });
73437             enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
73438
73439             mapFeatures.merge(enter).attr('transform', transform).classed('currentView', function (d) {
73440               return d.detections.some(function (detection) {
73441                 return detection.image_key === selectedImageKey;
73442               });
73443             }).sort(function (a, b) {
73444               var aSelected = a.detections.some(function (detection) {
73445                 return detection.image_key === selectedImageKey;
73446               });
73447               var bSelected = b.detections.some(function (detection) {
73448                 return detection.image_key === selectedImageKey;
73449               });
73450
73451               if (aSelected === bSelected) {
73452                 return b.loc[1] - a.loc[1]; // sort Y
73453               } else if (aSelected) {
73454                 return 1;
73455               }
73456
73457               return -1;
73458             });
73459           }
73460
73461           function drawMapFeatures(selection) {
73462             var enabled = svgMapillaryMapFeatures.enabled;
73463             var service = getService();
73464             layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
73465             layer.exit().remove();
73466             layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
73467
73468             if (enabled) {
73469               if (service && ~~context.map().zoom() >= minZoom) {
73470                 editOn();
73471                 update();
73472                 service.loadMapFeatures(projection);
73473                 service.showFeatureDetections(true);
73474               } else {
73475                 editOff();
73476               }
73477             } else if (service) {
73478               service.showFeatureDetections(false);
73479             }
73480           }
73481
73482           drawMapFeatures.enabled = function (_) {
73483             if (!arguments.length) return svgMapillaryMapFeatures.enabled;
73484             svgMapillaryMapFeatures.enabled = _;
73485
73486             if (svgMapillaryMapFeatures.enabled) {
73487               showLayer();
73488               context.photos().on('change.mapillary_map_features', update);
73489             } else {
73490               hideLayer();
73491               context.photos().on('change.mapillary_map_features', null);
73492             }
73493
73494             dispatch.call('change');
73495             return this;
73496           };
73497
73498           drawMapFeatures.supported = function () {
73499             return !!getService();
73500           };
73501
73502           init();
73503           return drawMapFeatures;
73504         }
73505
73506         function svgOpenstreetcamImages(projection, context, dispatch) {
73507           var throttledRedraw = throttle(function () {
73508             dispatch.call('change');
73509           }, 1000);
73510
73511           var minZoom = 12;
73512           var minMarkerZoom = 16;
73513           var minViewfieldZoom = 18;
73514           var layer = select(null);
73515
73516           var _openstreetcam;
73517
73518           function init() {
73519             if (svgOpenstreetcamImages.initialized) return; // run once
73520
73521             svgOpenstreetcamImages.enabled = false;
73522             svgOpenstreetcamImages.initialized = true;
73523           }
73524
73525           function getService() {
73526             if (services.openstreetcam && !_openstreetcam) {
73527               _openstreetcam = services.openstreetcam;
73528
73529               _openstreetcam.event.on('loadedImages', throttledRedraw);
73530             } else if (!services.openstreetcam && _openstreetcam) {
73531               _openstreetcam = null;
73532             }
73533
73534             return _openstreetcam;
73535           }
73536
73537           function showLayer() {
73538             var service = getService();
73539             if (!service) return;
73540             editOn();
73541             layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
73542               dispatch.call('change');
73543             });
73544           }
73545
73546           function hideLayer() {
73547             throttledRedraw.cancel();
73548             layer.transition().duration(250).style('opacity', 0).on('end', editOff);
73549           }
73550
73551           function editOn() {
73552             layer.style('display', 'block');
73553           }
73554
73555           function editOff() {
73556             layer.selectAll('.viewfield-group').remove();
73557             layer.style('display', 'none');
73558           }
73559
73560           function click(d3_event, d) {
73561             var service = getService();
73562             if (!service) return;
73563             service.ensureViewerLoaded(context).then(function () {
73564               service.selectImage(context, d.key).showViewer(context);
73565             });
73566             context.map().centerEase(d.loc);
73567           }
73568
73569           function mouseover(d3_event, d) {
73570             var service = getService();
73571             if (service) service.setStyles(context, d);
73572           }
73573
73574           function mouseout() {
73575             var service = getService();
73576             if (service) service.setStyles(context, null);
73577           }
73578
73579           function transform(d) {
73580             var t = svgPointTransform(projection)(d);
73581
73582             if (d.ca) {
73583               t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
73584             }
73585
73586             return t;
73587           }
73588
73589           function filterImages(images) {
73590             var fromDate = context.photos().fromDate();
73591             var toDate = context.photos().toDate();
73592             var usernames = context.photos().usernames();
73593
73594             if (fromDate) {
73595               var fromTimestamp = new Date(fromDate).getTime();
73596               images = images.filter(function (item) {
73597                 return new Date(item.captured_at).getTime() >= fromTimestamp;
73598               });
73599             }
73600
73601             if (toDate) {
73602               var toTimestamp = new Date(toDate).getTime();
73603               images = images.filter(function (item) {
73604                 return new Date(item.captured_at).getTime() <= toTimestamp;
73605               });
73606             }
73607
73608             if (usernames) {
73609               images = images.filter(function (item) {
73610                 return usernames.indexOf(item.captured_by) !== -1;
73611               });
73612             }
73613
73614             return images;
73615           }
73616
73617           function filterSequences(sequences) {
73618             var fromDate = context.photos().fromDate();
73619             var toDate = context.photos().toDate();
73620             var usernames = context.photos().usernames();
73621
73622             if (fromDate) {
73623               var fromTimestamp = new Date(fromDate).getTime();
73624               sequences = sequences.filter(function (image) {
73625                 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
73626               });
73627             }
73628
73629             if (toDate) {
73630               var toTimestamp = new Date(toDate).getTime();
73631               sequences = sequences.filter(function (image) {
73632                 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
73633               });
73634             }
73635
73636             if (usernames) {
73637               sequences = sequences.filter(function (image) {
73638                 return usernames.indexOf(image.properties.captured_by) !== -1;
73639               });
73640             }
73641
73642             return sequences;
73643           }
73644
73645           function update() {
73646             var viewer = context.container().select('.photoviewer');
73647             var selected = viewer.empty() ? undefined : viewer.datum();
73648             var z = ~~context.map().zoom();
73649             var showMarkers = z >= minMarkerZoom;
73650             var showViewfields = z >= minViewfieldZoom;
73651             var service = getService();
73652             var sequences = [];
73653             var images = [];
73654
73655             if (context.photos().showsFlat()) {
73656               sequences = service ? service.sequences(projection) : [];
73657               images = service && showMarkers ? service.images(projection) : [];
73658               sequences = filterSequences(sequences);
73659               images = filterImages(images);
73660             }
73661
73662             var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
73663               return d.properties.key;
73664             }); // exit
73665
73666             traces.exit().remove(); // enter/update
73667
73668             traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
73669             var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
73670               return d.key;
73671             }); // exit
73672
73673             groups.exit().remove(); // enter
73674
73675             var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
73676             groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
73677
73678             var markers = groups.merge(groupsEnter).sort(function (a, b) {
73679               return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
73680             }).attr('transform', transform).select('.viewfield-scale');
73681             markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
73682             var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
73683             viewfields.exit().remove();
73684             viewfields.enter() // viewfields may or may not be drawn...
73685             .insert('path', 'circle') // but if they are, draw below the circles
73686             .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');
73687           }
73688
73689           function drawImages(selection) {
73690             var enabled = svgOpenstreetcamImages.enabled,
73691                 service = getService();
73692             layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
73693             layer.exit().remove();
73694             var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
73695             layerEnter.append('g').attr('class', 'sequences');
73696             layerEnter.append('g').attr('class', 'markers');
73697             layer = layerEnter.merge(layer);
73698
73699             if (enabled) {
73700               if (service && ~~context.map().zoom() >= minZoom) {
73701                 editOn();
73702                 update();
73703                 service.loadImages(projection);
73704               } else {
73705                 editOff();
73706               }
73707             }
73708           }
73709
73710           drawImages.enabled = function (_) {
73711             if (!arguments.length) return svgOpenstreetcamImages.enabled;
73712             svgOpenstreetcamImages.enabled = _;
73713
73714             if (svgOpenstreetcamImages.enabled) {
73715               showLayer();
73716               context.photos().on('change.openstreetcam_images', update);
73717             } else {
73718               hideLayer();
73719               context.photos().on('change.openstreetcam_images', null);
73720             }
73721
73722             dispatch.call('change');
73723             return this;
73724           };
73725
73726           drawImages.supported = function () {
73727             return !!getService();
73728           };
73729
73730           init();
73731           return drawImages;
73732         }
73733
73734         function svgOsm(projection, context, dispatch) {
73735           var enabled = true;
73736
73737           function drawOsm(selection) {
73738             selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
73739               return 'layer-osm ' + d;
73740             });
73741             selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
73742               return 'points-group ' + d;
73743             });
73744           }
73745
73746           function showLayer() {
73747             var layer = context.surface().selectAll('.data-layer.osm');
73748             layer.interrupt();
73749             layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
73750               dispatch.call('change');
73751             });
73752           }
73753
73754           function hideLayer() {
73755             var layer = context.surface().selectAll('.data-layer.osm');
73756             layer.interrupt();
73757             layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
73758               layer.classed('disabled', true);
73759               dispatch.call('change');
73760             });
73761           }
73762
73763           drawOsm.enabled = function (val) {
73764             if (!arguments.length) return enabled;
73765             enabled = val;
73766
73767             if (enabled) {
73768               showLayer();
73769             } else {
73770               hideLayer();
73771             }
73772
73773             dispatch.call('change');
73774             return this;
73775           };
73776
73777           return drawOsm;
73778         }
73779
73780         var _notesEnabled = false;
73781
73782         var _osmService;
73783
73784         function svgNotes(projection, context, dispatch$1) {
73785           if (!dispatch$1) {
73786             dispatch$1 = dispatch('change');
73787           }
73788
73789           var throttledRedraw = throttle(function () {
73790             dispatch$1.call('change');
73791           }, 1000);
73792
73793           var minZoom = 12;
73794           var touchLayer = select(null);
73795           var drawLayer = select(null);
73796           var _notesVisible = false;
73797
73798           function markerPath(selection, klass) {
73799             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');
73800           } // Loosely-coupled osm service for fetching notes.
73801
73802
73803           function getService() {
73804             if (services.osm && !_osmService) {
73805               _osmService = services.osm;
73806
73807               _osmService.on('loadedNotes', throttledRedraw);
73808             } else if (!services.osm && _osmService) {
73809               _osmService = null;
73810             }
73811
73812             return _osmService;
73813           } // Show the notes
73814
73815
73816           function editOn() {
73817             if (!_notesVisible) {
73818               _notesVisible = true;
73819               drawLayer.style('display', 'block');
73820             }
73821           } // Immediately remove the notes and their touch targets
73822
73823
73824           function editOff() {
73825             if (_notesVisible) {
73826               _notesVisible = false;
73827               drawLayer.style('display', 'none');
73828               drawLayer.selectAll('.note').remove();
73829               touchLayer.selectAll('.note').remove();
73830             }
73831           } // Enable the layer.  This shows the notes and transitions them to visible.
73832
73833
73834           function layerOn() {
73835             editOn();
73836             drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
73837               dispatch$1.call('change');
73838             });
73839           } // Disable the layer.  This transitions the layer invisible and then hides the notes.
73840
73841
73842           function layerOff() {
73843             throttledRedraw.cancel();
73844             drawLayer.interrupt();
73845             touchLayer.selectAll('.note').remove();
73846             drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
73847               editOff();
73848               dispatch$1.call('change');
73849             });
73850           } // Update the note markers
73851
73852
73853           function updateMarkers() {
73854             if (!_notesVisible || !_notesEnabled) return;
73855             var service = getService();
73856             var selectedID = context.selectedNoteID();
73857             var data = service ? service.notes(projection) : [];
73858             var getTransform = svgPointTransform(projection); // Draw markers..
73859
73860             var notes = drawLayer.selectAll('.note').data(data, function (d) {
73861               return d.status + d.id;
73862             }); // exit
73863
73864             notes.exit().remove(); // enter
73865
73866             var notesEnter = notes.enter().append('g').attr('class', function (d) {
73867               return 'note note-' + d.id + ' ' + d.status;
73868             }).classed('new', function (d) {
73869               return d.id < 0;
73870             });
73871             notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
73872             notesEnter.append('path').call(markerPath, 'shadow');
73873             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');
73874             notesEnter.selectAll('.icon-annotation').data(function (d) {
73875               return [d];
73876             }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
73877               return '#iD-icon-' + (d.id < 0 ? 'plus' : d.status === 'open' ? 'close' : 'apply');
73878             }); // update
73879
73880             notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
73881               var mode = context.mode();
73882               var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
73883
73884               return !isMoving && d.id === selectedID;
73885             }).attr('transform', getTransform); // Draw targets..
73886
73887             if (touchLayer.empty()) return;
73888             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
73889             var targets = touchLayer.selectAll('.note').data(data, function (d) {
73890               return d.id;
73891             }); // exit
73892
73893             targets.exit().remove(); // enter/update
73894
73895             targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
73896               var newClass = d.id < 0 ? 'new' : '';
73897               return 'note target note-' + d.id + ' ' + fillClass + newClass;
73898             }).attr('transform', getTransform);
73899
73900             function sortY(a, b) {
73901               return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
73902             }
73903           } // Draw the notes layer and schedule loading notes and updating markers.
73904
73905
73906           function drawNotes(selection) {
73907             var service = getService();
73908             var surface = context.surface();
73909
73910             if (surface && !surface.empty()) {
73911               touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
73912             }
73913
73914             drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
73915             drawLayer.exit().remove();
73916             drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
73917
73918             if (_notesEnabled) {
73919               if (service && ~~context.map().zoom() >= minZoom) {
73920                 editOn();
73921                 service.loadNotes(projection);
73922                 updateMarkers();
73923               } else {
73924                 editOff();
73925               }
73926             }
73927           } // Toggles the layer on and off
73928
73929
73930           drawNotes.enabled = function (val) {
73931             if (!arguments.length) return _notesEnabled;
73932             _notesEnabled = val;
73933
73934             if (_notesEnabled) {
73935               layerOn();
73936             } else {
73937               layerOff();
73938
73939               if (context.selectedNoteID()) {
73940                 context.enter(modeBrowse(context));
73941               }
73942             }
73943
73944             dispatch$1.call('change');
73945             return this;
73946           };
73947
73948           return drawNotes;
73949         }
73950
73951         function svgTouch() {
73952           function drawTouch(selection) {
73953             selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
73954               return 'layer-touch ' + d;
73955             });
73956           }
73957
73958           return drawTouch;
73959         }
73960
73961         function refresh(selection, node) {
73962           var cr = node.getBoundingClientRect();
73963           var prop = [cr.width, cr.height];
73964           selection.property('__dimensions__', prop);
73965           return prop;
73966         }
73967
73968         function utilGetDimensions(selection, force) {
73969           if (!selection || selection.empty()) {
73970             return [0, 0];
73971           }
73972
73973           var node = selection.node(),
73974               cached = selection.property('__dimensions__');
73975           return !cached || force ? refresh(selection, node) : cached;
73976         }
73977         function utilSetDimensions(selection, dimensions) {
73978           if (!selection || selection.empty()) {
73979             return selection;
73980           }
73981
73982           var node = selection.node();
73983
73984           if (dimensions === null) {
73985             refresh(selection, node);
73986             return selection;
73987           }
73988
73989           return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
73990         }
73991
73992         function svgLayers(projection, context) {
73993           var dispatch$1 = dispatch('change');
73994           var svg = select(null);
73995           var _layers = [{
73996             id: 'osm',
73997             layer: svgOsm(projection, context, dispatch$1)
73998           }, {
73999             id: 'notes',
74000             layer: svgNotes(projection, context, dispatch$1)
74001           }, {
74002             id: 'data',
74003             layer: svgData(projection, context, dispatch$1)
74004           }, {
74005             id: 'keepRight',
74006             layer: svgKeepRight(projection, context, dispatch$1)
74007           }, {
74008             id: 'improveOSM',
74009             layer: svgImproveOSM(projection, context, dispatch$1)
74010           }, {
74011             id: 'osmose',
74012             layer: svgOsmose(projection, context, dispatch$1)
74013           }, {
74014             id: 'streetside',
74015             layer: svgStreetside(projection, context, dispatch$1)
74016           }, {
74017             id: 'mapillary',
74018             layer: svgMapillaryImages(projection, context, dispatch$1)
74019           }, {
74020             id: 'mapillary-position',
74021             layer: svgMapillaryPosition(projection, context)
74022           }, {
74023             id: 'mapillary-map-features',
74024             layer: svgMapillaryMapFeatures(projection, context, dispatch$1)
74025           }, {
74026             id: 'mapillary-signs',
74027             layer: svgMapillarySigns(projection, context, dispatch$1)
74028           }, {
74029             id: 'openstreetcam',
74030             layer: svgOpenstreetcamImages(projection, context, dispatch$1)
74031           }, {
74032             id: 'debug',
74033             layer: svgDebug(projection, context)
74034           }, {
74035             id: 'geolocate',
74036             layer: svgGeolocate(projection)
74037           }, {
74038             id: 'touch',
74039             layer: svgTouch()
74040           }];
74041
74042           function drawLayers(selection) {
74043             svg = selection.selectAll('.surface').data([0]);
74044             svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
74045             var defs = svg.selectAll('.surface-defs').data([0]);
74046             defs.enter().append('defs').attr('class', 'surface-defs');
74047             var groups = svg.selectAll('.data-layer').data(_layers);
74048             groups.exit().remove();
74049             groups.enter().append('g').attr('class', function (d) {
74050               return 'data-layer ' + d.id;
74051             }).merge(groups).each(function (d) {
74052               select(this).call(d.layer);
74053             });
74054           }
74055
74056           drawLayers.all = function () {
74057             return _layers;
74058           };
74059
74060           drawLayers.layer = function (id) {
74061             var obj = _layers.find(function (o) {
74062               return o.id === id;
74063             });
74064
74065             return obj && obj.layer;
74066           };
74067
74068           drawLayers.only = function (what) {
74069             var arr = [].concat(what);
74070
74071             var all = _layers.map(function (layer) {
74072               return layer.id;
74073             });
74074
74075             return drawLayers.remove(utilArrayDifference(all, arr));
74076           };
74077
74078           drawLayers.remove = function (what) {
74079             var arr = [].concat(what);
74080             arr.forEach(function (id) {
74081               _layers = _layers.filter(function (o) {
74082                 return o.id !== id;
74083               });
74084             });
74085             dispatch$1.call('change');
74086             return this;
74087           };
74088
74089           drawLayers.add = function (what) {
74090             var arr = [].concat(what);
74091             arr.forEach(function (obj) {
74092               if ('id' in obj && 'layer' in obj) {
74093                 _layers.push(obj);
74094               }
74095             });
74096             dispatch$1.call('change');
74097             return this;
74098           };
74099
74100           drawLayers.dimensions = function (val) {
74101             if (!arguments.length) return utilGetDimensions(svg);
74102             utilSetDimensions(svg, val);
74103             return this;
74104           };
74105
74106           return utilRebind(drawLayers, dispatch$1, 'on');
74107         }
74108
74109         function svgLines(projection, context) {
74110           var detected = utilDetect();
74111           var highway_stack = {
74112             motorway: 0,
74113             motorway_link: 1,
74114             trunk: 2,
74115             trunk_link: 3,
74116             primary: 4,
74117             primary_link: 5,
74118             secondary: 6,
74119             tertiary: 7,
74120             unclassified: 8,
74121             residential: 9,
74122             service: 10,
74123             footway: 11
74124           };
74125
74126           function drawTargets(selection, graph, entities, filter) {
74127             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74128             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
74129             var getPath = svgPath(projection).geojson;
74130             var activeID = context.activeID();
74131             var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
74132
74133             var data = {
74134               targets: [],
74135               nopes: []
74136             };
74137             entities.forEach(function (way) {
74138               var features = svgSegmentWay(way, graph, activeID);
74139               data.targets.push.apply(data.targets, features.passive);
74140               data.nopes.push.apply(data.nopes, features.active);
74141             }); // Targets allow hover and vertex snapping
74142
74143             var targetData = data.targets.filter(getPath);
74144             var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
74145               return filter(d.properties.entity);
74146             }).data(targetData, function key(d) {
74147               return d.id;
74148             }); // exit
74149
74150             targets.exit().remove();
74151
74152             var segmentWasEdited = function segmentWasEdited(d) {
74153               var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
74154
74155               if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
74156                 return false;
74157               }
74158
74159               return d.properties.nodes.some(function (n) {
74160                 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
74161               });
74162             }; // enter/update
74163
74164
74165             targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
74166               return 'way line target target-allowed ' + targetClass + d.id;
74167             }).classed('segment-edited', segmentWasEdited); // NOPE
74168
74169             var nopeData = data.nopes.filter(getPath);
74170             var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
74171               return filter(d.properties.entity);
74172             }).data(nopeData, function key(d) {
74173               return d.id;
74174             }); // exit
74175
74176             nopes.exit().remove(); // enter/update
74177
74178             nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
74179               return 'way line target target-nope ' + nopeClass + d.id;
74180             }).classed('segment-edited', segmentWasEdited);
74181           }
74182
74183           function drawLines(selection, graph, entities, filter) {
74184             var base = context.history().base();
74185
74186             function waystack(a, b) {
74187               var selected = context.selectedIDs();
74188               var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
74189               var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
74190
74191               if (a.tags.highway) {
74192                 scoreA -= highway_stack[a.tags.highway];
74193               }
74194
74195               if (b.tags.highway) {
74196                 scoreB -= highway_stack[b.tags.highway];
74197               }
74198
74199               return scoreA - scoreB;
74200             }
74201
74202             function drawLineGroup(selection, klass, isSelected) {
74203               // Note: Don't add `.selected` class in draw modes
74204               var mode = context.mode();
74205               var isDrawing = mode && /^draw/.test(mode.id);
74206               var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
74207               var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
74208               lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
74209               // works because osmEntity.key is defined to include the entity v attribute.
74210
74211               lines.enter().append('path').attr('class', function (d) {
74212                 var prefix = 'way line'; // if this line isn't styled by its own tags
74213
74214                 if (!d.hasInterestingTags()) {
74215                   var parentRelations = graph.parentRelations(d);
74216                   var parentMultipolygons = parentRelations.filter(function (relation) {
74217                     return relation.isMultipolygon();
74218                   }); // and if it's a member of at least one multipolygon relation
74219
74220                   if (parentMultipolygons.length > 0 && // and only multipolygon relations
74221                   parentRelations.length === parentMultipolygons.length) {
74222                     // then fudge the classes to style this as an area edge
74223                     prefix = 'relation area';
74224                   }
74225                 }
74226
74227                 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
74228                 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
74229               }).classed('added', function (d) {
74230                 return !base.entities[d.id];
74231               }).classed('geometry-edited', function (d) {
74232                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
74233               }).classed('retagged', function (d) {
74234                 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74235               }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
74236               return selection;
74237             }
74238
74239             function getPathData(isSelected) {
74240               return function () {
74241                 var layer = this.parentNode.__data__;
74242                 var data = pathdata[layer] || [];
74243                 return data.filter(function (d) {
74244                   if (isSelected) return context.selectedIDs().indexOf(d.id) !== -1;else return context.selectedIDs().indexOf(d.id) === -1;
74245                 });
74246               };
74247             }
74248
74249             function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
74250               var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
74251               markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
74252               var markers = markergroup.selectAll('path').filter(filter).data(function data() {
74253                 return groupdata[this.parentNode.__data__] || [];
74254               }, function key(d) {
74255                 return [d.id, d.index];
74256               });
74257               markers.exit().remove();
74258               markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
74259                 return d.d;
74260               });
74261
74262               if (detected.ie) {
74263                 markers.each(function () {
74264                   this.parentNode.insertBefore(this, this);
74265                 });
74266               }
74267             }
74268
74269             var getPath = svgPath(projection, graph);
74270             var ways = [];
74271             var onewaydata = {};
74272             var sideddata = {};
74273             var oldMultiPolygonOuters = {};
74274
74275             for (var i = 0; i < entities.length; i++) {
74276               var entity = entities[i];
74277               var outer = osmOldMultipolygonOuterMember(entity, graph);
74278
74279               if (outer) {
74280                 ways.push(entity.mergeTags(outer.tags));
74281                 oldMultiPolygonOuters[outer.id] = true;
74282               } else if (entity.geometry(graph) === 'line') {
74283                 ways.push(entity);
74284               }
74285             }
74286
74287             ways = ways.filter(getPath);
74288             var pathdata = utilArrayGroupBy(ways, function (way) {
74289               return way.layer();
74290             });
74291             Object.keys(pathdata).forEach(function (k) {
74292               var v = pathdata[k];
74293               var onewayArr = v.filter(function (d) {
74294                 return d.isOneWay();
74295               });
74296               var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
74297                 return entity.tags.oneway === '-1';
74298               }, function bothDirections(entity) {
74299                 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
74300               });
74301               onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
74302               var sidedArr = v.filter(function (d) {
74303                 return d.isSided();
74304               });
74305               var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
74306                 return false;
74307               }, function bothDirections() {
74308                 return false;
74309               });
74310               sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
74311             });
74312             var covered = selection.selectAll('.layer-osm.covered'); // under areas
74313
74314             var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
74315
74316             var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
74317
74318             [covered, uncovered].forEach(function (selection) {
74319               var range$1 = selection === covered ? range(-10, 0) : range(0, 11);
74320               var layergroup = selection.selectAll('g.layergroup').data(range$1);
74321               layergroup = layergroup.enter().append('g').attr('class', function (d) {
74322                 return 'layergroup layer' + String(d);
74323               }).merge(layergroup);
74324               layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
74325                 return 'linegroup line-' + d;
74326               });
74327               layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
74328               layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
74329               layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
74330               layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
74331               layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
74332               layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
74333               addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
74334               addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
74335                 var category = graph.entity(d.id).sidednessIdentifier();
74336                 return 'url(#ideditor-sided-marker-' + category + ')';
74337               });
74338             }); // Draw touch targets..
74339
74340             touchLayer.call(drawTargets, graph, ways, filter);
74341           }
74342
74343           return drawLines;
74344         }
74345
74346         function svgMidpoints(projection, context) {
74347           var targetRadius = 8;
74348
74349           function drawTargets(selection, graph, entities, filter) {
74350             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74351             var getTransform = svgPointTransform(projection).geojson;
74352             var data = entities.map(function (midpoint) {
74353               return {
74354                 type: 'Feature',
74355                 id: midpoint.id,
74356                 properties: {
74357                   target: true,
74358                   entity: midpoint
74359                 },
74360                 geometry: {
74361                   type: 'Point',
74362                   coordinates: midpoint.loc
74363                 }
74364               };
74365             });
74366             var targets = selection.selectAll('.midpoint.target').filter(function (d) {
74367               return filter(d.properties.entity);
74368             }).data(data, function key(d) {
74369               return d.id;
74370             }); // exit
74371
74372             targets.exit().remove(); // enter/update
74373
74374             targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
74375               return 'node midpoint target ' + fillClass + d.id;
74376             }).attr('transform', getTransform);
74377           }
74378
74379           function drawMidpoints(selection, graph, entities, filter, extent) {
74380             var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
74381             var touchLayer = selection.selectAll('.layer-touch.points');
74382             var mode = context.mode();
74383
74384             if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
74385               drawLayer.selectAll('.midpoint').remove();
74386               touchLayer.selectAll('.midpoint.target').remove();
74387               return;
74388             }
74389
74390             var poly = extent.polygon();
74391             var midpoints = {};
74392
74393             for (var i = 0; i < entities.length; i++) {
74394               var entity = entities[i];
74395               if (entity.type !== 'way') continue;
74396               if (!filter(entity)) continue;
74397               if (context.selectedIDs().indexOf(entity.id) < 0) continue;
74398               var nodes = graph.childNodes(entity);
74399
74400               for (var j = 0; j < nodes.length - 1; j++) {
74401                 var a = nodes[j];
74402                 var b = nodes[j + 1];
74403                 var id = [a.id, b.id].sort().join('-');
74404
74405                 if (midpoints[id]) {
74406                   midpoints[id].parents.push(entity);
74407                 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
74408                   var point = geoVecInterp(a.loc, b.loc, 0.5);
74409                   var loc = null;
74410
74411                   if (extent.intersects(point)) {
74412                     loc = point;
74413                   } else {
74414                     for (var k = 0; k < 4; k++) {
74415                       point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
74416
74417                       if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
74418                         loc = point;
74419                         break;
74420                       }
74421                     }
74422                   }
74423
74424                   if (loc) {
74425                     midpoints[id] = {
74426                       type: 'midpoint',
74427                       id: id,
74428                       loc: loc,
74429                       edge: [a.id, b.id],
74430                       parents: [entity]
74431                     };
74432                   }
74433                 }
74434               }
74435             }
74436
74437             function midpointFilter(d) {
74438               if (midpoints[d.id]) return true;
74439
74440               for (var i = 0; i < d.parents.length; i++) {
74441                 if (filter(d.parents[i])) {
74442                   return true;
74443                 }
74444               }
74445
74446               return false;
74447             }
74448
74449             var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
74450               return d.id;
74451             });
74452             groups.exit().remove();
74453             var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
74454             enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
74455             enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
74456             groups = groups.merge(enter).attr('transform', function (d) {
74457               var translate = svgPointTransform(projection);
74458               var a = graph.entity(d.edge[0]);
74459               var b = graph.entity(d.edge[1]);
74460               var angle = geoAngle(a, b, projection) * (180 / Math.PI);
74461               return translate(d) + ' rotate(' + angle + ')';
74462             }).call(svgTagClasses().tags(function (d) {
74463               return d.parents[0].tags;
74464             })); // Propagate data bindings.
74465
74466             groups.select('polygon.shadow');
74467             groups.select('polygon.fill'); // Draw touch targets..
74468
74469             touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
74470           }
74471
74472           return drawMidpoints;
74473         }
74474
74475         function svgPoints(projection, context) {
74476           function markerPath(selection, klass) {
74477             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');
74478           }
74479
74480           function sortY(a, b) {
74481             return b.loc[1] - a.loc[1];
74482           } // Avoid exit/enter if we're just moving stuff around.
74483           // The node will get a new version but we only need to run the update selection.
74484
74485
74486           function fastEntityKey(d) {
74487             var mode = context.mode();
74488             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74489             return isMoving ? d.id : osmEntity.key(d);
74490           }
74491
74492           function drawTargets(selection, graph, entities, filter) {
74493             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74494             var getTransform = svgPointTransform(projection).geojson;
74495             var activeID = context.activeID();
74496             var data = [];
74497             entities.forEach(function (node) {
74498               if (activeID === node.id) return; // draw no target on the activeID
74499
74500               data.push({
74501                 type: 'Feature',
74502                 id: node.id,
74503                 properties: {
74504                   target: true,
74505                   entity: node
74506                 },
74507                 geometry: node.asGeoJSON()
74508               });
74509             });
74510             var targets = selection.selectAll('.point.target').filter(function (d) {
74511               return filter(d.properties.entity);
74512             }).data(data, function key(d) {
74513               return d.id;
74514             }); // exit
74515
74516             targets.exit().remove(); // enter/update
74517
74518             targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
74519               return 'node point target ' + fillClass + d.id;
74520             }).attr('transform', getTransform);
74521           }
74522
74523           function drawPoints(selection, graph, entities, filter) {
74524             var wireframe = context.surface().classed('fill-wireframe');
74525             var zoom = geoScaleToZoom(projection.scale());
74526             var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
74527
74528             function renderAsPoint(entity) {
74529               return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
74530             } // All points will render as vertices in wireframe mode too..
74531
74532
74533             var points = wireframe ? [] : entities.filter(renderAsPoint);
74534             points.sort(sortY);
74535             var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
74536             var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
74537
74538             var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
74539             groups.exit().remove();
74540             var enter = groups.enter().append('g').attr('class', function (d) {
74541               return 'node point ' + d.id;
74542             }).order();
74543             enter.append('path').call(markerPath, 'shadow');
74544             enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
74545             enter.append('path').call(markerPath, 'stroke');
74546             enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
74547             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
74548               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
74549             }).classed('moved', function (d) {
74550               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
74551             }).classed('retagged', function (d) {
74552               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74553             }).call(svgTagClasses());
74554             groups.select('.shadow'); // propagate bound data
74555
74556             groups.select('.stroke'); // propagate bound data
74557
74558             groups.select('.icon') // propagate bound data
74559             .attr('xlink:href', function (entity) {
74560               var preset = _mainPresetIndex.match(entity, graph);
74561               var picon = preset && preset.icon;
74562
74563               if (!picon) {
74564                 return '';
74565               } else {
74566                 var isMaki = /^maki-/.test(picon);
74567                 return '#' + picon + (isMaki ? '-11' : '');
74568               }
74569             }); // Draw touch targets..
74570
74571             touchLayer.call(drawTargets, graph, points, filter);
74572           }
74573
74574           return drawPoints;
74575         }
74576
74577         function svgTurns(projection, context) {
74578           function icon(turn) {
74579             var u = turn.u ? '-u' : '';
74580             if (turn.no) return '#iD-turn-no' + u;
74581             if (turn.only) return '#iD-turn-only' + u;
74582             return '#iD-turn-yes' + u;
74583           }
74584
74585           function drawTurns(selection, graph, turns) {
74586             function turnTransform(d) {
74587               var pxRadius = 50;
74588               var toWay = graph.entity(d.to.way);
74589               var toPoints = graph.childNodes(toWay).map(function (n) {
74590                 return n.loc;
74591               }).map(projection);
74592               var toLength = geoPathLength(toPoints);
74593               var mid = toLength / 2; // midpoint of destination way
74594
74595               var toNode = graph.entity(d.to.node);
74596               var toVertex = graph.entity(d.to.vertex);
74597               var a = geoAngle(toVertex, toNode, projection);
74598               var o = projection(toVertex.loc);
74599               var r = d.u ? 0 // u-turn: no radius
74600               : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
74601               : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
74602
74603               return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
74604             }
74605
74606             var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
74607             var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
74608
74609             var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
74610               return d.key;
74611             }); // exit
74612
74613             groups.exit().remove(); // enter
74614
74615             var groupsEnter = groups.enter().append('g').attr('class', function (d) {
74616               return 'turn ' + d.key;
74617             });
74618             var turnsEnter = groupsEnter.filter(function (d) {
74619               return !d.u;
74620             });
74621             turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74622             turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74623             var uEnter = groupsEnter.filter(function (d) {
74624               return d.u;
74625             });
74626             uEnter.append('circle').attr('r', '16');
74627             uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
74628
74629             groups = groups.merge(groupsEnter).attr('opacity', function (d) {
74630               return d.direct === false ? '0.7' : null;
74631             }).attr('transform', turnTransform);
74632             groups.select('use').attr('xlink:href', icon);
74633             groups.select('rect'); // propagate bound data
74634
74635             groups.select('circle'); // propagate bound data
74636             // Draw touch targets..
74637
74638             var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74639             groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
74640               return d.key;
74641             }); // exit
74642
74643             groups.exit().remove(); // enter
74644
74645             groupsEnter = groups.enter().append('g').attr('class', function (d) {
74646               return 'turn ' + d.key;
74647             });
74648             turnsEnter = groupsEnter.filter(function (d) {
74649               return !d.u;
74650             });
74651             turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
74652             uEnter = groupsEnter.filter(function (d) {
74653               return d.u;
74654             });
74655             uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
74656
74657             groups = groups.merge(groupsEnter).attr('transform', turnTransform);
74658             groups.select('rect'); // propagate bound data
74659
74660             groups.select('circle'); // propagate bound data
74661
74662             return this;
74663           }
74664
74665           return drawTurns;
74666         }
74667
74668         function svgVertices(projection, context) {
74669           var radiuses = {
74670             //       z16-, z17,   z18+,  w/icon
74671             shadow: [6, 7.5, 7.5, 12],
74672             stroke: [2.5, 3.5, 3.5, 8],
74673             fill: [1, 1.5, 1.5, 1.5]
74674           };
74675
74676           var _currHoverTarget;
74677
74678           var _currPersistent = {};
74679           var _currHover = {};
74680           var _prevHover = {};
74681           var _currSelected = {};
74682           var _prevSelected = {};
74683           var _radii = {};
74684
74685           function sortY(a, b) {
74686             return b.loc[1] - a.loc[1];
74687           } // Avoid exit/enter if we're just moving stuff around.
74688           // The node will get a new version but we only need to run the update selection.
74689
74690
74691           function fastEntityKey(d) {
74692             var mode = context.mode();
74693             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74694             return isMoving ? d.id : osmEntity.key(d);
74695           }
74696
74697           function draw(selection, graph, vertices, sets, filter) {
74698             sets = sets || {
74699               selected: {},
74700               important: {},
74701               hovered: {}
74702             };
74703             var icons = {};
74704             var directions = {};
74705             var wireframe = context.surface().classed('fill-wireframe');
74706             var zoom = geoScaleToZoom(projection.scale());
74707             var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
74708             var activeID = context.activeID();
74709             var base = context.history().base();
74710
74711             function getIcon(d) {
74712               // always check latest entity, as fastEntityKey avoids enter/exit now
74713               var entity = graph.entity(d.id);
74714               if (entity.id in icons) return icons[entity.id];
74715               icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
74716               return icons[entity.id];
74717             } // memoize directions results, return false for empty arrays (for use in filter)
74718
74719
74720             function getDirections(entity) {
74721               if (entity.id in directions) return directions[entity.id];
74722               var angles = entity.directions(graph, projection);
74723               directions[entity.id] = angles.length ? angles : false;
74724               return angles;
74725             }
74726
74727             function updateAttributes(selection) {
74728               ['shadow', 'stroke', 'fill'].forEach(function (klass) {
74729                 var rads = radiuses[klass];
74730                 selection.selectAll('.' + klass).each(function (entity) {
74731                   var i = z && getIcon(entity);
74732                   var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
74733
74734                   if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
74735                     r += 1.5;
74736                   }
74737
74738                   if (klass === 'shadow') {
74739                     // remember this value, so we don't need to
74740                     _radii[entity.id] = r; // recompute it when we draw the touch targets
74741                   }
74742
74743                   select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
74744                 });
74745               });
74746             }
74747
74748             vertices.sort(sortY);
74749             var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
74750
74751             groups.exit().remove(); // enter
74752
74753             var enter = groups.enter().append('g').attr('class', function (d) {
74754               return 'node vertex ' + d.id;
74755             }).order();
74756             enter.append('circle').attr('class', 'shadow');
74757             enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
74758
74759             enter.filter(function (d) {
74760               return d.hasInterestingTags();
74761             }).append('circle').attr('class', 'fill'); // update
74762
74763             groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
74764               return d.id in sets.selected;
74765             }).classed('shared', function (d) {
74766               return graph.isShared(d);
74767             }).classed('endpoint', function (d) {
74768               return d.isEndpoint(graph);
74769             }).classed('added', function (d) {
74770               return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
74771             }).classed('moved', function (d) {
74772               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
74773             }).classed('retagged', function (d) {
74774               return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
74775             }).call(updateAttributes); // Vertices with icons get a `use`.
74776
74777             var iconUse = groups.selectAll('.icon').data(function data(d) {
74778               return zoom >= 17 && getIcon(d) ? [d] : [];
74779             }, fastEntityKey); // exit
74780
74781             iconUse.exit().remove(); // enter
74782
74783             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) {
74784               var picon = getIcon(d);
74785               var isMaki = /^maki-/.test(picon);
74786               return '#' + picon + (isMaki ? '-11' : '');
74787             }); // Vertices with directions get viewfields
74788
74789             var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
74790               return zoom >= 18 && getDirections(d) ? [d] : [];
74791             }, fastEntityKey); // exit
74792
74793             dgroups.exit().remove(); // enter/update
74794
74795             dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
74796             var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
74797               return osmEntity.key(d);
74798             }); // exit
74799
74800             viewfields.exit().remove(); // enter/update
74801
74802             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) {
74803               return 'rotate(' + d + ')';
74804             });
74805           }
74806
74807           function drawTargets(selection, graph, entities, filter) {
74808             var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
74809             var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
74810             var getTransform = svgPointTransform(projection).geojson;
74811             var activeID = context.activeID();
74812             var data = {
74813               targets: [],
74814               nopes: []
74815             };
74816             entities.forEach(function (node) {
74817               if (activeID === node.id) return; // draw no target on the activeID
74818
74819               var vertexType = svgPassiveVertex(node, graph, activeID);
74820
74821               if (vertexType !== 0) {
74822                 // passive or adjacent - allow to connect
74823                 data.targets.push({
74824                   type: 'Feature',
74825                   id: node.id,
74826                   properties: {
74827                     target: true,
74828                     entity: node
74829                   },
74830                   geometry: node.asGeoJSON()
74831                 });
74832               } else {
74833                 data.nopes.push({
74834                   type: 'Feature',
74835                   id: node.id + '-nope',
74836                   properties: {
74837                     nope: true,
74838                     target: true,
74839                     entity: node
74840                   },
74841                   geometry: node.asGeoJSON()
74842                 });
74843               }
74844             }); // Targets allow hover and vertex snapping
74845
74846             var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
74847               return filter(d.properties.entity);
74848             }).data(data.targets, function key(d) {
74849               return d.id;
74850             }); // exit
74851
74852             targets.exit().remove(); // enter/update
74853
74854             targets.enter().append('circle').attr('r', function (d) {
74855               return _radii[d.id] || radiuses.shadow[3];
74856             }).merge(targets).attr('class', function (d) {
74857               return 'node vertex target target-allowed ' + targetClass + d.id;
74858             }).attr('transform', getTransform); // NOPE
74859
74860             var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
74861               return filter(d.properties.entity);
74862             }).data(data.nopes, function key(d) {
74863               return d.id;
74864             }); // exit
74865
74866             nopes.exit().remove(); // enter/update
74867
74868             nopes.enter().append('circle').attr('r', function (d) {
74869               return _radii[d.properties.entity.id] || radiuses.shadow[3];
74870             }).merge(nopes).attr('class', function (d) {
74871               return 'node vertex target target-nope ' + nopeClass + d.id;
74872             }).attr('transform', getTransform);
74873           } // Points can also render as vertices:
74874           // 1. in wireframe mode or
74875           // 2. at higher zooms if they have a direction
74876
74877
74878           function renderAsVertex(entity, graph, wireframe, zoom) {
74879             var geometry = entity.geometry(graph);
74880             return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
74881           }
74882
74883           function isEditedNode(node, base, head) {
74884             var baseNode = base.entities[node.id];
74885             var headNode = head.entities[node.id];
74886             return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
74887           }
74888
74889           function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
74890             var results = {};
74891             var seenIds = {};
74892
74893             function addChildVertices(entity) {
74894               // avoid redundant work and infinite recursion of circular relations
74895               if (seenIds[entity.id]) return;
74896               seenIds[entity.id] = true;
74897               var geometry = entity.geometry(graph);
74898
74899               if (!context.features().isHiddenFeature(entity, graph, geometry)) {
74900                 var i;
74901
74902                 if (entity.type === 'way') {
74903                   for (i = 0; i < entity.nodes.length; i++) {
74904                     var child = graph.hasEntity(entity.nodes[i]);
74905
74906                     if (child) {
74907                       addChildVertices(child);
74908                     }
74909                   }
74910                 } else if (entity.type === 'relation') {
74911                   for (i = 0; i < entity.members.length; i++) {
74912                     var member = graph.hasEntity(entity.members[i].id);
74913
74914                     if (member) {
74915                       addChildVertices(member);
74916                     }
74917                   }
74918                 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
74919                   results[entity.id] = entity;
74920                 }
74921               }
74922             }
74923
74924             ids.forEach(function (id) {
74925               var entity = graph.hasEntity(id);
74926               if (!entity) return;
74927
74928               if (entity.type === 'node') {
74929                 if (renderAsVertex(entity, graph, wireframe, zoom)) {
74930                   results[entity.id] = entity;
74931                   graph.parentWays(entity).forEach(function (entity) {
74932                     addChildVertices(entity);
74933                   });
74934                 }
74935               } else {
74936                 // way, relation
74937                 addChildVertices(entity);
74938               }
74939             });
74940             return results;
74941           }
74942
74943           function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
74944             var wireframe = context.surface().classed('fill-wireframe');
74945             var visualDiff = context.surface().classed('highlight-edited');
74946             var zoom = geoScaleToZoom(projection.scale());
74947             var mode = context.mode();
74948             var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
74949             var base = context.history().base();
74950             var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
74951             var touchLayer = selection.selectAll('.layer-touch.points');
74952
74953             if (fullRedraw) {
74954               _currPersistent = {};
74955               _radii = {};
74956             } // Collect important vertices from the `entities` list..
74957             // (during a partial redraw, it will not contain everything)
74958
74959
74960             for (var i = 0; i < entities.length; i++) {
74961               var entity = entities[i];
74962               var geometry = entity.geometry(graph);
74963               var keep = false; // a point that looks like a vertex..
74964
74965               if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
74966                 _currPersistent[entity.id] = entity;
74967                 keep = true; // a vertex of some importance..
74968               } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
74969                 _currPersistent[entity.id] = entity;
74970                 keep = true;
74971               } // whatever this is, it's not a persistent vertex..
74972
74973
74974               if (!keep && !fullRedraw) {
74975                 delete _currPersistent[entity.id];
74976               }
74977             } // 3 sets of vertices to consider:
74978
74979
74980             var sets = {
74981               persistent: _currPersistent,
74982               // persistent = important vertices (render always)
74983               selected: _currSelected,
74984               // selected + siblings of selected (render always)
74985               hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
74986
74987             };
74988             var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
74989             // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
74990             // Adjust the filter function to expand the scope beyond whatever entities were passed in.
74991
74992             var filterRendered = function filterRendered(d) {
74993               return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
74994             };
74995
74996             drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
74997             // When drawing, render all targets (not just those affected by a partial redraw)
74998
74999             var filterTouch = function filterTouch(d) {
75000               return isMoving ? true : filterRendered(d);
75001             };
75002
75003             touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
75004
75005             function currentVisible(which) {
75006               return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
75007               .filter(function (entity) {
75008                 return entity && entity.intersects(extent, graph);
75009               });
75010             }
75011           } // partial redraw - only update the selected items..
75012
75013
75014           drawVertices.drawSelected = function (selection, graph, extent) {
75015             var wireframe = context.surface().classed('fill-wireframe');
75016             var zoom = geoScaleToZoom(projection.scale());
75017             _prevSelected = _currSelected || {};
75018
75019             if (context.map().isInWideSelection()) {
75020               _currSelected = {};
75021               context.selectedIDs().forEach(function (id) {
75022                 var entity = graph.hasEntity(id);
75023                 if (!entity) return;
75024
75025                 if (entity.type === 'node') {
75026                   if (renderAsVertex(entity, graph, wireframe, zoom)) {
75027                     _currSelected[entity.id] = entity;
75028                   }
75029                 }
75030               });
75031             } else {
75032               _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
75033             } // note that drawVertices will add `_currSelected` automatically if needed..
75034
75035
75036             var filter = function filter(d) {
75037               return d.id in _prevSelected;
75038             };
75039
75040             drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
75041           }; // partial redraw - only update the hovered items..
75042
75043
75044           drawVertices.drawHover = function (selection, graph, target, extent) {
75045             if (target === _currHoverTarget) return; // continue only if something changed
75046
75047             var wireframe = context.surface().classed('fill-wireframe');
75048             var zoom = geoScaleToZoom(projection.scale());
75049             _prevHover = _currHover || {};
75050             _currHoverTarget = target;
75051             var entity = target && target.properties && target.properties.entity;
75052
75053             if (entity) {
75054               _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
75055             } else {
75056               _currHover = {};
75057             } // note that drawVertices will add `_currHover` automatically if needed..
75058
75059
75060             var filter = function filter(d) {
75061               return d.id in _prevHover;
75062             };
75063
75064             drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
75065           };
75066
75067           return drawVertices;
75068         }
75069
75070         function utilBindOnce(target, type, listener, capture) {
75071           var typeOnce = type + '.once';
75072
75073           function one() {
75074             target.on(typeOnce, null);
75075             listener.apply(this, arguments);
75076           }
75077
75078           target.on(typeOnce, one, capture);
75079           return this;
75080         }
75081
75082         function defaultFilter$2(d3_event) {
75083           return !d3_event.ctrlKey && !d3_event.button;
75084         }
75085
75086         function defaultExtent$1() {
75087           var e = this;
75088
75089           if (e instanceof SVGElement) {
75090             e = e.ownerSVGElement || e;
75091
75092             if (e.hasAttribute('viewBox')) {
75093               e = e.viewBox.baseVal;
75094               return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
75095             }
75096
75097             return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
75098           }
75099
75100           return [[0, 0], [e.clientWidth, e.clientHeight]];
75101         }
75102
75103         function defaultWheelDelta$1(d3_event) {
75104           return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
75105         }
75106
75107         function defaultConstrain$1(transform, extent, translateExtent) {
75108           var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
75109               dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
75110               dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
75111               dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
75112           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));
75113         }
75114
75115         function utilZoomPan() {
75116           var filter = defaultFilter$2,
75117               extent = defaultExtent$1,
75118               constrain = defaultConstrain$1,
75119               wheelDelta = defaultWheelDelta$1,
75120               scaleExtent = [0, Infinity],
75121               translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
75122               interpolate = interpolateZoom,
75123               dispatch$1 = dispatch('start', 'zoom', 'end'),
75124               _wheelDelay = 150,
75125               _transform = identity$2,
75126               _activeGesture;
75127
75128           function zoom(selection) {
75129             selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
75130             select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
75131           }
75132
75133           zoom.transform = function (collection, transform, point) {
75134             var selection = collection.selection ? collection.selection() : collection;
75135
75136             if (collection !== selection) {
75137               schedule(collection, transform, point);
75138             } else {
75139               selection.interrupt().each(function () {
75140                 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
75141               });
75142             }
75143           };
75144
75145           zoom.scaleBy = function (selection, k, p) {
75146             zoom.scaleTo(selection, function () {
75147               var k0 = _transform.k,
75148                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
75149               return k0 * k1;
75150             }, p);
75151           };
75152
75153           zoom.scaleTo = function (selection, k, p) {
75154             zoom.transform(selection, function () {
75155               var e = extent.apply(this, arguments),
75156                   t0 = _transform,
75157                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
75158                   p1 = t0.invert(p0),
75159                   k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
75160               return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
75161             }, p);
75162           };
75163
75164           zoom.translateBy = function (selection, x, y) {
75165             zoom.transform(selection, function () {
75166               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);
75167             });
75168           };
75169
75170           zoom.translateTo = function (selection, x, y, p) {
75171             zoom.transform(selection, function () {
75172               var e = extent.apply(this, arguments),
75173                   t = _transform,
75174                   p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
75175               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);
75176             }, p);
75177           };
75178
75179           function scale(transform, k) {
75180             k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
75181             return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
75182           }
75183
75184           function translate(transform, p0, p1) {
75185             var x = p0[0] - p1[0] * transform.k,
75186                 y = p0[1] - p1[1] * transform.k;
75187             return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
75188           }
75189
75190           function centroid(extent) {
75191             return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
75192           }
75193
75194           function schedule(transition, transform, point) {
75195             transition.on('start.zoom', function () {
75196               gesture(this, arguments).start(null);
75197             }).on('interrupt.zoom end.zoom', function () {
75198               gesture(this, arguments).end(null);
75199             }).tween('zoom', function () {
75200               var that = this,
75201                   args = arguments,
75202                   g = gesture(that, args),
75203                   e = extent.apply(that, args),
75204                   p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
75205                   w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
75206                   a = _transform,
75207                   b = typeof transform === 'function' ? transform.apply(that, args) : transform,
75208                   i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
75209               return function (t) {
75210                 if (t === 1) t = b; // Avoid rounding error on end.
75211                 else {
75212                     var l = i(t),
75213                         k = w / l[2];
75214                     t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
75215                   }
75216                 g.zoom(null, null, t);
75217               };
75218             });
75219           }
75220
75221           function gesture(that, args, clean) {
75222             return !clean && _activeGesture || new Gesture(that, args);
75223           }
75224
75225           function Gesture(that, args) {
75226             this.that = that;
75227             this.args = args;
75228             this.active = 0;
75229             this.extent = extent.apply(that, args);
75230           }
75231
75232           Gesture.prototype = {
75233             start: function start(d3_event) {
75234               if (++this.active === 1) {
75235                 _activeGesture = this;
75236                 dispatch$1.call('start', this, d3_event);
75237               }
75238
75239               return this;
75240             },
75241             zoom: function zoom(d3_event, key, transform) {
75242               if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
75243               if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
75244               if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
75245               _transform = transform;
75246               dispatch$1.call('zoom', this, d3_event, key, transform);
75247               return this;
75248             },
75249             end: function end(d3_event) {
75250               if (--this.active === 0) {
75251                 _activeGesture = null;
75252                 dispatch$1.call('end', this, d3_event);
75253               }
75254
75255               return this;
75256             }
75257           };
75258
75259           function wheeled(d3_event) {
75260             if (!filter.apply(this, arguments)) return;
75261             var g = gesture(this, arguments),
75262                 t = _transform,
75263                 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
75264                 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
75265             // If there were recent wheel events, reset the wheel idle timeout.
75266
75267             if (g.wheel) {
75268               if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
75269                 g.mouse[1] = t.invert(g.mouse[0] = p);
75270               }
75271
75272               clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
75273             } else {
75274               g.mouse = [p, t.invert(p)];
75275               interrupt(this);
75276               g.start(d3_event);
75277             }
75278
75279             d3_event.preventDefault();
75280             d3_event.stopImmediatePropagation();
75281             g.wheel = setTimeout(wheelidled, _wheelDelay);
75282             g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
75283
75284             function wheelidled() {
75285               g.wheel = null;
75286               g.end(d3_event);
75287             }
75288           }
75289
75290           var _downPointerIDs = new Set();
75291
75292           var _pointerLocGetter;
75293
75294           function pointerdown(d3_event) {
75295             _downPointerIDs.add(d3_event.pointerId);
75296
75297             if (!filter.apply(this, arguments)) return;
75298             var g = gesture(this, arguments, _downPointerIDs.size === 1);
75299             var started;
75300             d3_event.stopImmediatePropagation();
75301             _pointerLocGetter = utilFastMouse(this);
75302
75303             var loc = _pointerLocGetter(d3_event);
75304
75305             var p = [loc, _transform.invert(loc), d3_event.pointerId];
75306
75307             if (!g.pointer0) {
75308               g.pointer0 = p;
75309               started = true;
75310             } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
75311               g.pointer1 = p;
75312             }
75313
75314             if (started) {
75315               interrupt(this);
75316               g.start(d3_event);
75317             }
75318           }
75319
75320           function pointermove(d3_event) {
75321             if (!_downPointerIDs.has(d3_event.pointerId)) return;
75322             if (!_activeGesture || !_pointerLocGetter) return;
75323             var g = gesture(this, arguments);
75324             var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
75325             var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
75326
75327             if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
75328               // The pointer went up without ending the gesture somehow, e.g.
75329               // a down mouse was moved off the map and released. End it here.
75330               if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
75331               if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
75332               g.end(d3_event);
75333               return;
75334             }
75335
75336             d3_event.preventDefault();
75337             d3_event.stopImmediatePropagation();
75338
75339             var loc = _pointerLocGetter(d3_event);
75340
75341             var t, p, l;
75342             if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
75343             t = _transform;
75344
75345             if (g.pointer1) {
75346               var p0 = g.pointer0[0],
75347                   l0 = g.pointer0[1],
75348                   p1 = g.pointer1[0],
75349                   l1 = g.pointer1[1],
75350                   dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
75351                   dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
75352               t = scale(t, Math.sqrt(dp / dl));
75353               p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
75354               l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
75355             } else if (g.pointer0) {
75356               p = g.pointer0[0];
75357               l = g.pointer0[1];
75358             } else return;
75359
75360             g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
75361           }
75362
75363           function pointerup(d3_event) {
75364             if (!_downPointerIDs.has(d3_event.pointerId)) return;
75365
75366             _downPointerIDs["delete"](d3_event.pointerId);
75367
75368             if (!_activeGesture) return;
75369             var g = gesture(this, arguments);
75370             d3_event.stopImmediatePropagation();
75371             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;
75372
75373             if (g.pointer1 && !g.pointer0) {
75374               g.pointer0 = g.pointer1;
75375               delete g.pointer1;
75376             }
75377
75378             if (g.pointer0) g.pointer0[1] = _transform.invert(g.pointer0[0]);else {
75379               g.end(d3_event);
75380             }
75381           }
75382
75383           zoom.wheelDelta = function (_) {
75384             return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
75385           };
75386
75387           zoom.filter = function (_) {
75388             return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
75389           };
75390
75391           zoom.extent = function (_) {
75392             return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
75393           };
75394
75395           zoom.scaleExtent = function (_) {
75396             return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
75397           };
75398
75399           zoom.translateExtent = function (_) {
75400             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]]];
75401           };
75402
75403           zoom.constrain = function (_) {
75404             return arguments.length ? (constrain = _, zoom) : constrain;
75405           };
75406
75407           zoom.interpolate = function (_) {
75408             return arguments.length ? (interpolate = _, zoom) : interpolate;
75409           };
75410
75411           zoom._transform = function (_) {
75412             return arguments.length ? (_transform = _, zoom) : _transform;
75413           };
75414
75415           return utilRebind(zoom, dispatch$1, 'on');
75416         }
75417
75418         // if pointer events are supported. Falls back to default `dblclick` event.
75419
75420         function utilDoubleUp() {
75421           var dispatch$1 = dispatch('doubleUp');
75422           var _maxTimespan = 500; // milliseconds
75423
75424           var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
75425
75426           var _pointer; // object representing the pointer that could trigger double up
75427
75428
75429           function pointerIsValidFor(loc) {
75430             // second pointerup must occur within a small timeframe after the first pointerdown
75431             return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
75432             geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
75433           }
75434
75435           function pointerdown(d3_event) {
75436             // ignore right-click
75437             if (d3_event.ctrlKey || d3_event.button === 2) return;
75438             var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
75439             // events on touch devices
75440
75441             if (_pointer && !pointerIsValidFor(loc)) {
75442               // if this pointer is no longer valid, clear it so another can be started
75443               _pointer = undefined;
75444             }
75445
75446             if (!_pointer) {
75447               _pointer = {
75448                 startLoc: loc,
75449                 startTime: new Date().getTime(),
75450                 upCount: 0,
75451                 pointerId: d3_event.pointerId
75452               };
75453             } else {
75454               // double down
75455               _pointer.pointerId = d3_event.pointerId;
75456             }
75457           }
75458
75459           function pointerup(d3_event) {
75460             // ignore right-click
75461             if (d3_event.ctrlKey || d3_event.button === 2) return;
75462             if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
75463             _pointer.upCount += 1;
75464
75465             if (_pointer.upCount === 2) {
75466               // double up!
75467               var loc = [d3_event.clientX, d3_event.clientY];
75468
75469               if (pointerIsValidFor(loc)) {
75470                 var locInThis = utilFastMouse(this)(d3_event);
75471                 dispatch$1.call('doubleUp', this, d3_event, locInThis);
75472               } // clear the pointer info in any case
75473
75474
75475               _pointer = undefined;
75476             }
75477           }
75478
75479           function doubleUp(selection) {
75480             if ('PointerEvent' in window) {
75481               // dblclick isn't well supported on touch devices so manually use
75482               // pointer events if they're available
75483               selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
75484             } else {
75485               // fallback to dblclick
75486               selection.on('dblclick.doubleUp', function (d3_event) {
75487                 dispatch$1.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
75488               });
75489             }
75490           }
75491
75492           doubleUp.off = function (selection) {
75493             selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
75494           };
75495
75496           return utilRebind(doubleUp, dispatch$1, 'on');
75497         }
75498
75499         var TILESIZE = 256;
75500         var minZoom = 2;
75501         var maxZoom = 24;
75502         var kMin = geoZoomToScale(minZoom, TILESIZE);
75503         var kMax = geoZoomToScale(maxZoom, TILESIZE);
75504
75505         function clamp(num, min, max) {
75506           return Math.max(min, Math.min(num, max));
75507         }
75508
75509         function rendererMap(context) {
75510           var dispatch$1 = dispatch('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
75511           var projection = context.projection;
75512           var curtainProjection = context.curtainProjection;
75513           var drawLayers;
75514           var drawPoints;
75515           var drawVertices;
75516           var drawLines;
75517           var drawAreas;
75518           var drawMidpoints;
75519           var drawLabels;
75520
75521           var _selection = select(null);
75522
75523           var supersurface = select(null);
75524           var wrapper = select(null);
75525           var surface = select(null);
75526           var _dimensions = [1, 1];
75527           var _dblClickZoomEnabled = true;
75528           var _redrawEnabled = true;
75529
75530           var _gestureTransformStart;
75531
75532           var _transformStart = projection.transform();
75533
75534           var _transformLast;
75535
75536           var _isTransformed = false;
75537           var _minzoom = 0;
75538
75539           var _getMouseCoords;
75540
75541           var _lastPointerEvent;
75542
75543           var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
75544
75545
75546           var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
75547
75548           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
75549
75550
75551           var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
75552
75553           var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
75554             _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
75555           }).on('end.map', function () {
75556             _pointerDown = false;
75557           });
75558
75559           var _doubleUpHandler = utilDoubleUp();
75560
75561           var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
75562           // var pendingRedrawCall;
75563           // function scheduleRedraw() {
75564           //     // Only schedule the redraw if one has not already been set.
75565           //     if (isRedrawScheduled) return;
75566           //     isRedrawScheduled = true;
75567           //     var that = this;
75568           //     var args = arguments;
75569           //     pendingRedrawCall = window.requestIdleCallback(function () {
75570           //         // Reset the boolean so future redraws can be set.
75571           //         isRedrawScheduled = false;
75572           //         redraw.apply(that, args);
75573           //     }, { timeout: 1400 });
75574           // }
75575
75576
75577           function cancelPendingRedraw() {
75578             scheduleRedraw.cancel(); // isRedrawScheduled = false;
75579             // window.cancelIdleCallback(pendingRedrawCall);
75580           }
75581
75582           function map(selection) {
75583             _selection = selection;
75584             context.on('change.map', immediateRedraw);
75585             var osm = context.connection();
75586
75587             if (osm) {
75588               osm.on('change.map', immediateRedraw);
75589             }
75590
75591             function didUndoOrRedo(targetTransform) {
75592               var mode = context.mode().id;
75593               if (mode !== 'browse' && mode !== 'select') return;
75594
75595               if (targetTransform) {
75596                 map.transformEase(targetTransform);
75597               }
75598             }
75599
75600             context.history().on('merge.map', function () {
75601               scheduleRedraw();
75602             }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
75603               didUndoOrRedo(fromStack.transform);
75604             }).on('redone.map', function (stack) {
75605               didUndoOrRedo(stack.transform);
75606             });
75607             context.background().on('change.map', immediateRedraw);
75608             context.features().on('redraw.map', immediateRedraw);
75609             drawLayers.on('change.map', function () {
75610               context.background().updateImagery();
75611               immediateRedraw();
75612             });
75613             selection.on('wheel.map mousewheel.map', function (d3_event) {
75614               // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
75615               d3_event.preventDefault();
75616             }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
75617
75618             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
75619             // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
75620
75621             wrapper = supersurface.append('div').attr('class', 'layer layer-data');
75622             map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
75623             surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
75624               _lastPointerEvent = d3_event;
75625
75626               if (d3_event.button === 2) {
75627                 d3_event.stopPropagation();
75628               }
75629             }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
75630               _lastPointerEvent = d3_event;
75631
75632               if (resetTransform()) {
75633                 immediateRedraw();
75634               }
75635             }).on(_pointerPrefix + 'move.map', function (d3_event) {
75636               _lastPointerEvent = d3_event;
75637             }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
75638               if (map.editableDataEnabled() && !_isTransformed) {
75639                 var hover = d3_event.target.__data__;
75640                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
75641                 dispatch$1.call('drawn', this, {
75642                   full: false
75643                 });
75644               }
75645             }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
75646               if (map.editableDataEnabled() && !_isTransformed) {
75647                 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
75648                 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
75649                 dispatch$1.call('drawn', this, {
75650                   full: false
75651                 });
75652               }
75653             });
75654             var detected = utilDetect(); // only WebKit supports gesture events
75655
75656             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
75657             // but we only need to do this on desktop Safari anyway. – #7694
75658             !detected.isMobileWebKit) {
75659               // Desktop Safari sends gesture events for multitouch trackpad pinches.
75660               // We can listen for these and translate them into map zooms.
75661               surface.on('gesturestart.surface', function (d3_event) {
75662                 d3_event.preventDefault();
75663                 _gestureTransformStart = projection.transform();
75664               }).on('gesturechange.surface', gestureChange);
75665             } // must call after surface init
75666
75667
75668             updateAreaFill();
75669
75670             _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
75671               if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
75672
75673               if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
75674               !select(d3_event.target).classed('fill')) return;
75675               var zoomOut = d3_event.shiftKey;
75676               var t = projection.transform();
75677               var p1 = t.invert(p0);
75678               t = t.scale(zoomOut ? 0.5 : 2);
75679               t.x = p0[0] - p1[0] * t.k;
75680               t.y = p0[1] - p1[1] * t.k;
75681               map.transformEase(t);
75682             });
75683
75684             context.on('enter.map', function () {
75685               if (!map.editableDataEnabled(true
75686               /* skip zoom check */
75687               )) return; // redraw immediately any objects affected by a change in selectedIDs.
75688
75689               var graph = context.graph();
75690               var selectedAndParents = {};
75691               context.selectedIDs().forEach(function (id) {
75692                 var entity = graph.hasEntity(id);
75693
75694                 if (entity) {
75695                   selectedAndParents[entity.id] = entity;
75696
75697                   if (entity.type === 'node') {
75698                     graph.parentWays(entity).forEach(function (parent) {
75699                       selectedAndParents[parent.id] = parent;
75700                     });
75701                   }
75702                 }
75703               });
75704               var data = Object.values(selectedAndParents);
75705
75706               var filter = function filter(d) {
75707                 return d.id in selectedAndParents;
75708               };
75709
75710               data = context.features().filter(data, graph);
75711               surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
75712               dispatch$1.call('drawn', this, {
75713                 full: false
75714               }); // redraw everything else later
75715
75716               scheduleRedraw();
75717             });
75718             map.dimensions(utilGetDimensions(selection));
75719           }
75720
75721           function zoomEventFilter(d3_event) {
75722             // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
75723             // Intercept `mousedown` and check if there is an orphaned zoom gesture.
75724             // This can happen if a previous `mousedown` occurred without a `mouseup`.
75725             // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
75726             // so that d3-zoom won't stop propagation of new `mousedown` events.
75727             if (d3_event.type === 'mousedown') {
75728               var hasOrphan = false;
75729               var listeners = window.__on;
75730
75731               for (var i = 0; i < listeners.length; i++) {
75732                 var listener = listeners[i];
75733
75734                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
75735                   hasOrphan = true;
75736                   break;
75737                 }
75738               }
75739
75740               if (hasOrphan) {
75741                 var event = window.CustomEvent;
75742
75743                 if (event) {
75744                   event = new event('mouseup');
75745                 } else {
75746                   event = window.document.createEvent('Event');
75747                   event.initEvent('mouseup', false, false);
75748                 } // Event needs to be dispatched with an event.view property.
75749
75750
75751                 event.view = window;
75752                 window.dispatchEvent(event);
75753               }
75754             }
75755
75756             return d3_event.button !== 2; // ignore right clicks
75757           }
75758
75759           function pxCenter() {
75760             return [_dimensions[0] / 2, _dimensions[1] / 2];
75761           }
75762
75763           function drawEditable(difference, extent) {
75764             var mode = context.mode();
75765             var graph = context.graph();
75766             var features = context.features();
75767             var all = context.history().intersects(map.extent());
75768             var fullRedraw = false;
75769             var data;
75770             var set;
75771             var filter;
75772             var applyFeatureLayerFilters = true;
75773
75774             if (map.isInWideSelection()) {
75775               data = [];
75776               utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
75777                 var entity = context.hasEntity(id);
75778                 if (entity) data.push(entity);
75779               });
75780               fullRedraw = true;
75781               filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
75782
75783               applyFeatureLayerFilters = false;
75784             } else if (difference) {
75785               var complete = difference.complete(map.extent());
75786               data = Object.values(complete).filter(Boolean);
75787               set = new Set(Object.keys(complete));
75788
75789               filter = function filter(d) {
75790                 return set.has(d.id);
75791               };
75792
75793               features.clear(data);
75794             } else {
75795               // force a full redraw if gatherStats detects that a feature
75796               // should be auto-hidden (e.g. points or buildings)..
75797               if (features.gatherStats(all, graph, _dimensions)) {
75798                 extent = undefined;
75799               }
75800
75801               if (extent) {
75802                 data = context.history().intersects(map.extent().intersection(extent));
75803                 set = new Set(data.map(function (entity) {
75804                   return entity.id;
75805                 }));
75806
75807                 filter = function filter(d) {
75808                   return set.has(d.id);
75809                 };
75810               } else {
75811                 data = all;
75812                 fullRedraw = true;
75813                 filter = utilFunctor(true);
75814               }
75815             }
75816
75817             if (applyFeatureLayerFilters) {
75818               data = features.filter(data, graph);
75819             } else {
75820               context.features().resetStats();
75821             }
75822
75823             if (mode && mode.id === 'select') {
75824               // update selected vertices - the user might have just double-clicked a way,
75825               // creating a new vertex, triggering a partial redraw without a mode change
75826               surface.call(drawVertices.drawSelected, graph, map.extent());
75827             }
75828
75829             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);
75830             dispatch$1.call('drawn', this, {
75831               full: true
75832             });
75833           }
75834
75835           map.init = function () {
75836             drawLayers = svgLayers(projection, context);
75837             drawPoints = svgPoints(projection, context);
75838             drawVertices = svgVertices(projection, context);
75839             drawLines = svgLines(projection, context);
75840             drawAreas = svgAreas(projection, context);
75841             drawMidpoints = svgMidpoints(projection, context);
75842             drawLabels = svgLabels(projection, context);
75843           };
75844
75845           function editOff() {
75846             context.features().resetStats();
75847             surface.selectAll('.layer-osm *').remove();
75848             surface.selectAll('.layer-touch:not(.markers) *').remove();
75849             var allowed = {
75850               'browse': true,
75851               'save': true,
75852               'select-note': true,
75853               'select-data': true,
75854               'select-error': true
75855             };
75856             var mode = context.mode();
75857
75858             if (mode && !allowed[mode.id]) {
75859               context.enter(modeBrowse(context));
75860             }
75861
75862             dispatch$1.call('drawn', this, {
75863               full: true
75864             });
75865           }
75866
75867           function gestureChange(d3_event) {
75868             // Remap Safari gesture events to wheel events - #5492
75869             // We want these disabled most places, but enabled for zoom/unzoom on map surface
75870             // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
75871             var e = d3_event;
75872             e.preventDefault();
75873             var props = {
75874               deltaMode: 0,
75875               // dummy values to ignore in zoomPan
75876               deltaY: 1,
75877               // dummy values to ignore in zoomPan
75878               clientX: e.clientX,
75879               clientY: e.clientY,
75880               screenX: e.screenX,
75881               screenY: e.screenY,
75882               x: e.x,
75883               y: e.y
75884             };
75885             var e2 = new WheelEvent('wheel', props);
75886             e2._scale = e.scale; // preserve the original scale
75887
75888             e2._rotation = e.rotation; // preserve the original rotation
75889
75890             _selection.node().dispatchEvent(e2);
75891           }
75892
75893           function zoomPan(event, key, transform) {
75894             var source = event && event.sourceEvent || event;
75895             var eventTransform = transform || event && event.transform;
75896             var x = eventTransform.x;
75897             var y = eventTransform.y;
75898             var k = eventTransform.k; // Special handling of 'wheel' events:
75899             // They might be triggered by the user scrolling the mouse wheel,
75900             // or 2-finger pinch/zoom gestures, the transform may need adjustment.
75901
75902             if (source && source.type === 'wheel') {
75903               // assume that the gesture is already handled by pointer events
75904               if (_pointerDown) return;
75905               var detected = utilDetect();
75906               var dX = source.deltaX;
75907               var dY = source.deltaY;
75908               var x2 = x;
75909               var y2 = y;
75910               var k2 = k;
75911               var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
75912               // If wheel delta is provided in LINE units, recalculate it in PIXEL units
75913               // We are essentially redoing the calculations that occur here:
75914               //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
75915               // See this for more info:
75916               //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
75917
75918               if (source.deltaMode === 1
75919               /* LINE */
75920               ) {
75921                   // Convert from lines to pixels, more if the user is scrolling fast.
75922                   // (I made up the exp function to roughly match Firefox to what Chrome does)
75923                   // These numbers should be floats, because integers are treated as pan gesture below.
75924                   var lines = Math.abs(source.deltaY);
75925                   var sign = source.deltaY > 0 ? 1 : -1;
75926                   dY = sign * clamp(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
75927                   350.000244140625 // max
75928                   ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
75929                   // There doesn't seem to be any scroll acceleration.
75930                   // This multiplier increases the speed a little bit - #5512
75931
75932                   if (detected.os !== 'mac') {
75933                     dY *= 5;
75934                   } // recalculate x2,y2,k2
75935
75936
75937                   t0 = _isTransformed ? _transformLast : _transformStart;
75938                   p0 = _getMouseCoords(source);
75939                   p1 = t0.invert(p0);
75940                   k2 = t0.k * Math.pow(2, -dY / 500);
75941                   k2 = clamp(k2, kMin, kMax);
75942                   x2 = p0[0] - p1[0] * k2;
75943                   y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
75944                   // These are fake `wheel` events we made from Safari `gesturechange` events..
75945                 } else if (source._scale) {
75946                 // recalculate x2,y2,k2
75947                 t0 = _gestureTransformStart;
75948                 p0 = _getMouseCoords(source);
75949                 p1 = t0.invert(p0);
75950                 k2 = t0.k * source._scale;
75951                 k2 = clamp(k2, kMin, kMax);
75952                 x2 = p0[0] - p1[0] * k2;
75953                 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
75954                 // Pinch zooming via the `wheel` event will always have:
75955                 // - `ctrlKey = true`
75956                 // - `deltaY` is not round integer pixels (ignore `deltaX`)
75957               } else if (source.ctrlKey && !isInteger(dY)) {
75958                 dY *= 6; // slightly scale up whatever the browser gave us
75959                 // recalculate x2,y2,k2
75960
75961                 t0 = _isTransformed ? _transformLast : _transformStart;
75962                 p0 = _getMouseCoords(source);
75963                 p1 = t0.invert(p0);
75964                 k2 = t0.k * Math.pow(2, -dY / 500);
75965                 k2 = clamp(k2, kMin, kMax);
75966                 x2 = p0[0] - p1[0] * k2;
75967                 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
75968               } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
75969                 // recalculate x2,y2,k2
75970                 t0 = _isTransformed ? _transformLast : _transformStart;
75971                 p0 = _getMouseCoords(source);
75972                 p1 = t0.invert(p0);
75973                 k2 = t0.k * Math.pow(2, -dY / 500);
75974                 k2 = clamp(k2, kMin, kMax);
75975                 x2 = p0[0] - p1[0] * k2;
75976                 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers) - #5492, #5512
75977                 // Panning via the `wheel` event will always have:
75978                 // - `ctrlKey = false`
75979                 // - `deltaX`,`deltaY` are round integer pixels
75980               } else if (detected.os === 'mac' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
75981                 p1 = projection.translate();
75982                 x2 = p1[0] - dX;
75983                 y2 = p1[1] - dY;
75984                 k2 = projection.scale();
75985                 k2 = clamp(k2, kMin, kMax);
75986               } // something changed - replace the event transform
75987
75988
75989               if (x2 !== x || y2 !== y || k2 !== k) {
75990                 x = x2;
75991                 y = y2;
75992                 k = k2;
75993                 eventTransform = identity$2.translate(x2, y2).scale(k2);
75994
75995                 if (_zoomerPanner._transform) {
75996                   // utilZoomPan interface
75997                   _zoomerPanner._transform(eventTransform);
75998                 } else {
75999                   // d3_zoom interface
76000                   _selection.node().__zoom = eventTransform;
76001                 }
76002               }
76003             }
76004
76005             if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
76006               return; // no change
76007             }
76008
76009             var withinEditableZoom = map.withinEditableZoom();
76010
76011             if (_lastWithinEditableZoom !== withinEditableZoom) {
76012               if (_lastWithinEditableZoom !== undefined) {
76013                 // notify that the map zoomed in or out over the editable zoom threshold
76014                 dispatch$1.call('crossEditableZoom', this, withinEditableZoom);
76015               }
76016
76017               _lastWithinEditableZoom = withinEditableZoom;
76018             }
76019
76020             if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
76021               surface.interrupt();
76022               dispatch$1.call('hitMinZoom', this, map);
76023               setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
76024               scheduleRedraw();
76025               dispatch$1.call('move', this, map);
76026               return;
76027             }
76028
76029             projection.transform(eventTransform);
76030             var scale = k / _transformStart.k;
76031             var tX = (x / scale - _transformStart.x) * scale;
76032             var tY = (y / scale - _transformStart.y) * scale;
76033
76034             if (context.inIntro()) {
76035               curtainProjection.transform({
76036                 x: x - tX,
76037                 y: y - tY,
76038                 k: k
76039               });
76040             }
76041
76042             if (source) {
76043               _lastPointerEvent = event;
76044             }
76045
76046             _isTransformed = true;
76047             _transformLast = eventTransform;
76048             utilSetTransform(supersurface, tX, tY, scale);
76049             scheduleRedraw();
76050             dispatch$1.call('move', this, map);
76051
76052             function isInteger(val) {
76053               return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
76054             }
76055           }
76056
76057           function resetTransform() {
76058             if (!_isTransformed) return false;
76059             utilSetTransform(supersurface, 0, 0);
76060             _isTransformed = false;
76061
76062             if (context.inIntro()) {
76063               curtainProjection.transform(projection.transform());
76064             }
76065
76066             return true;
76067           }
76068
76069           function redraw(difference, extent) {
76070             if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
76071             // It would result in artifacts where differenced entities are redrawn with
76072             // one transform and unchanged entities with another.
76073
76074             if (resetTransform()) {
76075               difference = extent = undefined;
76076             }
76077
76078             var zoom = map.zoom();
76079             var z = String(~~zoom);
76080
76081             if (surface.attr('data-zoom') !== z) {
76082               surface.attr('data-zoom', z);
76083             } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
76084
76085
76086             var lat = map.center()[1];
76087             var lowzoom = linear$2().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
76088             surface.classed('low-zoom', zoom <= lowzoom(lat));
76089
76090             if (!difference) {
76091               supersurface.call(context.background());
76092               wrapper.call(drawLayers);
76093             } // OSM
76094
76095
76096             if (map.editableDataEnabled() || map.isInWideSelection()) {
76097               context.loadTiles(projection);
76098               drawEditable(difference, extent);
76099             } else {
76100               editOff();
76101             }
76102
76103             _transformStart = projection.transform();
76104             return map;
76105           }
76106
76107           var immediateRedraw = function immediateRedraw(difference, extent) {
76108             if (!difference && !extent) cancelPendingRedraw();
76109             redraw(difference, extent);
76110           };
76111
76112           map.lastPointerEvent = function () {
76113             return _lastPointerEvent;
76114           };
76115
76116           map.mouse = function (d3_event) {
76117             var event = _lastPointerEvent || d3_event;
76118
76119             if (event) {
76120               var s;
76121
76122               while (s = event.sourceEvent) {
76123                 event = s;
76124               }
76125
76126               return _getMouseCoords(event);
76127             }
76128
76129             return null;
76130           }; // returns Lng/Lat
76131
76132
76133           map.mouseCoordinates = function () {
76134             var coord = map.mouse() || pxCenter();
76135             return projection.invert(coord);
76136           };
76137
76138           map.dblclickZoomEnable = function (val) {
76139             if (!arguments.length) return _dblClickZoomEnabled;
76140             _dblClickZoomEnabled = val;
76141             return map;
76142           };
76143
76144           map.redrawEnable = function (val) {
76145             if (!arguments.length) return _redrawEnabled;
76146             _redrawEnabled = val;
76147             return map;
76148           };
76149
76150           map.isTransformed = function () {
76151             return _isTransformed;
76152           };
76153
76154           function setTransform(t2, duration, force) {
76155             var t = projection.transform();
76156             if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
76157
76158             if (duration) {
76159               _selection.transition().duration(duration).on('start', function () {
76160                 map.startEase();
76161               }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
76162             } else {
76163               projection.transform(t2);
76164               _transformStart = t2;
76165
76166               _selection.call(_zoomerPanner.transform, _transformStart);
76167             }
76168
76169             return true;
76170           }
76171
76172           function setCenterZoom(loc2, z2, duration, force) {
76173             var c = map.center();
76174             var z = map.zoom();
76175             if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
76176             var proj = geoRawMercator().transform(projection.transform()); // copy projection
76177
76178             var k2 = clamp(geoZoomToScale(z2, TILESIZE), kMin, kMax);
76179             proj.scale(k2);
76180             var t = proj.translate();
76181             var point = proj(loc2);
76182             var center = pxCenter();
76183             t[0] += center[0] - point[0];
76184             t[1] += center[1] - point[1];
76185             return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
76186           }
76187
76188           map.pan = function (delta, duration) {
76189             var t = projection.translate();
76190             var k = projection.scale();
76191             t[0] += delta[0];
76192             t[1] += delta[1];
76193
76194             if (duration) {
76195               _selection.transition().duration(duration).on('start', function () {
76196                 map.startEase();
76197               }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
76198             } else {
76199               projection.translate(t);
76200               _transformStart = projection.transform();
76201
76202               _selection.call(_zoomerPanner.transform, _transformStart);
76203
76204               dispatch$1.call('move', this, map);
76205               immediateRedraw();
76206             }
76207
76208             return map;
76209           };
76210
76211           map.dimensions = function (val) {
76212             if (!arguments.length) return _dimensions;
76213             _dimensions = val;
76214             drawLayers.dimensions(_dimensions);
76215             context.background().dimensions(_dimensions);
76216             projection.clipExtent([[0, 0], _dimensions]);
76217             _getMouseCoords = utilFastMouse(supersurface.node());
76218             scheduleRedraw();
76219             return map;
76220           };
76221
76222           function zoomIn(delta) {
76223             setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
76224           }
76225
76226           function zoomOut(delta) {
76227             setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
76228           }
76229
76230           map.zoomIn = function () {
76231             zoomIn(1);
76232           };
76233
76234           map.zoomInFurther = function () {
76235             zoomIn(4);
76236           };
76237
76238           map.canZoomIn = function () {
76239             return map.zoom() < maxZoom;
76240           };
76241
76242           map.zoomOut = function () {
76243             zoomOut(1);
76244           };
76245
76246           map.zoomOutFurther = function () {
76247             zoomOut(4);
76248           };
76249
76250           map.canZoomOut = function () {
76251             return map.zoom() > minZoom;
76252           };
76253
76254           map.center = function (loc2) {
76255             if (!arguments.length) {
76256               return projection.invert(pxCenter());
76257             }
76258
76259             if (setCenterZoom(loc2, map.zoom())) {
76260               dispatch$1.call('move', this, map);
76261             }
76262
76263             scheduleRedraw();
76264             return map;
76265           };
76266
76267           map.unobscuredCenterZoomEase = function (loc, zoom) {
76268             var offset = map.unobscuredOffsetPx();
76269             var proj = geoRawMercator().transform(projection.transform()); // copy projection
76270             // use the target zoom to calculate the offset center
76271
76272             proj.scale(geoZoomToScale(zoom, TILESIZE));
76273             var locPx = proj(loc);
76274             var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
76275             var offsetLoc = proj.invert(offsetLocPx);
76276             map.centerZoomEase(offsetLoc, zoom);
76277           };
76278
76279           map.unobscuredOffsetPx = function () {
76280             var openPane = context.container().select('.map-panes .map-pane.shown');
76281
76282             if (!openPane.empty()) {
76283               return [openPane.node().offsetWidth / 2, 0];
76284             }
76285
76286             return [0, 0];
76287           };
76288
76289           map.zoom = function (z2) {
76290             if (!arguments.length) {
76291               return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
76292             }
76293
76294             if (z2 < _minzoom) {
76295               surface.interrupt();
76296               dispatch$1.call('hitMinZoom', this, map);
76297               z2 = context.minEditableZoom();
76298             }
76299
76300             if (setCenterZoom(map.center(), z2)) {
76301               dispatch$1.call('move', this, map);
76302             }
76303
76304             scheduleRedraw();
76305             return map;
76306           };
76307
76308           map.centerZoom = function (loc2, z2) {
76309             if (setCenterZoom(loc2, z2)) {
76310               dispatch$1.call('move', this, map);
76311             }
76312
76313             scheduleRedraw();
76314             return map;
76315           };
76316
76317           map.zoomTo = function (entity) {
76318             var extent = entity.extent(context.graph());
76319             if (!isFinite(extent.area())) return map;
76320             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
76321             return map.centerZoom(extent.center(), z2);
76322           };
76323
76324           map.centerEase = function (loc2, duration) {
76325             duration = duration || 250;
76326             setCenterZoom(loc2, map.zoom(), duration);
76327             return map;
76328           };
76329
76330           map.zoomEase = function (z2, duration) {
76331             duration = duration || 250;
76332             setCenterZoom(map.center(), z2, duration, false);
76333             return map;
76334           };
76335
76336           map.centerZoomEase = function (loc2, z2, duration) {
76337             duration = duration || 250;
76338             setCenterZoom(loc2, z2, duration, false);
76339             return map;
76340           };
76341
76342           map.transformEase = function (t2, duration) {
76343             duration = duration || 250;
76344             setTransform(t2, duration, false
76345             /* don't force */
76346             );
76347             return map;
76348           };
76349
76350           map.zoomToEase = function (obj, duration) {
76351             var extent;
76352
76353             if (Array.isArray(obj)) {
76354               obj.forEach(function (entity) {
76355                 var entityExtent = entity.extent(context.graph());
76356
76357                 if (!extent) {
76358                   extent = entityExtent;
76359                 } else {
76360                   extent = extent.extend(entityExtent);
76361                 }
76362               });
76363             } else {
76364               extent = obj.extent(context.graph());
76365             }
76366
76367             if (!isFinite(extent.area())) return map;
76368             var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
76369             return map.centerZoomEase(extent.center(), z2, duration);
76370           };
76371
76372           map.startEase = function () {
76373             utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
76374               map.cancelEase();
76375             });
76376             return map;
76377           };
76378
76379           map.cancelEase = function () {
76380             _selection.interrupt();
76381
76382             return map;
76383           };
76384
76385           map.extent = function (val) {
76386             if (!arguments.length) {
76387               return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
76388             } else {
76389               var extent = geoExtent(val);
76390               map.centerZoom(extent.center(), map.extentZoom(extent));
76391             }
76392           };
76393
76394           map.trimmedExtent = function (val) {
76395             if (!arguments.length) {
76396               var headerY = 71;
76397               var footerY = 30;
76398               var pad = 10;
76399               return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
76400             } else {
76401               var extent = geoExtent(val);
76402               map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
76403             }
76404           };
76405
76406           function calcExtentZoom(extent, dim) {
76407             var tl = projection([extent[0][0], extent[1][1]]);
76408             var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
76409
76410             var hFactor = (br[0] - tl[0]) / dim[0];
76411             var vFactor = (br[1] - tl[1]) / dim[1];
76412             var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
76413             var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
76414             var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
76415             return newZoom;
76416           }
76417
76418           map.extentZoom = function (val) {
76419             return calcExtentZoom(geoExtent(val), _dimensions);
76420           };
76421
76422           map.trimmedExtentZoom = function (val) {
76423             var trimY = 120;
76424             var trimX = 40;
76425             var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
76426             return calcExtentZoom(geoExtent(val), trimmed);
76427           };
76428
76429           map.withinEditableZoom = function () {
76430             return map.zoom() >= context.minEditableZoom();
76431           };
76432
76433           map.isInWideSelection = function () {
76434             return !map.withinEditableZoom() && context.selectedIDs().length;
76435           };
76436
76437           map.editableDataEnabled = function (skipZoomCheck) {
76438             var layer = context.layers().layer('osm');
76439             if (!layer || !layer.enabled()) return false;
76440             return skipZoomCheck || map.withinEditableZoom();
76441           };
76442
76443           map.notesEditable = function () {
76444             var layer = context.layers().layer('notes');
76445             if (!layer || !layer.enabled()) return false;
76446             return map.withinEditableZoom();
76447           };
76448
76449           map.minzoom = function (val) {
76450             if (!arguments.length) return _minzoom;
76451             _minzoom = val;
76452             return map;
76453           };
76454
76455           map.toggleHighlightEdited = function () {
76456             surface.classed('highlight-edited', !surface.classed('highlight-edited'));
76457             map.pan([0, 0]); // trigger a redraw
76458
76459             dispatch$1.call('changeHighlighting', this);
76460           };
76461
76462           map.areaFillOptions = ['wireframe', 'partial', 'full'];
76463
76464           map.activeAreaFill = function (val) {
76465             if (!arguments.length) return corePreferences('area-fill') || 'partial';
76466             corePreferences('area-fill', val);
76467
76468             if (val !== 'wireframe') {
76469               corePreferences('area-fill-toggle', val);
76470             }
76471
76472             updateAreaFill();
76473             map.pan([0, 0]); // trigger a redraw
76474
76475             dispatch$1.call('changeAreaFill', this);
76476             return map;
76477           };
76478
76479           map.toggleWireframe = function () {
76480             var activeFill = map.activeAreaFill();
76481
76482             if (activeFill === 'wireframe') {
76483               activeFill = corePreferences('area-fill-toggle') || 'partial';
76484             } else {
76485               activeFill = 'wireframe';
76486             }
76487
76488             map.activeAreaFill(activeFill);
76489           };
76490
76491           function updateAreaFill() {
76492             var activeFill = map.activeAreaFill();
76493             map.areaFillOptions.forEach(function (opt) {
76494               surface.classed('fill-' + opt, Boolean(opt === activeFill));
76495             });
76496           }
76497
76498           map.layers = function () {
76499             return drawLayers;
76500           };
76501
76502           map.doubleUpHandler = function () {
76503             return _doubleUpHandler;
76504           };
76505
76506           return utilRebind(map, dispatch$1, 'on');
76507         }
76508
76509         function rendererPhotos(context) {
76510           var dispatch$1 = dispatch('change');
76511           var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
76512           var _allPhotoTypes = ['flat', 'panoramic'];
76513
76514           var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
76515
76516
76517           var _dateFilters = ['fromDate', 'toDate'];
76518
76519           var _fromDate;
76520
76521           var _toDate;
76522
76523           var _usernames;
76524
76525           function photos() {}
76526
76527           function updateStorage() {
76528             if (window.mocha) return;
76529             var hash = utilStringQs(window.location.hash);
76530             var enabled = context.layers().all().filter(function (d) {
76531               return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
76532             }).map(function (d) {
76533               return d.id;
76534             });
76535
76536             if (enabled.length) {
76537               hash.photo_overlay = enabled.join(',');
76538             } else {
76539               delete hash.photo_overlay;
76540             }
76541
76542             window.location.replace('#' + utilQsString(hash, true));
76543           }
76544
76545           photos.overlayLayerIDs = function () {
76546             return _layerIDs;
76547           };
76548
76549           photos.allPhotoTypes = function () {
76550             return _allPhotoTypes;
76551           };
76552
76553           photos.dateFilters = function () {
76554             return _dateFilters;
76555           };
76556
76557           photos.dateFilterValue = function (val) {
76558             return val === _dateFilters[0] ? _fromDate : _toDate;
76559           };
76560
76561           photos.setDateFilter = function (type, val, updateUrl) {
76562             // validate the date
76563             var date = val && new Date(val);
76564
76565             if (date && !isNaN(date)) {
76566               val = date.toISOString().substr(0, 10);
76567             } else {
76568               val = null;
76569             }
76570
76571             if (type === _dateFilters[0]) {
76572               _fromDate = val;
76573
76574               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
76575                 _toDate = _fromDate;
76576               }
76577             }
76578
76579             if (type === _dateFilters[1]) {
76580               _toDate = val;
76581
76582               if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
76583                 _fromDate = _toDate;
76584               }
76585             }
76586
76587             dispatch$1.call('change', this);
76588
76589             if (updateUrl) {
76590               var rangeString;
76591
76592               if (_fromDate || _toDate) {
76593                 rangeString = (_fromDate || '') + '_' + (_toDate || '');
76594               }
76595
76596               setUrlFilterValue('photo_dates', rangeString);
76597             }
76598           };
76599
76600           photos.setUsernameFilter = function (val, updateUrl) {
76601             if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
76602
76603             if (val) {
76604               val = val.map(function (d) {
76605                 return d.trim();
76606               }).filter(Boolean);
76607
76608               if (!val.length) {
76609                 val = null;
76610               }
76611             }
76612
76613             _usernames = val;
76614             dispatch$1.call('change', this);
76615
76616             if (updateUrl) {
76617               var hashString;
76618
76619               if (_usernames) {
76620                 hashString = _usernames.join(',');
76621               }
76622
76623               setUrlFilterValue('photo_username', hashString);
76624             }
76625           };
76626
76627           function setUrlFilterValue(property, val) {
76628             if (!window.mocha) {
76629               var hash = utilStringQs(window.location.hash);
76630
76631               if (val) {
76632                 if (hash[property] === val) return;
76633                 hash[property] = val;
76634               } else {
76635                 if (!(property in hash)) return;
76636                 delete hash[property];
76637               }
76638
76639               window.location.replace('#' + utilQsString(hash, true));
76640             }
76641           }
76642
76643           function showsLayer(id) {
76644             var layer = context.layers().layer(id);
76645             return layer && layer.supported() && layer.enabled();
76646           }
76647
76648           photos.shouldFilterByDate = function () {
76649             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
76650           };
76651
76652           photos.shouldFilterByPhotoType = function () {
76653             return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
76654           };
76655
76656           photos.shouldFilterByUsername = function () {
76657             return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
76658           };
76659
76660           photos.showsPhotoType = function (val) {
76661             if (!photos.shouldFilterByPhotoType()) return true;
76662             return _shownPhotoTypes.indexOf(val) !== -1;
76663           };
76664
76665           photos.showsFlat = function () {
76666             return photos.showsPhotoType('flat');
76667           };
76668
76669           photos.showsPanoramic = function () {
76670             return photos.showsPhotoType('panoramic');
76671           };
76672
76673           photos.fromDate = function () {
76674             return _fromDate;
76675           };
76676
76677           photos.toDate = function () {
76678             return _toDate;
76679           };
76680
76681           photos.togglePhotoType = function (val) {
76682             var index = _shownPhotoTypes.indexOf(val);
76683
76684             if (index !== -1) {
76685               _shownPhotoTypes.splice(index, 1);
76686             } else {
76687               _shownPhotoTypes.push(val);
76688             }
76689
76690             dispatch$1.call('change', this);
76691             return photos;
76692           };
76693
76694           photos.usernames = function () {
76695             return _usernames;
76696           };
76697
76698           photos.init = function () {
76699             var hash = utilStringQs(window.location.hash);
76700
76701             if (hash.photo_dates) {
76702               // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
76703               var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
76704               this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
76705               this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
76706             }
76707
76708             if (hash.photo_username) {
76709               this.setUsernameFilter(hash.photo_username, false);
76710             }
76711
76712             if (hash.photo_overlay) {
76713               // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
76714               var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
76715               hashOverlayIDs.forEach(function (id) {
76716                 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
76717                 if (layer && !layer.enabled()) layer.enabled(true);
76718               });
76719             }
76720
76721             if (hash.photo) {
76722               // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
76723               var photoIds = hash.photo.replace(/;/g, ',').split(',');
76724               var photoId = photoIds.length && photoIds[0].trim();
76725               var results = /(.*)\/(.*)/g.exec(photoId);
76726
76727               if (results && results.length >= 3) {
76728                 var serviceId = results[1];
76729                 var photoKey = results[2];
76730                 var service = services[serviceId];
76731
76732                 if (service && service.ensureViewerLoaded) {
76733                   // if we're showing a photo then make sure its layer is enabled too
76734                   var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
76735                   if (layer && !layer.enabled()) layer.enabled(true);
76736                   var baselineTime = Date.now();
76737                   service.on('loadedImages.rendererPhotos', function () {
76738                     // don't open the viewer if too much time has elapsed
76739                     if (Date.now() - baselineTime > 45000) {
76740                       service.on('loadedImages.rendererPhotos', null);
76741                       return;
76742                     }
76743
76744                     if (!service.cachedImage(photoKey)) return;
76745                     service.on('loadedImages.rendererPhotos', null);
76746                     service.ensureViewerLoaded(context).then(function () {
76747                       service.selectImage(context, photoKey).showViewer(context);
76748                     });
76749                   });
76750                 }
76751               }
76752             }
76753
76754             context.layers().on('change.rendererPhotos', updateStorage);
76755           };
76756
76757           return utilRebind(photos, dispatch$1, 'on');
76758         }
76759
76760         function uiAccount(context) {
76761           var osm = context.connection();
76762
76763           function update(selection) {
76764             if (!osm) return;
76765
76766             if (!osm.authenticated()) {
76767               selection.selectAll('.userLink, .logoutLink').classed('hide', true);
76768               return;
76769             }
76770
76771             osm.userDetails(function (err, details) {
76772               var userLink = selection.select('.userLink'),
76773                   logoutLink = selection.select('.logoutLink');
76774               userLink.html('');
76775               logoutLink.html('');
76776               if (err || !details) return;
76777               selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
76778
76779               var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
76780
76781               if (details.image_url) {
76782                 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
76783               } else {
76784                 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
76785               } // Add user name
76786
76787
76788               userLinkA.append('span').attr('class', 'label').html(details.display_name);
76789               logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
76790                 d3_event.preventDefault();
76791                 osm.logout();
76792               });
76793             });
76794           }
76795
76796           return function (selection) {
76797             selection.append('li').attr('class', 'userLink').classed('hide', true);
76798             selection.append('li').attr('class', 'logoutLink').classed('hide', true);
76799
76800             if (osm) {
76801               osm.on('change.account', function () {
76802                 update(selection);
76803               });
76804               update(selection);
76805             }
76806           };
76807         }
76808
76809         function uiAttribution(context) {
76810           var _selection = select(null);
76811
76812           function render(selection, data, klass) {
76813             var div = selection.selectAll(".".concat(klass)).data([0]);
76814             div = div.enter().append('div').attr('class', klass).merge(div);
76815             var attributions = div.selectAll('.attribution').data(data, function (d) {
76816               return d.id;
76817             });
76818             attributions.exit().remove();
76819             attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
76820               var attribution = select(nodes[i]);
76821
76822               if (d.terms_html) {
76823                 attribution.html(d.terms_html);
76824                 return;
76825               }
76826
76827               if (d.terms_url) {
76828                 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
76829               }
76830
76831               var sourceID = d.id.replace(/\./g, '<TX_DOT>');
76832               var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
76833                 "default": d.terms_text || d.id || d.name()
76834               });
76835
76836               if (d.icon && !d.overlay) {
76837                 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
76838               }
76839
76840               attribution.append('span').attr('class', 'attribution-text').html(terms_text);
76841             }).merge(attributions);
76842             var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
76843               var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
76844               return notice ? [notice] : [];
76845             });
76846             copyright.exit().remove();
76847             copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
76848             copyright.html(String);
76849           }
76850
76851           function update() {
76852             var baselayer = context.background().baseLayerSource();
76853
76854             _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
76855
76856             var z = context.map().zoom();
76857             var overlays = context.background().overlayLayerSources() || [];
76858
76859             _selection.call(render, overlays.filter(function (s) {
76860               return s.validZoom(z);
76861             }), 'overlay-layer-attribution');
76862           }
76863
76864           return function (selection) {
76865             _selection = selection;
76866             context.background().on('change.attribution', update);
76867             context.map().on('move.attribution', throttle(update, 400, {
76868               leading: false
76869             }));
76870             update();
76871           };
76872         }
76873
76874         function uiContributors(context) {
76875           var osm = context.connection(),
76876               debouncedUpdate = debounce(function () {
76877             update();
76878           }, 1000),
76879               limit = 4,
76880               hidden = false,
76881               wrap = select(null);
76882
76883           function update() {
76884             if (!osm) return;
76885             var users = {},
76886                 entities = context.history().intersects(context.map().extent());
76887             entities.forEach(function (entity) {
76888               if (entity && entity.user) users[entity.user] = true;
76889             });
76890             var u = Object.keys(users),
76891                 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
76892             wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
76893             var userList = select(document.createElement('span'));
76894             userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
76895               return osm.userURL(d);
76896             }).attr('target', '_blank').html(String);
76897
76898             if (u.length > limit) {
76899               var count = select(document.createElement('span'));
76900               var othersNum = u.length - limit + 1;
76901               count.append('a').attr('target', '_blank').attr('href', function () {
76902                 return osm.changesetsURL(context.map().center(), context.map().zoom());
76903               }).html(othersNum);
76904               wrap.append('span').html(_t.html('contributors.truncated_list', {
76905                 n: othersNum,
76906                 users: userList.html(),
76907                 count: count.html()
76908               }));
76909             } else {
76910               wrap.append('span').html(_t.html('contributors.list', {
76911                 users: userList.html()
76912               }));
76913             }
76914
76915             if (!u.length) {
76916               hidden = true;
76917               wrap.transition().style('opacity', 0);
76918             } else if (hidden) {
76919               wrap.transition().style('opacity', 1);
76920             }
76921           }
76922
76923           return function (selection) {
76924             if (!osm) return;
76925             wrap = selection;
76926             update();
76927             osm.on('loaded.contributors', debouncedUpdate);
76928             context.map().on('move.contributors', debouncedUpdate);
76929           };
76930         }
76931
76932         var _popoverID = 0;
76933         function uiPopover(klass) {
76934           var _id = _popoverID++;
76935
76936           var _anchorSelection = select(null);
76937
76938           var popover = function popover(selection) {
76939             _anchorSelection = selection;
76940             selection.each(setup);
76941           };
76942
76943           var _animation = utilFunctor(false);
76944
76945           var _placement = utilFunctor('top'); // top, bottom, left, right
76946
76947
76948           var _alignment = utilFunctor('center'); // leading, center, trailing
76949
76950
76951           var _scrollContainer = utilFunctor(select(null));
76952
76953           var _content;
76954
76955           var _displayType = utilFunctor('');
76956
76957           var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
76958
76959
76960           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
76961
76962           popover.displayType = function (val) {
76963             if (arguments.length) {
76964               _displayType = utilFunctor(val);
76965               return popover;
76966             } else {
76967               return _displayType;
76968             }
76969           };
76970
76971           popover.hasArrow = function (val) {
76972             if (arguments.length) {
76973               _hasArrow = utilFunctor(val);
76974               return popover;
76975             } else {
76976               return _hasArrow;
76977             }
76978           };
76979
76980           popover.placement = function (val) {
76981             if (arguments.length) {
76982               _placement = utilFunctor(val);
76983               return popover;
76984             } else {
76985               return _placement;
76986             }
76987           };
76988
76989           popover.alignment = function (val) {
76990             if (arguments.length) {
76991               _alignment = utilFunctor(val);
76992               return popover;
76993             } else {
76994               return _alignment;
76995             }
76996           };
76997
76998           popover.scrollContainer = function (val) {
76999             if (arguments.length) {
77000               _scrollContainer = utilFunctor(val);
77001               return popover;
77002             } else {
77003               return _scrollContainer;
77004             }
77005           };
77006
77007           popover.content = function (val) {
77008             if (arguments.length) {
77009               _content = val;
77010               return popover;
77011             } else {
77012               return _content;
77013             }
77014           };
77015
77016           popover.isShown = function () {
77017             var popoverSelection = _anchorSelection.select('.popover-' + _id);
77018
77019             return !popoverSelection.empty() && popoverSelection.classed('in');
77020           };
77021
77022           popover.show = function () {
77023             _anchorSelection.each(show);
77024           };
77025
77026           popover.updateContent = function () {
77027             _anchorSelection.each(updateContent);
77028           };
77029
77030           popover.hide = function () {
77031             _anchorSelection.each(hide);
77032           };
77033
77034           popover.toggle = function () {
77035             _anchorSelection.each(toggle);
77036           };
77037
77038           popover.destroy = function (selection, selector) {
77039             // by default, just destroy the current popover
77040             selector = selector || '.popover-' + _id;
77041             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 () {
77042               return this.getAttribute('data-original-title') || this.getAttribute('title');
77043             }).attr('data-original-title', null).selectAll(selector).remove();
77044           };
77045
77046           popover.destroyAny = function (selection) {
77047             selection.call(popover.destroy, '.popover');
77048           };
77049
77050           function setup() {
77051             var anchor = select(this);
77052
77053             var animate = _animation.apply(this, arguments);
77054
77055             var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
77056             var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
77057             enter.append('div').attr('class', 'popover-arrow');
77058             enter.append('div').attr('class', 'popover-inner');
77059             popoverSelection = enter.merge(popoverSelection);
77060
77061             if (animate) {
77062               popoverSelection.classed('fade', true);
77063             }
77064
77065             var display = _displayType.apply(this, arguments);
77066
77067             if (display === 'hover') {
77068               var _lastNonMouseEnterTime;
77069
77070               anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
77071                 if (d3_event.pointerType) {
77072                   if (d3_event.pointerType !== 'mouse') {
77073                     _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
77074
77075                     return;
77076                   } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
77077                     // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
77078                     // event for non-mouse interactions right after sending
77079                     // the correct type pointerenter event. Workaround by discarding
77080                     // any mouse event that occurs immediately after a non-mouse event.
77081                     return;
77082                   }
77083                 } // don't show if buttons are pressed, e.g. during click and drag of map
77084
77085
77086                 if (d3_event.buttons !== 0) return;
77087                 show.apply(this, arguments);
77088               }).on(_pointerPrefix + 'leave.popover', function () {
77089                 hide.apply(this, arguments);
77090               }) // show on focus too for better keyboard navigation support
77091               .on('focus.popover', function () {
77092                 show.apply(this, arguments);
77093               }).on('blur.popover', function () {
77094                 hide.apply(this, arguments);
77095               });
77096             } else if (display === 'clickFocus') {
77097               anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
77098                 d3_event.preventDefault();
77099                 d3_event.stopPropagation();
77100               }).on(_pointerPrefix + 'up.popover', function (d3_event) {
77101                 d3_event.preventDefault();
77102                 d3_event.stopPropagation();
77103               }).on('click.popover', toggle);
77104               popoverSelection // This attribute lets the popover take focus
77105               .attr('tabindex', 0).on('blur.popover', function () {
77106                 anchor.each(function () {
77107                   hide.apply(this, arguments);
77108                 });
77109               });
77110             }
77111           }
77112
77113           function show() {
77114             var anchor = select(this);
77115             var popoverSelection = anchor.selectAll('.popover-' + _id);
77116
77117             if (popoverSelection.empty()) {
77118               // popover was removed somehow, put it back
77119               anchor.call(popover.destroy);
77120               anchor.each(setup);
77121               popoverSelection = anchor.selectAll('.popover-' + _id);
77122             }
77123
77124             popoverSelection.classed('in', true);
77125
77126             var displayType = _displayType.apply(this, arguments);
77127
77128             if (displayType === 'clickFocus') {
77129               anchor.classed('active', true);
77130               popoverSelection.node().focus();
77131             }
77132
77133             anchor.each(updateContent);
77134           }
77135
77136           function updateContent() {
77137             var anchor = select(this);
77138
77139             if (_content) {
77140               anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
77141             }
77142
77143             updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
77144             // set before the dynamic popover size is calculated by the browser
77145
77146             updatePosition.apply(this, arguments);
77147             updatePosition.apply(this, arguments);
77148           }
77149
77150           function updatePosition() {
77151             var anchor = select(this);
77152             var popoverSelection = anchor.selectAll('.popover-' + _id);
77153
77154             var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
77155
77156             var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
77157             var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
77158             var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
77159
77160             var placement = _placement.apply(this, arguments);
77161
77162             popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
77163
77164             var alignment = _alignment.apply(this, arguments);
77165
77166             var alignFactor = 0.5;
77167
77168             if (alignment === 'leading') {
77169               alignFactor = 0;
77170             } else if (alignment === 'trailing') {
77171               alignFactor = 1;
77172             }
77173
77174             var anchorFrame = getFrame(anchor.node());
77175             var popoverFrame = getFrame(popoverSelection.node());
77176             var position;
77177
77178             switch (placement) {
77179               case 'top':
77180                 position = {
77181                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
77182                   y: anchorFrame.y - popoverFrame.h
77183                 };
77184                 break;
77185
77186               case 'bottom':
77187                 position = {
77188                   x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
77189                   y: anchorFrame.y + anchorFrame.h
77190                 };
77191                 break;
77192
77193               case 'left':
77194                 position = {
77195                   x: anchorFrame.x - popoverFrame.w,
77196                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
77197                 };
77198                 break;
77199
77200               case 'right':
77201                 position = {
77202                   x: anchorFrame.x + anchorFrame.w,
77203                   y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
77204                 };
77205                 break;
77206             }
77207
77208             if (position) {
77209               if (scrollNode && (placement === 'top' || placement === 'bottom')) {
77210                 var initialPosX = position.x;
77211
77212                 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
77213                   position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
77214                 } else if (position.x < 10) {
77215                   position.x = 10;
77216                 }
77217
77218                 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
77219
77220                 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
77221                 arrow.style('left', ~~arrowPosX + 'px');
77222               }
77223
77224               popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
77225             } else {
77226               popoverSelection.style('left', null).style('top', null);
77227             }
77228
77229             function getFrame(node) {
77230               var positionStyle = select(node).style('position');
77231
77232               if (positionStyle === 'absolute' || positionStyle === 'static') {
77233                 return {
77234                   x: node.offsetLeft - scrollLeft,
77235                   y: node.offsetTop - scrollTop,
77236                   w: node.offsetWidth,
77237                   h: node.offsetHeight
77238                 };
77239               } else {
77240                 return {
77241                   x: 0,
77242                   y: 0,
77243                   w: node.offsetWidth,
77244                   h: node.offsetHeight
77245                 };
77246               }
77247             }
77248           }
77249
77250           function hide() {
77251             var anchor = select(this);
77252
77253             if (_displayType.apply(this, arguments) === 'clickFocus') {
77254               anchor.classed('active', false);
77255             }
77256
77257             anchor.selectAll('.popover-' + _id).classed('in', false);
77258           }
77259
77260           function toggle() {
77261             if (select(this).select('.popover-' + _id).classed('in')) {
77262               hide.apply(this, arguments);
77263             } else {
77264               show.apply(this, arguments);
77265             }
77266           }
77267
77268           return popover;
77269         }
77270
77271         function uiTooltip(klass) {
77272           var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
77273
77274           var _title = function _title() {
77275             var title = this.getAttribute('data-original-title');
77276
77277             if (title) {
77278               return title;
77279             } else {
77280               title = this.getAttribute('title');
77281               this.removeAttribute('title');
77282               this.setAttribute('data-original-title', title);
77283             }
77284
77285             return title;
77286           };
77287
77288           var _heading = utilFunctor(null);
77289
77290           var _keys = utilFunctor(null);
77291
77292           tooltip.title = function (val) {
77293             if (!arguments.length) return _title;
77294             _title = utilFunctor(val);
77295             return tooltip;
77296           };
77297
77298           tooltip.heading = function (val) {
77299             if (!arguments.length) return _heading;
77300             _heading = utilFunctor(val);
77301             return tooltip;
77302           };
77303
77304           tooltip.keys = function (val) {
77305             if (!arguments.length) return _keys;
77306             _keys = utilFunctor(val);
77307             return tooltip;
77308           };
77309
77310           tooltip.content(function () {
77311             var heading = _heading.apply(this, arguments);
77312
77313             var text = _title.apply(this, arguments);
77314
77315             var keys = _keys.apply(this, arguments);
77316
77317             return function (selection) {
77318               var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
77319               headingSelect.exit().remove();
77320               headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
77321               var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
77322               textSelect.exit().remove();
77323               textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
77324               var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
77325               keyhintWrap.exit().remove();
77326               var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
77327               keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
77328               keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
77329               keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
77330                 return d;
77331               });
77332             };
77333           });
77334           return tooltip;
77335         }
77336
77337         function uiEditMenu(context) {
77338           var dispatch$1 = dispatch('toggled');
77339
77340           var _menu = select(null);
77341
77342           var _operations = []; // the position the menu should be displayed relative to
77343
77344           var _anchorLoc = [0, 0];
77345           var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
77346
77347           var _triggerType = '';
77348           var _vpTopMargin = 85; // viewport top margin
77349
77350           var _vpBottomMargin = 45; // viewport bottom margin
77351
77352           var _vpSideMargin = 35; // viewport side margin
77353
77354           var _menuTop = false;
77355
77356           var _menuHeight;
77357
77358           var _menuWidth; // hardcode these values to make menu positioning easier
77359
77360
77361           var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
77362
77363           var _tooltipWidth = 210; // offset the menu slightly from the target location
77364
77365           var _menuSideMargin = 10;
77366           var _tooltips = [];
77367
77368           var editMenu = function editMenu(selection) {
77369             var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
77370
77371             var ops = _operations.filter(function (op) {
77372               return !isTouchMenu || !op.mouseOnly;
77373             });
77374
77375             if (!ops.length) return;
77376             _tooltips = []; // Position the menu above the anchor for stylus and finger input
77377             // since the mapper's hand likely obscures the screen below the anchor
77378
77379             _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
77380
77381             var showLabels = isTouchMenu;
77382             var buttonHeight = showLabels ? 32 : 34;
77383
77384             if (showLabels) {
77385               // Get a general idea of the width based on the length of the label
77386               _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
77387                 return op.title.length;
77388               })));
77389             } else {
77390               _menuWidth = 44;
77391             }
77392
77393             _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
77394             _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
77395
77396             var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
77397
77398
77399             var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
77400               return 'edit-menu-item edit-menu-item-' + d.id;
77401             }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
77402             .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
77403               // don't let button presses also act as map input - #1869
77404               d3_event.stopPropagation();
77405             }).on('mouseenter.highlight', function (d3_event, d) {
77406               if (!d.relatedEntityIds || select(this).classed('disabled')) return;
77407               utilHighlightEntities(d.relatedEntityIds(), true, context);
77408             }).on('mouseleave.highlight', function (d3_event, d) {
77409               if (!d.relatedEntityIds) return;
77410               utilHighlightEntities(d.relatedEntityIds(), false, context);
77411             });
77412             buttonsEnter.each(function (d) {
77413               var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
77414
77415               _tooltips.push(tooltip);
77416
77417               select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
77418             });
77419
77420             if (showLabels) {
77421               buttonsEnter.append('span').attr('class', 'label').html(function (d) {
77422                 return d.title;
77423               });
77424             } // update
77425
77426
77427             buttonsEnter.merge(buttons).classed('disabled', function (d) {
77428               return d.disabled();
77429             });
77430             updatePosition();
77431             var initialScale = context.projection.scale();
77432             context.map().on('move.edit-menu', function () {
77433               if (initialScale !== context.projection.scale()) {
77434                 editMenu.close();
77435               }
77436             }).on('drawn.edit-menu', function (info) {
77437               if (info.full) updatePosition();
77438             });
77439             var lastPointerUpType; // `pointerup` is always called before `click`
77440
77441             function pointerup(d3_event) {
77442               lastPointerUpType = d3_event.pointerType;
77443             }
77444
77445             function click(d3_event, operation) {
77446               d3_event.stopPropagation();
77447
77448               if (operation.relatedEntityIds) {
77449                 utilHighlightEntities(operation.relatedEntityIds(), false, context);
77450               }
77451
77452               if (operation.disabled()) {
77453                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
77454                   // there are no tooltips for touch interactions so flash feedback instead
77455                   context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
77456                 }
77457               } else {
77458                 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
77459                   context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
77460                 }
77461
77462                 operation();
77463                 editMenu.close();
77464               }
77465
77466               lastPointerUpType = null;
77467             }
77468
77469             dispatch$1.call('toggled', this, true);
77470           };
77471
77472           function updatePosition() {
77473             if (!_menu || _menu.empty()) return;
77474             var anchorLoc = context.projection(_anchorLocLonLat);
77475             var viewport = context.surfaceRect();
77476
77477             if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
77478               // close the menu if it's gone offscreen
77479               editMenu.close();
77480               return;
77481             }
77482
77483             var menuLeft = displayOnLeft(viewport);
77484             var offset = [0, 0];
77485             offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
77486
77487             if (_menuTop) {
77488               if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
77489                 // menu is near top viewport edge, shift downward
77490                 offset[1] = -anchorLoc[1] + _vpTopMargin;
77491               } else {
77492                 offset[1] = -_menuHeight;
77493               }
77494             } else {
77495               if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
77496                 // menu is near bottom viewport edge, shift upwards
77497                 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
77498               } else {
77499                 offset[1] = 0;
77500               }
77501             }
77502
77503             var origin = geoVecAdd(anchorLoc, offset);
77504
77505             _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
77506
77507             var tooltipSide = tooltipPosition(viewport, menuLeft);
77508
77509             _tooltips.forEach(function (tooltip) {
77510               tooltip.placement(tooltipSide);
77511             });
77512
77513             function displayOnLeft(viewport) {
77514               if (_mainLocalizer.textDirection() === 'ltr') {
77515                 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
77516                   // right menu would be too close to the right viewport edge, go left
77517                   return true;
77518                 } // prefer right menu
77519
77520
77521                 return false;
77522               } else {
77523                 // rtl
77524                 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
77525                   // left menu would be too close to the left viewport edge, go right
77526                   return false;
77527                 } // prefer left menu
77528
77529
77530                 return true;
77531               }
77532             }
77533
77534             function tooltipPosition(viewport, menuLeft) {
77535               if (_mainLocalizer.textDirection() === 'ltr') {
77536                 if (menuLeft) {
77537                   // if there's not room for a right-side menu then there definitely
77538                   // isn't room for right-side tooltips
77539                   return 'left';
77540                 }
77541
77542                 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
77543                   // right tooltips would be too close to the right viewport edge, go left
77544                   return 'left';
77545                 } // prefer right tooltips
77546
77547
77548                 return 'right';
77549               } else {
77550                 // rtl
77551                 if (!menuLeft) {
77552                   return 'right';
77553                 }
77554
77555                 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
77556                   // left tooltips would be too close to the left viewport edge, go right
77557                   return 'right';
77558                 } // prefer left tooltips
77559
77560
77561                 return 'left';
77562               }
77563             }
77564           }
77565
77566           editMenu.close = function () {
77567             context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
77568
77569             _menu.remove();
77570
77571             _tooltips = [];
77572             dispatch$1.call('toggled', this, false);
77573           };
77574
77575           editMenu.anchorLoc = function (val) {
77576             if (!arguments.length) return _anchorLoc;
77577             _anchorLoc = val;
77578             _anchorLocLonLat = context.projection.invert(_anchorLoc);
77579             return editMenu;
77580           };
77581
77582           editMenu.triggerType = function (val) {
77583             if (!arguments.length) return _triggerType;
77584             _triggerType = val;
77585             return editMenu;
77586           };
77587
77588           editMenu.operations = function (val) {
77589             if (!arguments.length) return _operations;
77590             _operations = val;
77591             return editMenu;
77592           };
77593
77594           return utilRebind(editMenu, dispatch$1, 'on');
77595         }
77596
77597         function uiFeatureInfo(context) {
77598           function update(selection) {
77599             var features = context.features();
77600             var stats = features.stats();
77601             var count = 0;
77602             var hiddenList = features.hidden().map(function (k) {
77603               if (stats[k]) {
77604                 count += stats[k];
77605                 return _t('inspector.title_count', {
77606                   title: _t.html('feature.' + k + '.description'),
77607                   count: stats[k]
77608                 });
77609               }
77610
77611               return null;
77612             }).filter(Boolean);
77613             selection.html('');
77614
77615             if (hiddenList.length) {
77616               var tooltipBehavior = uiTooltip().placement('top').title(function () {
77617                 return hiddenList.join('<br/>');
77618               });
77619               selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
77620                 count: count
77621               })).call(tooltipBehavior).on('click', function (d3_event) {
77622                 tooltipBehavior.hide();
77623                 d3_event.preventDefault(); // open the Map Data pane
77624
77625                 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
77626               });
77627             }
77628
77629             selection.classed('hide', !hiddenList.length);
77630           }
77631
77632           return function (selection) {
77633             update(selection);
77634             context.features().on('change.feature_info', function () {
77635               update(selection);
77636             });
77637           };
77638         }
77639
77640         function uiFlash(context) {
77641           var _flashTimer;
77642
77643           var _duration = 2000;
77644           var _iconName = '#iD-icon-no';
77645           var _iconClass = 'disabled';
77646           var _label = '';
77647
77648           function flash() {
77649             if (_flashTimer) {
77650               _flashTimer.stop();
77651             }
77652
77653             context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
77654             context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
77655             var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
77656
77657             var contentEnter = content.enter().append('div').attr('class', 'flash-content');
77658             var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
77659             iconEnter.append('circle').attr('r', 9);
77660             iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
77661             contentEnter.append('div').attr('class', 'flash-text'); // Update
77662
77663             content = content.merge(contentEnter);
77664             content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
77665             content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
77666             content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
77667             _flashTimer = d3_timeout(function () {
77668               _flashTimer = null;
77669               context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
77670               context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
77671             }, _duration);
77672             return content;
77673           }
77674
77675           flash.duration = function (_) {
77676             if (!arguments.length) return _duration;
77677             _duration = _;
77678             return flash;
77679           };
77680
77681           flash.label = function (_) {
77682             if (!arguments.length) return _label;
77683             _label = _;
77684             return flash;
77685           };
77686
77687           flash.iconName = function (_) {
77688             if (!arguments.length) return _iconName;
77689             _iconName = _;
77690             return flash;
77691           };
77692
77693           flash.iconClass = function (_) {
77694             if (!arguments.length) return _iconClass;
77695             _iconClass = _;
77696             return flash;
77697           };
77698
77699           return flash;
77700         }
77701
77702         function uiFullScreen(context) {
77703           var element = context.container().node(); // var button = d3_select(null);
77704
77705           function getFullScreenFn() {
77706             if (element.requestFullscreen) {
77707               return element.requestFullscreen;
77708             } else if (element.msRequestFullscreen) {
77709               return element.msRequestFullscreen;
77710             } else if (element.mozRequestFullScreen) {
77711               return element.mozRequestFullScreen;
77712             } else if (element.webkitRequestFullscreen) {
77713               return element.webkitRequestFullscreen;
77714             }
77715           }
77716
77717           function getExitFullScreenFn() {
77718             if (document.exitFullscreen) {
77719               return document.exitFullscreen;
77720             } else if (document.msExitFullscreen) {
77721               return document.msExitFullscreen;
77722             } else if (document.mozCancelFullScreen) {
77723               return document.mozCancelFullScreen;
77724             } else if (document.webkitExitFullscreen) {
77725               return document.webkitExitFullscreen;
77726             }
77727           }
77728
77729           function isFullScreen() {
77730             return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
77731           }
77732
77733           function isSupported() {
77734             return !!getFullScreenFn();
77735           }
77736
77737           function fullScreen(d3_event) {
77738             d3_event.preventDefault();
77739
77740             if (!isFullScreen()) {
77741               // button.classed('active', true);
77742               getFullScreenFn().apply(element);
77743             } else {
77744               // button.classed('active', false);
77745               getExitFullScreenFn().apply(document);
77746             }
77747           }
77748
77749           return function () {
77750             // selection) {
77751             if (!isSupported()) return; // button = selection.append('button')
77752             //     .attr('title', t('full_screen'))
77753             //     .on('click', fullScreen)
77754             //     .call(tooltip);
77755             // button.append('span')
77756             //     .attr('class', 'icon full-screen');
77757
77758             var detected = utilDetect();
77759             var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
77760             context.keybinding().on(keys, fullScreen);
77761           };
77762         }
77763
77764         function uiGeolocate(context) {
77765           var _geolocationOptions = {
77766             // prioritize speed and power usage over precision
77767             enableHighAccuracy: false,
77768             // don't hang indefinitely getting the location
77769             timeout: 6000 // 6sec
77770
77771           };
77772
77773           var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
77774
77775           var _layer = context.layers().layer('geolocate');
77776
77777           var _position;
77778
77779           var _extent;
77780
77781           var _timeoutID;
77782
77783           var _button = select(null);
77784
77785           function click() {
77786             if (context.inIntro()) return;
77787
77788             if (!_layer.enabled() && !_locating.isShown()) {
77789               // This timeout ensures that we still call finish() even if
77790               // the user declines to share their location in Firefox
77791               _timeoutID = setTimeout(error, 10000
77792               /* 10sec */
77793               );
77794               context.container().call(_locating); // get the latest position even if we already have one
77795
77796               navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
77797             } else {
77798               _locating.close();
77799
77800               _layer.enabled(null, false);
77801
77802               updateButtonState();
77803             }
77804           }
77805
77806           function zoomTo() {
77807             context.enter(modeBrowse(context));
77808             var map = context.map();
77809
77810             _layer.enabled(_position, true);
77811
77812             updateButtonState();
77813             map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
77814           }
77815
77816           function success(geolocation) {
77817             _position = geolocation;
77818             var coords = _position.coords;
77819             _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
77820             zoomTo();
77821             finish();
77822           }
77823
77824           function error() {
77825             if (_position) {
77826               // use the position from a previous call if we have one
77827               zoomTo();
77828             } else {
77829               context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
77830             }
77831
77832             finish();
77833           }
77834
77835           function finish() {
77836             _locating.close(); // unblock ui
77837
77838
77839             if (_timeoutID) {
77840               clearTimeout(_timeoutID);
77841             }
77842
77843             _timeoutID = undefined;
77844           }
77845
77846           function updateButtonState() {
77847             _button.classed('active', _layer.enabled());
77848           }
77849
77850           return function (selection) {
77851             if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
77852             _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')]));
77853             context.keybinding().on(_t('geolocate.key'), click);
77854           };
77855         }
77856
77857         function uiPanelBackground(context) {
77858           var background = context.background();
77859           var _currSourceName = null;
77860           var _metadata = {};
77861           var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
77862
77863           var debouncedRedraw = debounce(redraw, 250);
77864
77865           function redraw(selection) {
77866             var source = background.baseLayerSource();
77867             if (!source) return;
77868             var isDG = source.id.match(/^DigitalGlobe/i) !== null;
77869             var sourceLabel = source.label();
77870
77871             if (_currSourceName !== sourceLabel) {
77872               _currSourceName = sourceLabel;
77873               _metadata = {};
77874             }
77875
77876             selection.html('');
77877             var list = selection.append('ul').attr('class', 'background-info');
77878             list.append('li').html(_currSourceName);
77879
77880             _metadataKeys.forEach(function (k) {
77881               // DigitalGlobe vintage is available in raster layers for now.
77882               if (isDG && k === 'vintage') return;
77883               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]);
77884             });
77885
77886             debouncedGetMetadata(selection);
77887             var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
77888             selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
77889               d3_event.preventDefault();
77890               context.setDebug('tile', !context.getDebug('tile'));
77891               selection.call(redraw);
77892             });
77893
77894             if (isDG) {
77895               var key = source.id + '-vintage';
77896               var sourceVintage = context.background().findSource(key);
77897               var showsVintage = context.background().showsLayer(sourceVintage);
77898               var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
77899               selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
77900                 d3_event.preventDefault();
77901                 context.background().toggleOverlayLayer(sourceVintage);
77902                 selection.call(redraw);
77903               });
77904             } // disable if necessary
77905
77906
77907             ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
77908               if (source.id !== layerId) {
77909                 var key = layerId + '-vintage';
77910                 var sourceVintage = context.background().findSource(key);
77911
77912                 if (context.background().showsLayer(sourceVintage)) {
77913                   context.background().toggleOverlayLayer(sourceVintage);
77914                 }
77915               }
77916             });
77917           }
77918
77919           var debouncedGetMetadata = debounce(getMetadata, 250);
77920
77921           function getMetadata(selection) {
77922             var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
77923
77924             if (tile.empty()) return;
77925             var sourceName = _currSourceName;
77926             var d = tile.datum();
77927             var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
77928             var center = context.map().center(); // update zoom
77929
77930             _metadata.zoom = String(zoom);
77931             selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
77932             if (!d || !d.length >= 3) return;
77933             background.baseLayerSource().getMetadata(center, d, function (err, result) {
77934               if (err || _currSourceName !== sourceName) return; // update vintage
77935
77936               var vintage = result.vintage;
77937               _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
77938               selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
77939
77940               _metadataKeys.forEach(function (k) {
77941                 if (k === 'zoom' || k === 'vintage') return; // done already
77942
77943                 var val = result[k];
77944                 _metadata[k] = val;
77945                 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
77946               });
77947             });
77948           }
77949
77950           var panel = function panel(selection) {
77951             selection.call(redraw);
77952             context.map().on('drawn.info-background', function () {
77953               selection.call(debouncedRedraw);
77954             }).on('move.info-background', function () {
77955               selection.call(debouncedGetMetadata);
77956             });
77957           };
77958
77959           panel.off = function () {
77960             context.map().on('drawn.info-background', null).on('move.info-background', null);
77961           };
77962
77963           panel.id = 'background';
77964           panel.label = _t.html('info_panels.background.title');
77965           panel.key = _t('info_panels.background.key');
77966           return panel;
77967         }
77968
77969         function uiPanelHistory(context) {
77970           var osm;
77971
77972           function displayTimestamp(timestamp) {
77973             if (!timestamp) return _t('info_panels.history.unknown');
77974             var options = {
77975               day: 'numeric',
77976               month: 'short',
77977               year: 'numeric',
77978               hour: 'numeric',
77979               minute: 'numeric',
77980               second: 'numeric'
77981             };
77982             var d = new Date(timestamp);
77983             if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
77984             return d.toLocaleString(_mainLocalizer.localeCode(), options);
77985           }
77986
77987           function displayUser(selection, userName) {
77988             if (!userName) {
77989               selection.append('span').html(_t.html('info_panels.history.unknown'));
77990               return;
77991             }
77992
77993             selection.append('span').attr('class', 'user-name').html(userName);
77994             var links = selection.append('div').attr('class', 'links');
77995
77996             if (osm) {
77997               links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
77998             }
77999
78000             links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
78001           }
78002
78003           function displayChangeset(selection, changeset) {
78004             if (!changeset) {
78005               selection.append('span').html(_t.html('info_panels.history.unknown'));
78006               return;
78007             }
78008
78009             selection.append('span').attr('class', 'changeset-id').html(changeset);
78010             var links = selection.append('div').attr('class', 'links');
78011
78012             if (osm) {
78013               links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
78014             }
78015
78016             links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
78017             links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
78018           }
78019
78020           function redraw(selection) {
78021             var selectedNoteID = context.selectedNoteID();
78022             osm = context.connection();
78023             var selected, note, entity;
78024
78025             if (selectedNoteID && osm) {
78026               // selected 1 note
78027               selected = [_t('note.note') + ' ' + selectedNoteID];
78028               note = osm.getNote(selectedNoteID);
78029             } else {
78030               // selected 1..n entities
78031               selected = context.selectedIDs().filter(function (e) {
78032                 return context.hasEntity(e);
78033               });
78034
78035               if (selected.length) {
78036                 entity = context.entity(selected[0]);
78037               }
78038             }
78039
78040             var singular = selected.length === 1 ? selected[0] : null;
78041             selection.html('');
78042             selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
78043               n: selected.length
78044             }));
78045             if (!singular) return;
78046
78047             if (entity) {
78048               selection.call(redrawEntity, entity);
78049             } else if (note) {
78050               selection.call(redrawNote, note);
78051             }
78052           }
78053
78054           function redrawNote(selection, note) {
78055             if (!note || note.isNew()) {
78056               selection.append('div').html(_t.html('info_panels.history.note_no_history'));
78057               return;
78058             }
78059
78060             var list = selection.append('ul');
78061             list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
78062
78063             if (note.comments.length) {
78064               list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
78065               list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
78066             }
78067
78068             if (osm) {
78069               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'));
78070             }
78071           }
78072
78073           function redrawEntity(selection, entity) {
78074             if (!entity || entity.isNew()) {
78075               selection.append('div').html(_t.html('info_panels.history.no_history'));
78076               return;
78077             }
78078
78079             var links = selection.append('div').attr('class', 'links');
78080
78081             if (osm) {
78082               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');
78083             }
78084
78085             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');
78086             var list = selection.append('ul');
78087             list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
78088             list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
78089             list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
78090             list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
78091           }
78092
78093           var panel = function panel(selection) {
78094             selection.call(redraw);
78095             context.map().on('drawn.info-history', function () {
78096               selection.call(redraw);
78097             });
78098             context.on('enter.info-history', function () {
78099               selection.call(redraw);
78100             });
78101           };
78102
78103           panel.off = function () {
78104             context.map().on('drawn.info-history', null);
78105             context.on('enter.info-history', null);
78106           };
78107
78108           panel.id = 'history';
78109           panel.label = _t.html('info_panels.history.title');
78110           panel.key = _t('info_panels.history.key');
78111           return panel;
78112         }
78113
78114         var OSM_PRECISION = 7;
78115         /**
78116          * Returns a localized representation of the given length measurement.
78117          *
78118          * @param {Number} m area in meters
78119          * @param {Boolean} isImperial true for U.S. customary units; false for metric
78120          */
78121
78122         function displayLength(m, isImperial) {
78123           var d = m * (isImperial ? 3.28084 : 1);
78124           var unit;
78125
78126           if (isImperial) {
78127             if (d >= 5280) {
78128               d /= 5280;
78129               unit = 'miles';
78130             } else {
78131               unit = 'feet';
78132             }
78133           } else {
78134             if (d >= 1000) {
78135               d /= 1000;
78136               unit = 'kilometers';
78137             } else {
78138               unit = 'meters';
78139             }
78140           }
78141
78142           return _t('units.' + unit, {
78143             quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
78144               maximumSignificantDigits: 4
78145             })
78146           });
78147         }
78148         /**
78149          * Returns a localized representation of the given area measurement.
78150          *
78151          * @param {Number} m2 area in square meters
78152          * @param {Boolean} isImperial true for U.S. customary units; false for metric
78153          */
78154
78155         function displayArea(m2, isImperial) {
78156           var locale = _mainLocalizer.localeCode();
78157           var d = m2 * (isImperial ? 10.7639111056 : 1);
78158           var d1, d2, area;
78159           var unit1 = '';
78160           var unit2 = '';
78161
78162           if (isImperial) {
78163             if (d >= 6969600) {
78164               // > 0.25mi² show mi²
78165               d1 = d / 27878400;
78166               unit1 = 'square_miles';
78167             } else {
78168               d1 = d;
78169               unit1 = 'square_feet';
78170             }
78171
78172             if (d > 4356 && d < 43560000) {
78173               // 0.1 - 1000 acres
78174               d2 = d / 43560;
78175               unit2 = 'acres';
78176             }
78177           } else {
78178             if (d >= 250000) {
78179               // > 0.25km² show km²
78180               d1 = d / 1000000;
78181               unit1 = 'square_kilometers';
78182             } else {
78183               d1 = d;
78184               unit1 = 'square_meters';
78185             }
78186
78187             if (d > 1000 && d < 10000000) {
78188               // 0.1 - 1000 hectares
78189               d2 = d / 10000;
78190               unit2 = 'hectares';
78191             }
78192           }
78193
78194           area = _t('units.' + unit1, {
78195             quantity: d1.toLocaleString(locale, {
78196               maximumSignificantDigits: 4
78197             })
78198           });
78199
78200           if (d2) {
78201             return _t('units.area_pair', {
78202               area1: area,
78203               area2: _t('units.' + unit2, {
78204                 quantity: d2.toLocaleString(locale, {
78205                   maximumSignificantDigits: 2
78206                 })
78207               })
78208             });
78209           } else {
78210             return area;
78211           }
78212         }
78213
78214         function wrap$2(x, min, max) {
78215           var d = max - min;
78216           return ((x - min) % d + d) % d + min;
78217         }
78218
78219         function clamp$1(x, min, max) {
78220           return Math.max(min, Math.min(x, max));
78221         }
78222
78223         function displayCoordinate(deg, pos, neg) {
78224           var locale = _mainLocalizer.localeCode();
78225           var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
78226           var sec = (min - Math.floor(min)) * 60;
78227           var displayDegrees = _t('units.arcdegrees', {
78228             quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
78229           });
78230           var displayCoordinate;
78231
78232           if (Math.floor(sec) > 0) {
78233             displayCoordinate = displayDegrees + _t('units.arcminutes', {
78234               quantity: Math.floor(min).toLocaleString(locale)
78235             }) + _t('units.arcseconds', {
78236               quantity: Math.round(sec).toLocaleString(locale)
78237             });
78238           } else if (Math.floor(min) > 0) {
78239             displayCoordinate = displayDegrees + _t('units.arcminutes', {
78240               quantity: Math.round(min).toLocaleString(locale)
78241             });
78242           } else {
78243             displayCoordinate = _t('units.arcdegrees', {
78244               quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
78245             });
78246           }
78247
78248           if (deg === 0) {
78249             return displayCoordinate;
78250           } else {
78251             return _t('units.coordinate', {
78252               coordinate: displayCoordinate,
78253               direction: _t('units.' + (deg > 0 ? pos : neg))
78254             });
78255           }
78256         }
78257         /**
78258          * Returns given coordinate pair in degree-minute-second format.
78259          *
78260          * @param {Array<Number>} coord longitude and latitude
78261          */
78262
78263
78264         function dmsCoordinatePair(coord) {
78265           return _t('units.coordinate_pair', {
78266             latitude: displayCoordinate(clamp$1(coord[1], -90, 90), 'north', 'south'),
78267             longitude: displayCoordinate(wrap$2(coord[0], -180, 180), 'east', 'west')
78268           });
78269         }
78270         /**
78271          * Returns the given coordinate pair in decimal format.
78272          * note: unlocalized to avoid comma ambiguity - see #4765
78273          *
78274          * @param {Array<Number>} coord longitude and latitude
78275          */
78276
78277         function decimalCoordinatePair(coord) {
78278           return _t('units.coordinate_pair', {
78279             latitude: clamp$1(coord[1], -90, 90).toFixed(OSM_PRECISION),
78280             longitude: wrap$2(coord[0], -180, 180).toFixed(OSM_PRECISION)
78281           });
78282         }
78283
78284         function uiPanelLocation(context) {
78285           var currLocation = '';
78286
78287           function redraw(selection) {
78288             selection.html('');
78289             var list = selection.append('ul'); // Mouse coordinates
78290
78291             var coord = context.map().mouseCoordinates();
78292
78293             if (coord.some(isNaN)) {
78294               coord = context.map().center();
78295             }
78296
78297             list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
78298
78299             selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
78300             debouncedGetLocation(selection, coord);
78301           }
78302
78303           var debouncedGetLocation = debounce(getLocation, 250);
78304
78305           function getLocation(selection, coord) {
78306             if (!services.geocoder) {
78307               currLocation = _t('info_panels.location.unknown_location');
78308               selection.selectAll('.location-info').html(currLocation);
78309             } else {
78310               services.geocoder.reverse(coord, function (err, result) {
78311                 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
78312                 selection.selectAll('.location-info').html(currLocation);
78313               });
78314             }
78315           }
78316
78317           var panel = function panel(selection) {
78318             selection.call(redraw);
78319             context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
78320               selection.call(redraw);
78321             });
78322           };
78323
78324           panel.off = function () {
78325             context.surface().on('.info-location', null);
78326           };
78327
78328           panel.id = 'location';
78329           panel.label = _t.html('info_panels.location.title');
78330           panel.key = _t('info_panels.location.key');
78331           return panel;
78332         }
78333
78334         function uiPanelMeasurement(context) {
78335           function radiansToMeters(r) {
78336             // using WGS84 authalic radius (6371007.1809 m)
78337             return r * 6371007.1809;
78338           }
78339
78340           function steradiansToSqmeters(r) {
78341             // http://gis.stackexchange.com/a/124857/40446
78342             return r / (4 * Math.PI) * 510065621724000;
78343           }
78344
78345           function toLineString(feature) {
78346             if (feature.type === 'LineString') return feature;
78347             var result = {
78348               type: 'LineString',
78349               coordinates: []
78350             };
78351
78352             if (feature.type === 'Polygon') {
78353               result.coordinates = feature.coordinates[0];
78354             } else if (feature.type === 'MultiPolygon') {
78355               result.coordinates = feature.coordinates[0][0];
78356             }
78357
78358             return result;
78359           }
78360
78361           var _isImperial = !_mainLocalizer.usesMetric();
78362
78363           function redraw(selection) {
78364             var graph = context.graph();
78365             var selectedNoteID = context.selectedNoteID();
78366             var osm = services.osm;
78367             var localeCode = _mainLocalizer.localeCode();
78368             var heading;
78369             var center, location, centroid;
78370             var closed, geometry;
78371             var totalNodeCount,
78372                 length = 0,
78373                 area = 0,
78374                 distance;
78375
78376             if (selectedNoteID && osm) {
78377               // selected 1 note
78378               var note = osm.getNote(selectedNoteID);
78379               heading = _t('note.note') + ' ' + selectedNoteID;
78380               location = note.loc;
78381               geometry = 'note';
78382             } else {
78383               // selected 1..n entities
78384               var selectedIDs = context.selectedIDs().filter(function (id) {
78385                 return context.hasEntity(id);
78386               });
78387               var selected = selectedIDs.map(function (id) {
78388                 return context.entity(id);
78389               });
78390               heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
78391                 n: selected.length
78392               });
78393
78394               if (selected.length) {
78395                 var extent = geoExtent();
78396
78397                 for (var i in selected) {
78398                   var entity = selected[i];
78399
78400                   extent._extend(entity.extent(graph));
78401
78402                   geometry = entity.geometry(graph);
78403
78404                   if (geometry === 'line' || geometry === 'area') {
78405                     closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
78406                     var feature = entity.asGeoJSON(graph);
78407                     length += radiansToMeters(d3_geoLength(toLineString(feature))); // d3_geoCentroid is wrong for counterclockwise-wound polygons, so wind them clockwise
78408
78409                     centroid = d3_geoCentroid(geojsonRewind(Object.assign({}, feature), true));
78410
78411                     if (closed) {
78412                       area += steradiansToSqmeters(entity.area(graph));
78413                     }
78414                   }
78415                 }
78416
78417                 if (selected.length > 1) {
78418                   geometry = null;
78419                   closed = null;
78420                   centroid = null;
78421                 }
78422
78423                 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
78424                   distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
78425                 }
78426
78427                 if (selected.length === 1 && selected[0].type === 'node') {
78428                   location = selected[0].loc;
78429                 } else {
78430                   totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
78431                 }
78432
78433                 if (!location && !centroid) {
78434                   center = extent.center();
78435                 }
78436               }
78437             }
78438
78439             selection.html('');
78440
78441             if (heading) {
78442               selection.append('h4').attr('class', 'measurement-heading').html(heading);
78443             }
78444
78445             var list = selection.append('ul');
78446             var coordItem;
78447
78448             if (geometry) {
78449               list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
78450             }
78451
78452             if (totalNodeCount) {
78453               list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
78454             }
78455
78456             if (area) {
78457               list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
78458             }
78459
78460             if (length) {
78461               list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
78462             }
78463
78464             if (typeof distance === 'number') {
78465               list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
78466             }
78467
78468             if (location) {
78469               coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
78470               coordItem.append('span').html(dmsCoordinatePair(location));
78471               coordItem.append('span').html(decimalCoordinatePair(location));
78472             }
78473
78474             if (centroid) {
78475               coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
78476               coordItem.append('span').html(dmsCoordinatePair(centroid));
78477               coordItem.append('span').html(decimalCoordinatePair(centroid));
78478             }
78479
78480             if (center) {
78481               coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
78482               coordItem.append('span').html(dmsCoordinatePair(center));
78483               coordItem.append('span').html(decimalCoordinatePair(center));
78484             }
78485
78486             if (length || area || typeof distance === 'number') {
78487               var toggle = _isImperial ? 'imperial' : 'metric';
78488               selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
78489                 d3_event.preventDefault();
78490                 _isImperial = !_isImperial;
78491                 selection.call(redraw);
78492               });
78493             }
78494           }
78495
78496           var panel = function panel(selection) {
78497             selection.call(redraw);
78498             context.map().on('drawn.info-measurement', function () {
78499               selection.call(redraw);
78500             });
78501             context.on('enter.info-measurement', function () {
78502               selection.call(redraw);
78503             });
78504           };
78505
78506           panel.off = function () {
78507             context.map().on('drawn.info-measurement', null);
78508             context.on('enter.info-measurement', null);
78509           };
78510
78511           panel.id = 'measurement';
78512           panel.label = _t.html('info_panels.measurement.title');
78513           panel.key = _t('info_panels.measurement.key');
78514           return panel;
78515         }
78516
78517         var uiInfoPanels = {
78518           background: uiPanelBackground,
78519           history: uiPanelHistory,
78520           location: uiPanelLocation,
78521           measurement: uiPanelMeasurement
78522         };
78523
78524         function uiInfo(context) {
78525           var ids = Object.keys(uiInfoPanels);
78526           var wasActive = ['measurement'];
78527           var panels = {};
78528           var active = {}; // create panels
78529
78530           ids.forEach(function (k) {
78531             if (!panels[k]) {
78532               panels[k] = uiInfoPanels[k](context);
78533               active[k] = false;
78534             }
78535           });
78536
78537           function info(selection) {
78538             function redraw() {
78539               var activeids = ids.filter(function (k) {
78540                 return active[k];
78541               }).sort();
78542               var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
78543                 return k;
78544               });
78545               containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
78546                 select(this).call(panels[d].off).remove();
78547               });
78548               var enter = containers.enter().append('div').attr('class', function (d) {
78549                 return 'fillD2 panel-container panel-container-' + d;
78550               });
78551               enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
78552               var title = enter.append('div').attr('class', 'panel-title fillD2');
78553               title.append('h3').html(function (d) {
78554                 return panels[d].label;
78555               });
78556               title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
78557                 d3_event.stopImmediatePropagation();
78558                 d3_event.preventDefault();
78559                 info.toggle(d);
78560               }).call(svgIcon('#iD-icon-close'));
78561               enter.append('div').attr('class', function (d) {
78562                 return 'panel-content panel-content-' + d;
78563               }); // redraw the panels
78564
78565               infoPanels.selectAll('.panel-content').each(function (d) {
78566                 select(this).call(panels[d]);
78567               });
78568             }
78569
78570             info.toggle = function (which) {
78571               var activeids = ids.filter(function (k) {
78572                 return active[k];
78573               });
78574
78575               if (which) {
78576                 // toggle one
78577                 active[which] = !active[which];
78578
78579                 if (activeids.length === 1 && activeids[0] === which) {
78580                   // none active anymore
78581                   wasActive = [which];
78582                 }
78583
78584                 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
78585               } else {
78586                 // toggle all
78587                 if (activeids.length) {
78588                   wasActive = activeids;
78589                   activeids.forEach(function (k) {
78590                     active[k] = false;
78591                   });
78592                 } else {
78593                   wasActive.forEach(function (k) {
78594                     active[k] = true;
78595                   });
78596                 }
78597               }
78598
78599               redraw();
78600             };
78601
78602             var infoPanels = selection.selectAll('.info-panels').data([0]);
78603             infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
78604             redraw();
78605             context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
78606               d3_event.stopImmediatePropagation();
78607               d3_event.preventDefault();
78608               info.toggle();
78609             });
78610             ids.forEach(function (k) {
78611               var key = _t('info_panels.' + k + '.key', {
78612                 "default": null
78613               });
78614               if (!key) return;
78615               context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
78616                 d3_event.stopImmediatePropagation();
78617                 d3_event.preventDefault();
78618                 info.toggle(k);
78619               });
78620             });
78621           }
78622
78623           return info;
78624         }
78625
78626         function pointBox(loc, context) {
78627           var rect = context.surfaceRect();
78628           var point = context.curtainProjection(loc);
78629           return {
78630             left: point[0] + rect.left - 40,
78631             top: point[1] + rect.top - 60,
78632             width: 80,
78633             height: 90
78634           };
78635         }
78636         function pad(locOrBox, padding, context) {
78637           var box;
78638
78639           if (locOrBox instanceof Array) {
78640             var rect = context.surfaceRect();
78641             var point = context.curtainProjection(locOrBox);
78642             box = {
78643               left: point[0] + rect.left,
78644               top: point[1] + rect.top
78645             };
78646           } else {
78647             box = locOrBox;
78648           }
78649
78650           return {
78651             left: box.left - padding,
78652             top: box.top - padding,
78653             width: (box.width || 0) + 2 * padding,
78654             height: (box.width || 0) + 2 * padding
78655           };
78656         }
78657         function icon(name, svgklass, useklass) {
78658           return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
78659         }
78660         var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
78661         // label replacements suitable for tutorials and documentation. Optionally supplemented
78662         // with custom `replacements`
78663
78664         function helpHtml(id, replacements) {
78665           // only load these the first time
78666           if (!helpStringReplacements) helpStringReplacements = {
78667             // insert icons corresponding to various UI elements
78668             point_icon: icon('#iD-icon-point', 'inline'),
78669             line_icon: icon('#iD-icon-line', 'inline'),
78670             area_icon: icon('#iD-icon-area', 'inline'),
78671             note_icon: icon('#iD-icon-note', 'inline add-note'),
78672             plus: icon('#iD-icon-plus', 'inline'),
78673             minus: icon('#iD-icon-minus', 'inline'),
78674             layers_icon: icon('#iD-icon-layers', 'inline'),
78675             data_icon: icon('#iD-icon-data', 'inline'),
78676             inspect: icon('#iD-icon-inspect', 'inline'),
78677             help_icon: icon('#iD-icon-help', 'inline'),
78678             undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
78679             redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
78680             save_icon: icon('#iD-icon-save', 'inline'),
78681             // operation icons
78682             circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
78683             continue_icon: icon('#iD-operation-continue', 'inline operation'),
78684             copy_icon: icon('#iD-operation-copy', 'inline operation'),
78685             delete_icon: icon('#iD-operation-delete', 'inline operation'),
78686             disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
78687             downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
78688             extract_icon: icon('#iD-operation-extract', 'inline operation'),
78689             merge_icon: icon('#iD-operation-merge', 'inline operation'),
78690             move_icon: icon('#iD-operation-move', 'inline operation'),
78691             orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
78692             paste_icon: icon('#iD-operation-paste', 'inline operation'),
78693             reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
78694             reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
78695             reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
78696             rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
78697             split_icon: icon('#iD-operation-split', 'inline operation'),
78698             straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
78699             // interaction icons
78700             leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
78701             rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
78702             mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
78703             tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
78704             doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
78705             longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
78706             touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
78707             pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
78708             // insert keys; may be localized and platform-dependent
78709             shift: uiCmd.display('⇧'),
78710             alt: uiCmd.display('⌥'),
78711             "return": uiCmd.display('↵'),
78712             esc: _t.html('shortcuts.key.esc'),
78713             space: _t.html('shortcuts.key.space'),
78714             add_note_key: _t.html('modes.add_note.key'),
78715             help_key: _t.html('help.key'),
78716             shortcuts_key: _t.html('shortcuts.toggle.key'),
78717             // reference localized UI labels directly so that they'll always match
78718             save: _t.html('save.title'),
78719             undo: _t.html('undo.title'),
78720             redo: _t.html('redo.title'),
78721             upload: _t.html('commit.save'),
78722             point: _t.html('modes.add_point.title'),
78723             line: _t.html('modes.add_line.title'),
78724             area: _t.html('modes.add_area.title'),
78725             note: _t.html('modes.add_note.label'),
78726             circularize: _t.html('operations.circularize.title'),
78727             "continue": _t.html('operations.continue.title'),
78728             copy: _t.html('operations.copy.title'),
78729             "delete": _t.html('operations.delete.title'),
78730             disconnect: _t.html('operations.disconnect.title'),
78731             downgrade: _t.html('operations.downgrade.title'),
78732             extract: _t.html('operations.extract.title'),
78733             merge: _t.html('operations.merge.title'),
78734             move: _t.html('operations.move.title'),
78735             orthogonalize: _t.html('operations.orthogonalize.title'),
78736             paste: _t.html('operations.paste.title'),
78737             reflect_long: _t.html('operations.reflect.title.long'),
78738             reflect_short: _t.html('operations.reflect.title.short'),
78739             reverse: _t.html('operations.reverse.title'),
78740             rotate: _t.html('operations.rotate.title'),
78741             split: _t.html('operations.split.title'),
78742             straighten: _t.html('operations.straighten.title'),
78743             map_data: _t.html('map_data.title'),
78744             osm_notes: _t.html('map_data.layers.notes.title'),
78745             fields: _t.html('inspector.fields'),
78746             tags: _t.html('inspector.tags'),
78747             relations: _t.html('inspector.relations'),
78748             new_relation: _t.html('inspector.new_relation'),
78749             turn_restrictions: _t.html('presets.fields.restrictions.label'),
78750             background_settings: _t.html('background.description'),
78751             imagery_offset: _t.html('background.fix_misalignment'),
78752             start_the_walkthrough: _t.html('splash.walkthrough'),
78753             help: _t.html('help.title'),
78754             ok: _t.html('intro.ok')
78755           };
78756           var reps;
78757
78758           if (replacements) {
78759             reps = Object.assign(replacements, helpStringReplacements);
78760           } else {
78761             reps = helpStringReplacements;
78762           }
78763
78764           return _t.html(id, reps) // use keyboard key styling for shortcuts
78765           .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
78766         }
78767
78768         function slugify(text) {
78769           return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
78770           .replace(/[^\w\-]+/g, '') // Remove all non-word chars
78771           .replace(/\-\-+/g, '-') // Replace multiple - with single -
78772           .replace(/^-+/, '') // Trim - from start of text
78773           .replace(/-+$/, ''); // Trim - from end of text
78774         } // console warning for missing walkthrough names
78775
78776
78777         var missingStrings = {};
78778
78779         function checkKey(key, text) {
78780           if (_t(key, {
78781             "default": undefined
78782           }) === undefined) {
78783             if (missingStrings.hasOwnProperty(key)) return; // warn once
78784
78785             missingStrings[key] = text;
78786             var missing = key + ': ' + text;
78787             if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
78788           }
78789         }
78790
78791         function localize(obj) {
78792           var key; // Assign name if entity has one..
78793
78794           var name = obj.tags && obj.tags.name;
78795
78796           if (name) {
78797             key = 'intro.graph.name.' + slugify(name);
78798             obj.tags.name = _t(key, {
78799               "default": name
78800             });
78801             checkKey(key, name);
78802           } // Assign street name if entity has one..
78803
78804
78805           var street = obj.tags && obj.tags['addr:street'];
78806
78807           if (street) {
78808             key = 'intro.graph.name.' + slugify(street);
78809             obj.tags['addr:street'] = _t(key, {
78810               "default": street
78811             });
78812             checkKey(key, street); // Add address details common across walkthrough..
78813
78814             var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
78815             addrTags.forEach(function (k) {
78816               var key = 'intro.graph.' + k;
78817               var tag = 'addr:' + k;
78818               var val = obj.tags && obj.tags[tag];
78819               var str = _t(key, {
78820                 "default": val
78821               });
78822
78823               if (str) {
78824                 if (str.match(/^<.*>$/) !== null) {
78825                   delete obj.tags[tag];
78826                 } else {
78827                   obj.tags[tag] = str;
78828                 }
78829               }
78830             });
78831           }
78832
78833           return obj;
78834         } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
78835
78836         function isMostlySquare(points) {
78837           // note: uses 15 here instead of the 12 from actionOrthogonalize because
78838           // actionOrthogonalize can actually straighten some larger angles as it iterates
78839           var threshold = 15; // degrees within right or straight
78840
78841           var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
78842
78843           var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
78844
78845           for (var i = 0; i < points.length; i++) {
78846             var a = points[(i - 1 + points.length) % points.length];
78847             var origin = points[i];
78848             var b = points[(i + 1) % points.length];
78849             var dotp = geoVecNormalizedDot(a, b, origin);
78850             var mag = Math.abs(dotp);
78851
78852             if (mag > lowerBound && mag < upperBound) {
78853               return false;
78854             }
78855           }
78856
78857           return true;
78858         }
78859         function selectMenuItem(context, operation) {
78860           return context.container().select('.edit-menu .edit-menu-item-' + operation);
78861         }
78862         function transitionTime(point1, point2) {
78863           var distance = geoSphericalDistance(point1, point2);
78864           if (distance === 0) return 0;else if (distance < 80) return 500;else return 1000;
78865         }
78866
78867         function uiCurtain(containerNode) {
78868           var surface = select(null),
78869               tooltip = select(null),
78870               darkness = select(null);
78871
78872           function curtain(selection) {
78873             surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
78874             darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
78875             select(window).on('resize.curtain', resize);
78876             tooltip = selection.append('div').attr('class', 'tooltip');
78877             tooltip.append('div').attr('class', 'popover-arrow');
78878             tooltip.append('div').attr('class', 'popover-inner');
78879             resize();
78880
78881             function resize() {
78882               surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
78883               curtain.cut(darkness.datum());
78884             }
78885           }
78886           /**
78887            * Reveal cuts the curtain to highlight the given box,
78888            * and shows a tooltip with instructions next to the box.
78889            *
78890            * @param  {String|ClientRect} [box]   box used to cut the curtain
78891            * @param  {String}    [text]          text for a tooltip
78892            * @param  {Object}    [options]
78893            * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
78894            * @param  {integer}   [options.duration]        transition time in milliseconds
78895            * @param  {string}    [options.buttonText]      if set, create a button with this text label
78896            * @param  {function}  [options.buttonCallback]  if set, the callback for the button
78897            * @param  {function}  [options.padding]         extra margin in px to put around bbox
78898            * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
78899            */
78900
78901
78902           curtain.reveal = function (box, html, options) {
78903             options = options || {};
78904
78905             if (typeof box === 'string') {
78906               box = select(box).node();
78907             }
78908
78909             if (box && box.getBoundingClientRect) {
78910               box = copyBox(box.getBoundingClientRect());
78911               var containerRect = containerNode.getBoundingClientRect();
78912               box.top -= containerRect.top;
78913               box.left -= containerRect.left;
78914             }
78915
78916             if (box && options.padding) {
78917               box.top -= options.padding;
78918               box.left -= options.padding;
78919               box.bottom += options.padding;
78920               box.right += options.padding;
78921               box.height += options.padding * 2;
78922               box.width += options.padding * 2;
78923             }
78924
78925             var tooltipBox;
78926
78927             if (options.tooltipBox) {
78928               tooltipBox = options.tooltipBox;
78929
78930               if (typeof tooltipBox === 'string') {
78931                 tooltipBox = select(tooltipBox).node();
78932               }
78933
78934               if (tooltipBox && tooltipBox.getBoundingClientRect) {
78935                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
78936               }
78937             } else {
78938               tooltipBox = box;
78939             }
78940
78941             if (tooltipBox && html) {
78942               if (html.indexOf('**') !== -1) {
78943                 if (html.indexOf('<span') === 0) {
78944                   html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
78945                 } else {
78946                   html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
78947                 } // pseudo markdown bold text for the instruction section..
78948
78949
78950                 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
78951               }
78952
78953               html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
78954
78955               html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
78956
78957               if (options.buttonText && options.buttonCallback) {
78958                 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
78959               }
78960
78961               var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
78962               tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
78963
78964               if (options.buttonText && options.buttonCallback) {
78965                 var button = tooltip.selectAll('.button-section .button.action');
78966                 button.on('click', function (d3_event) {
78967                   d3_event.preventDefault();
78968                   options.buttonCallback();
78969                 });
78970               }
78971
78972               var tip = copyBox(tooltip.node().getBoundingClientRect()),
78973                   w = containerNode.clientWidth,
78974                   h = containerNode.clientHeight,
78975                   tooltipWidth = 200,
78976                   tooltipArrow = 5,
78977                   side,
78978                   pos; // hack: this will have bottom placement,
78979               // so need to reserve extra space for the tooltip illustration.
78980
78981               if (options.tooltipClass === 'intro-mouse') {
78982                 tip.height += 80;
78983               } // trim box dimensions to just the portion that fits in the container..
78984
78985
78986               if (tooltipBox.top + tooltipBox.height > h) {
78987                 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
78988               }
78989
78990               if (tooltipBox.left + tooltipBox.width > w) {
78991                 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
78992               } // determine tooltip placement..
78993
78994
78995               if (tooltipBox.top + tooltipBox.height < 100) {
78996                 // tooltip below box..
78997                 side = 'bottom';
78998                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
78999               } else if (tooltipBox.top > h - 140) {
79000                 // tooltip above box..
79001                 side = 'top';
79002                 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
79003               } else {
79004                 // tooltip to the side of the tooltipBox..
79005                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
79006
79007                 if (_mainLocalizer.textDirection() === 'rtl') {
79008                   if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
79009                     side = 'right';
79010                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
79011                   } else {
79012                     side = 'left';
79013                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
79014                   }
79015                 } else {
79016                   if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
79017                     side = 'left';
79018                     pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
79019                   } else {
79020                     side = 'right';
79021                     pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
79022                   }
79023                 }
79024               }
79025
79026               if (options.duration !== 0 || !tooltip.classed(side)) {
79027                 tooltip.call(uiToggle(true));
79028               }
79029
79030               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
79031               // (doesn't affect the placement of the popover-arrow)
79032
79033               var shiftY = 0;
79034
79035               if (side === 'left' || side === 'right') {
79036                 if (pos[1] < 60) {
79037                   shiftY = 60 - pos[1];
79038                 } else if (pos[1] + tip.height > h - 100) {
79039                   shiftY = h - pos[1] - tip.height - 100;
79040                 }
79041               }
79042
79043               tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
79044             } else {
79045               tooltip.classed('in', false).call(uiToggle(false));
79046             }
79047
79048             curtain.cut(box, options.duration);
79049             return tooltip;
79050           };
79051
79052           curtain.cut = function (datum, duration) {
79053             darkness.datum(datum).interrupt();
79054             var selection;
79055
79056             if (duration === 0) {
79057               selection = darkness;
79058             } else {
79059               selection = darkness.transition().duration(duration || 600).ease(linear$1);
79060             }
79061
79062             selection.attr('d', function (d) {
79063               var containerWidth = containerNode.clientWidth;
79064               var containerHeight = containerNode.clientHeight;
79065               var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
79066               if (!d) return string;
79067               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';
79068             });
79069           };
79070
79071           curtain.remove = function () {
79072             surface.remove();
79073             tooltip.remove();
79074             select(window).on('resize.curtain', null);
79075           }; // ClientRects are immutable, so copy them to an object,
79076           // in case we need to trim the height/width.
79077
79078
79079           function copyBox(src) {
79080             return {
79081               top: src.top,
79082               right: src.right,
79083               bottom: src.bottom,
79084               left: src.left,
79085               width: src.width,
79086               height: src.height
79087             };
79088           }
79089
79090           return curtain;
79091         }
79092
79093         function uiIntroWelcome(context, reveal) {
79094           var dispatch$1 = dispatch('done');
79095           var chapter = {
79096             title: 'intro.welcome.title'
79097           };
79098
79099           function welcome() {
79100             context.map().centerZoom([-85.63591, 41.94285], 19);
79101             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
79102               buttonText: _t.html('intro.ok'),
79103               buttonCallback: practice
79104             });
79105           }
79106
79107           function practice() {
79108             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
79109               buttonText: _t.html('intro.ok'),
79110               buttonCallback: words
79111             });
79112           }
79113
79114           function words() {
79115             reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
79116               buttonText: _t.html('intro.ok'),
79117               buttonCallback: chapters
79118             });
79119           }
79120
79121           function chapters() {
79122             dispatch$1.call('done');
79123             reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
79124               next: _t('intro.navigation.title')
79125             }));
79126           }
79127
79128           chapter.enter = function () {
79129             welcome();
79130           };
79131
79132           chapter.exit = function () {
79133             context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
79134           };
79135
79136           chapter.restart = function () {
79137             chapter.exit();
79138             chapter.enter();
79139           };
79140
79141           return utilRebind(chapter, dispatch$1, 'on');
79142         }
79143
79144         function uiIntroNavigation(context, reveal) {
79145           var dispatch$1 = dispatch('done');
79146           var timeouts = [];
79147           var hallId = 'n2061';
79148           var townHall = [-85.63591, 41.94285];
79149           var springStreetId = 'w397';
79150           var springStreetEndId = 'n1834';
79151           var springStreet = [-85.63582, 41.94255];
79152           var onewayField = _mainPresetIndex.field('oneway');
79153           var maxspeedField = _mainPresetIndex.field('maxspeed');
79154           var chapter = {
79155             title: 'intro.navigation.title'
79156           };
79157
79158           function timeout(f, t) {
79159             timeouts.push(window.setTimeout(f, t));
79160           }
79161
79162           function eventCancel(d3_event) {
79163             d3_event.stopPropagation();
79164             d3_event.preventDefault();
79165           }
79166
79167           function isTownHallSelected() {
79168             var ids = context.selectedIDs();
79169             return ids.length === 1 && ids[0] === hallId;
79170           }
79171
79172           function dragMap() {
79173             context.enter(modeBrowse(context));
79174             context.history().reset('initial');
79175             var msec = transitionTime(townHall, context.map().center());
79176
79177             if (msec) {
79178               reveal(null, null, {
79179                 duration: 0
79180               });
79181             }
79182
79183             context.map().centerZoomEase(townHall, 19, msec);
79184             timeout(function () {
79185               var centerStart = context.map().center();
79186               var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
79187               var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
79188               reveal('.surface', dragString);
79189               context.map().on('drawn.intro', function () {
79190                 reveal('.surface', dragString, {
79191                   duration: 0
79192                 });
79193               });
79194               context.map().on('move.intro', function () {
79195                 var centerNow = context.map().center();
79196
79197                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
79198                   context.map().on('move.intro', null);
79199                   timeout(function () {
79200                     continueTo(zoomMap);
79201                   }, 3000);
79202                 }
79203               });
79204             }, msec + 100);
79205
79206             function continueTo(nextStep) {
79207               context.map().on('move.intro drawn.intro', null);
79208               nextStep();
79209             }
79210           }
79211
79212           function zoomMap() {
79213             var zoomStart = context.map().zoom();
79214             var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
79215             var zoomString = helpHtml('intro.navigation.' + textId);
79216             reveal('.surface', zoomString);
79217             context.map().on('drawn.intro', function () {
79218               reveal('.surface', zoomString, {
79219                 duration: 0
79220               });
79221             });
79222             context.map().on('move.intro', function () {
79223               if (context.map().zoom() !== zoomStart) {
79224                 context.map().on('move.intro', null);
79225                 timeout(function () {
79226                   continueTo(features);
79227                 }, 3000);
79228               }
79229             });
79230
79231             function continueTo(nextStep) {
79232               context.map().on('move.intro drawn.intro', null);
79233               nextStep();
79234             }
79235           }
79236
79237           function features() {
79238             var onClick = function onClick() {
79239               continueTo(pointsLinesAreas);
79240             };
79241
79242             reveal('.surface', helpHtml('intro.navigation.features'), {
79243               buttonText: _t.html('intro.ok'),
79244               buttonCallback: onClick
79245             });
79246             context.map().on('drawn.intro', function () {
79247               reveal('.surface', helpHtml('intro.navigation.features'), {
79248                 duration: 0,
79249                 buttonText: _t.html('intro.ok'),
79250                 buttonCallback: onClick
79251               });
79252             });
79253
79254             function continueTo(nextStep) {
79255               context.map().on('drawn.intro', null);
79256               nextStep();
79257             }
79258           }
79259
79260           function pointsLinesAreas() {
79261             var onClick = function onClick() {
79262               continueTo(nodesWays);
79263             };
79264
79265             reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
79266               buttonText: _t.html('intro.ok'),
79267               buttonCallback: onClick
79268             });
79269             context.map().on('drawn.intro', function () {
79270               reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
79271                 duration: 0,
79272                 buttonText: _t.html('intro.ok'),
79273                 buttonCallback: onClick
79274               });
79275             });
79276
79277             function continueTo(nextStep) {
79278               context.map().on('drawn.intro', null);
79279               nextStep();
79280             }
79281           }
79282
79283           function nodesWays() {
79284             var onClick = function onClick() {
79285               continueTo(clickTownHall);
79286             };
79287
79288             reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
79289               buttonText: _t.html('intro.ok'),
79290               buttonCallback: onClick
79291             });
79292             context.map().on('drawn.intro', function () {
79293               reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
79294                 duration: 0,
79295                 buttonText: _t.html('intro.ok'),
79296                 buttonCallback: onClick
79297               });
79298             });
79299
79300             function continueTo(nextStep) {
79301               context.map().on('drawn.intro', null);
79302               nextStep();
79303             }
79304           }
79305
79306           function clickTownHall() {
79307             context.enter(modeBrowse(context));
79308             context.history().reset('initial');
79309             var entity = context.hasEntity(hallId);
79310             if (!entity) return;
79311             reveal(null, null, {
79312               duration: 0
79313             });
79314             context.map().centerZoomEase(entity.loc, 19, 500);
79315             timeout(function () {
79316               var entity = context.hasEntity(hallId);
79317               if (!entity) return;
79318               var box = pointBox(entity.loc, context);
79319               var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
79320               reveal(box, helpHtml('intro.navigation.' + textId));
79321               context.map().on('move.intro drawn.intro', function () {
79322                 var entity = context.hasEntity(hallId);
79323                 if (!entity) return;
79324                 var box = pointBox(entity.loc, context);
79325                 reveal(box, helpHtml('intro.navigation.' + textId), {
79326                   duration: 0
79327                 });
79328               });
79329               context.on('enter.intro', function () {
79330                 if (isTownHallSelected()) continueTo(selectedTownHall);
79331               });
79332             }, 550); // after centerZoomEase
79333
79334             context.history().on('change.intro', function () {
79335               if (!context.hasEntity(hallId)) {
79336                 continueTo(clickTownHall);
79337               }
79338             });
79339
79340             function continueTo(nextStep) {
79341               context.on('enter.intro', null);
79342               context.map().on('move.intro drawn.intro', null);
79343               context.history().on('change.intro', null);
79344               nextStep();
79345             }
79346           }
79347
79348           function selectedTownHall() {
79349             if (!isTownHallSelected()) return clickTownHall();
79350             var entity = context.hasEntity(hallId);
79351             if (!entity) return clickTownHall();
79352             var box = pointBox(entity.loc, context);
79353
79354             var onClick = function onClick() {
79355               continueTo(editorTownHall);
79356             };
79357
79358             reveal(box, helpHtml('intro.navigation.selected_townhall'), {
79359               buttonText: _t.html('intro.ok'),
79360               buttonCallback: onClick
79361             });
79362             context.map().on('move.intro drawn.intro', function () {
79363               var entity = context.hasEntity(hallId);
79364               if (!entity) return;
79365               var box = pointBox(entity.loc, context);
79366               reveal(box, helpHtml('intro.navigation.selected_townhall'), {
79367                 duration: 0,
79368                 buttonText: _t.html('intro.ok'),
79369                 buttonCallback: onClick
79370               });
79371             });
79372             context.history().on('change.intro', function () {
79373               if (!context.hasEntity(hallId)) {
79374                 continueTo(clickTownHall);
79375               }
79376             });
79377
79378             function continueTo(nextStep) {
79379               context.map().on('move.intro drawn.intro', null);
79380               context.history().on('change.intro', null);
79381               nextStep();
79382             }
79383           }
79384
79385           function editorTownHall() {
79386             if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
79387
79388             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79389
79390             var onClick = function onClick() {
79391               continueTo(presetTownHall);
79392             };
79393
79394             reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
79395               buttonText: _t.html('intro.ok'),
79396               buttonCallback: onClick
79397             });
79398             context.on('exit.intro', function () {
79399               continueTo(clickTownHall);
79400             });
79401             context.history().on('change.intro', function () {
79402               if (!context.hasEntity(hallId)) {
79403                 continueTo(clickTownHall);
79404               }
79405             });
79406
79407             function continueTo(nextStep) {
79408               context.on('exit.intro', null);
79409               context.history().on('change.intro', null);
79410               context.container().select('.inspector-wrap').on('wheel.intro', null);
79411               nextStep();
79412             }
79413           }
79414
79415           function presetTownHall() {
79416             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
79417
79418             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
79419
79420             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
79421
79422             var entity = context.entity(context.selectedIDs()[0]);
79423             var preset = _mainPresetIndex.match(entity, context.graph());
79424
79425             var onClick = function onClick() {
79426               continueTo(fieldsTownHall);
79427             };
79428
79429             reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
79430               preset: preset.name()
79431             }), {
79432               buttonText: _t.html('intro.ok'),
79433               buttonCallback: onClick
79434             });
79435             context.on('exit.intro', function () {
79436               continueTo(clickTownHall);
79437             });
79438             context.history().on('change.intro', function () {
79439               if (!context.hasEntity(hallId)) {
79440                 continueTo(clickTownHall);
79441               }
79442             });
79443
79444             function continueTo(nextStep) {
79445               context.on('exit.intro', null);
79446               context.history().on('change.intro', null);
79447               context.container().select('.inspector-wrap').on('wheel.intro', null);
79448               nextStep();
79449             }
79450           }
79451
79452           function fieldsTownHall() {
79453             if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
79454
79455             context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
79456
79457             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79458
79459             var onClick = function onClick() {
79460               continueTo(closeTownHall);
79461             };
79462
79463             reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
79464               buttonText: _t.html('intro.ok'),
79465               buttonCallback: onClick
79466             });
79467             context.on('exit.intro', function () {
79468               continueTo(clickTownHall);
79469             });
79470             context.history().on('change.intro', function () {
79471               if (!context.hasEntity(hallId)) {
79472                 continueTo(clickTownHall);
79473               }
79474             });
79475
79476             function continueTo(nextStep) {
79477               context.on('exit.intro', null);
79478               context.history().on('change.intro', null);
79479               context.container().select('.inspector-wrap').on('wheel.intro', null);
79480               nextStep();
79481             }
79482           }
79483
79484           function closeTownHall() {
79485             if (!isTownHallSelected()) return clickTownHall();
79486             var selector = '.entity-editor-pane button.close svg use';
79487             var href = select(selector).attr('href') || '#iD-icon-close';
79488             reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
79489               button: icon(href, 'inline')
79490             }));
79491             context.on('exit.intro', function () {
79492               continueTo(searchStreet);
79493             });
79494             context.history().on('change.intro', function () {
79495               // update the close icon in the tooltip if the user edits something.
79496               var selector = '.entity-editor-pane button.close svg use';
79497               var href = select(selector).attr('href') || '#iD-icon-close';
79498               reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
79499                 button: icon(href, 'inline')
79500               }), {
79501                 duration: 0
79502               });
79503             });
79504
79505             function continueTo(nextStep) {
79506               context.on('exit.intro', null);
79507               context.history().on('change.intro', null);
79508               nextStep();
79509             }
79510           }
79511
79512           function searchStreet() {
79513             context.enter(modeBrowse(context));
79514             context.history().reset('initial'); // ensure spring street exists
79515
79516             var msec = transitionTime(springStreet, context.map().center());
79517
79518             if (msec) {
79519               reveal(null, null, {
79520                 duration: 0
79521               });
79522             }
79523
79524             context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
79525
79526             timeout(function () {
79527               reveal('.search-header input', helpHtml('intro.navigation.search_street', {
79528                 name: _t('intro.graph.name.spring-street')
79529               }));
79530               context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
79531             }, msec + 100);
79532           }
79533
79534           function checkSearchResult() {
79535             var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
79536
79537             var firstName = first.select('.entity-name');
79538             var name = _t('intro.graph.name.spring-street');
79539
79540             if (!firstName.empty() && firstName.html() === name) {
79541               reveal(first.node(), helpHtml('intro.navigation.choose_street', {
79542                 name: name
79543               }), {
79544                 duration: 300
79545               });
79546               context.on('exit.intro', function () {
79547                 continueTo(selectedStreet);
79548               });
79549               context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79550             }
79551
79552             function continueTo(nextStep) {
79553               context.on('exit.intro', null);
79554               context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
79555               nextStep();
79556             }
79557           }
79558
79559           function selectedStreet() {
79560             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
79561               return searchStreet();
79562             }
79563
79564             var onClick = function onClick() {
79565               continueTo(editorStreet);
79566             };
79567
79568             var entity = context.entity(springStreetEndId);
79569             var box = pointBox(entity.loc, context);
79570             box.height = 500;
79571             reveal(box, helpHtml('intro.navigation.selected_street', {
79572               name: _t('intro.graph.name.spring-street')
79573             }), {
79574               duration: 600,
79575               buttonText: _t.html('intro.ok'),
79576               buttonCallback: onClick
79577             });
79578             timeout(function () {
79579               context.map().on('move.intro drawn.intro', function () {
79580                 var entity = context.hasEntity(springStreetEndId);
79581                 if (!entity) return;
79582                 var box = pointBox(entity.loc, context);
79583                 box.height = 500;
79584                 reveal(box, helpHtml('intro.navigation.selected_street', {
79585                   name: _t('intro.graph.name.spring-street')
79586                 }), {
79587                   duration: 0,
79588                   buttonText: _t.html('intro.ok'),
79589                   buttonCallback: onClick
79590                 });
79591               });
79592             }, 600); // after reveal.
79593
79594             context.on('enter.intro', function (mode) {
79595               if (!context.hasEntity(springStreetId)) {
79596                 return continueTo(searchStreet);
79597               }
79598
79599               var ids = context.selectedIDs();
79600
79601               if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
79602                 // keep Spring Street selected..
79603                 context.enter(modeSelect(context, [springStreetId]));
79604               }
79605             });
79606             context.history().on('change.intro', function () {
79607               if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
79608                 timeout(function () {
79609                   continueTo(searchStreet);
79610                 }, 300); // after any transition (e.g. if user deleted intersection)
79611               }
79612             });
79613
79614             function continueTo(nextStep) {
79615               context.map().on('move.intro drawn.intro', null);
79616               context.on('enter.intro', null);
79617               context.history().on('change.intro', null);
79618               nextStep();
79619             }
79620           }
79621
79622           function editorStreet() {
79623             var selector = '.entity-editor-pane button.close svg use';
79624             var href = select(selector).attr('href') || '#iD-icon-close';
79625             reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
79626               button: icon(href, 'inline'),
79627               field1: onewayField.label(),
79628               field2: maxspeedField.label()
79629             }));
79630             context.on('exit.intro', function () {
79631               continueTo(play);
79632             });
79633             context.history().on('change.intro', function () {
79634               // update the close icon in the tooltip if the user edits something.
79635               var selector = '.entity-editor-pane button.close svg use';
79636               var href = select(selector).attr('href') || '#iD-icon-close';
79637               reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
79638                 button: icon(href, 'inline'),
79639                 field1: onewayField.label(),
79640                 field2: maxspeedField.label()
79641               }), {
79642                 duration: 0
79643               });
79644             });
79645
79646             function continueTo(nextStep) {
79647               context.on('exit.intro', null);
79648               context.history().on('change.intro', null);
79649               nextStep();
79650             }
79651           }
79652
79653           function play() {
79654             dispatch$1.call('done');
79655             reveal('.ideditor', helpHtml('intro.navigation.play', {
79656               next: _t('intro.points.title')
79657             }), {
79658               tooltipBox: '.intro-nav-wrap .chapter-point',
79659               buttonText: _t.html('intro.ok'),
79660               buttonCallback: function buttonCallback() {
79661                 reveal('.ideditor');
79662               }
79663             });
79664           }
79665
79666           chapter.enter = function () {
79667             dragMap();
79668           };
79669
79670           chapter.exit = function () {
79671             timeouts.forEach(window.clearTimeout);
79672             context.on('enter.intro exit.intro', null);
79673             context.map().on('move.intro drawn.intro', null);
79674             context.history().on('change.intro', null);
79675             context.container().select('.inspector-wrap').on('wheel.intro', null);
79676             context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
79677           };
79678
79679           chapter.restart = function () {
79680             chapter.exit();
79681             chapter.enter();
79682           };
79683
79684           return utilRebind(chapter, dispatch$1, 'on');
79685         }
79686
79687         function uiIntroPoint(context, reveal) {
79688           var dispatch$1 = dispatch('done');
79689           var timeouts = [];
79690           var intersection = [-85.63279, 41.94394];
79691           var building = [-85.632422, 41.944045];
79692           var cafePreset = _mainPresetIndex.item('amenity/cafe');
79693           var _pointID = null;
79694           var chapter = {
79695             title: 'intro.points.title'
79696           };
79697
79698           function timeout(f, t) {
79699             timeouts.push(window.setTimeout(f, t));
79700           }
79701
79702           function eventCancel(d3_event) {
79703             d3_event.stopPropagation();
79704             d3_event.preventDefault();
79705           }
79706
79707           function addPoint() {
79708             context.enter(modeBrowse(context));
79709             context.history().reset('initial');
79710             var msec = transitionTime(intersection, context.map().center());
79711
79712             if (msec) {
79713               reveal(null, null, {
79714                 duration: 0
79715               });
79716             }
79717
79718             context.map().centerZoomEase(intersection, 19, msec);
79719             timeout(function () {
79720               var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
79721               _pointID = null;
79722               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
79723               context.on('enter.intro', function (mode) {
79724                 if (mode.id !== 'add-point') return;
79725                 continueTo(placePoint);
79726               });
79727             }, msec + 100);
79728
79729             function continueTo(nextStep) {
79730               context.on('enter.intro', null);
79731               nextStep();
79732             }
79733           }
79734
79735           function placePoint() {
79736             if (context.mode().id !== 'add-point') {
79737               return chapter.restart();
79738             }
79739
79740             var pointBox = pad(building, 150, context);
79741             var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
79742             reveal(pointBox, helpHtml('intro.points.' + textId));
79743             context.map().on('move.intro drawn.intro', function () {
79744               pointBox = pad(building, 150, context);
79745               reveal(pointBox, helpHtml('intro.points.' + textId), {
79746                 duration: 0
79747               });
79748             });
79749             context.on('enter.intro', function (mode) {
79750               if (mode.id !== 'select') return chapter.restart();
79751               _pointID = context.mode().selectedIDs()[0];
79752               continueTo(searchPreset);
79753             });
79754
79755             function continueTo(nextStep) {
79756               context.map().on('move.intro drawn.intro', null);
79757               context.on('enter.intro', null);
79758               nextStep();
79759             }
79760           }
79761
79762           function searchPreset() {
79763             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79764               return addPoint();
79765             } // disallow scrolling
79766
79767
79768             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79769             context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79770             reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
79771               preset: cafePreset.name()
79772             }));
79773             context.on('enter.intro', function (mode) {
79774               if (!_pointID || !context.hasEntity(_pointID)) {
79775                 return continueTo(addPoint);
79776               }
79777
79778               var ids = context.selectedIDs();
79779
79780               if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
79781                 // keep the user's point selected..
79782                 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
79783
79784                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
79785                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
79786                 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
79787                   preset: cafePreset.name()
79788                 }));
79789                 context.history().on('change.intro', null);
79790               }
79791             });
79792
79793             function checkPresetSearch() {
79794               var first = context.container().select('.preset-list-item:first-child');
79795
79796               if (first.classed('preset-amenity-cafe')) {
79797                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
79798                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
79799                   preset: cafePreset.name()
79800                 }), {
79801                   duration: 300
79802                 });
79803                 context.history().on('change.intro', function () {
79804                   continueTo(aboutFeatureEditor);
79805                 });
79806               }
79807             }
79808
79809             function continueTo(nextStep) {
79810               context.on('enter.intro', null);
79811               context.history().on('change.intro', null);
79812               context.container().select('.inspector-wrap').on('wheel.intro', null);
79813               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
79814               nextStep();
79815             }
79816           }
79817
79818           function aboutFeatureEditor() {
79819             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79820               return addPoint();
79821             }
79822
79823             timeout(function () {
79824               reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
79825                 tooltipClass: 'intro-points-describe',
79826                 buttonText: _t.html('intro.ok'),
79827                 buttonCallback: function buttonCallback() {
79828                   continueTo(addName);
79829                 }
79830               });
79831             }, 400);
79832             context.on('exit.intro', function () {
79833               // if user leaves select mode here, just continue with the tutorial.
79834               continueTo(reselectPoint);
79835             });
79836
79837             function continueTo(nextStep) {
79838               context.on('exit.intro', null);
79839               nextStep();
79840             }
79841           }
79842
79843           function addName() {
79844             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79845               return addPoint();
79846             } // reset pane, in case user happened to change it..
79847
79848
79849             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79850             var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
79851             timeout(function () {
79852               // It's possible for the user to add a name in a previous step..
79853               // If so, don't tell them to add the name in this step.
79854               // Give them an OK button instead.
79855               var entity = context.entity(_pointID);
79856
79857               if (entity.tags.name) {
79858                 var tooltip = reveal('.entity-editor-pane', addNameString, {
79859                   tooltipClass: 'intro-points-describe',
79860                   buttonText: _t.html('intro.ok'),
79861                   buttonCallback: function buttonCallback() {
79862                     continueTo(addCloseEditor);
79863                   }
79864                 });
79865                 tooltip.select('.instruction').style('display', 'none');
79866               } else {
79867                 reveal('.entity-editor-pane', addNameString, {
79868                   tooltipClass: 'intro-points-describe'
79869                 });
79870               }
79871             }, 400);
79872             context.history().on('change.intro', function () {
79873               continueTo(addCloseEditor);
79874             });
79875             context.on('exit.intro', function () {
79876               // if user leaves select mode here, just continue with the tutorial.
79877               continueTo(reselectPoint);
79878             });
79879
79880             function continueTo(nextStep) {
79881               context.on('exit.intro', null);
79882               context.history().on('change.intro', null);
79883               nextStep();
79884             }
79885           }
79886
79887           function addCloseEditor() {
79888             // reset pane, in case user happened to change it..
79889             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79890             var selector = '.entity-editor-pane button.close svg use';
79891             var href = select(selector).attr('href') || '#iD-icon-close';
79892             context.on('exit.intro', function () {
79893               continueTo(reselectPoint);
79894             });
79895             reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
79896               button: icon(href, 'inline')
79897             }));
79898
79899             function continueTo(nextStep) {
79900               context.on('exit.intro', null);
79901               nextStep();
79902             }
79903           }
79904
79905           function reselectPoint() {
79906             if (!_pointID) return chapter.restart();
79907             var entity = context.hasEntity(_pointID);
79908             if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
79909
79910             var oldPreset = _mainPresetIndex.match(entity, context.graph());
79911             context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
79912             context.enter(modeBrowse(context));
79913             var msec = transitionTime(entity.loc, context.map().center());
79914
79915             if (msec) {
79916               reveal(null, null, {
79917                 duration: 0
79918               });
79919             }
79920
79921             context.map().centerEase(entity.loc, msec);
79922             timeout(function () {
79923               var box = pointBox(entity.loc, context);
79924               reveal(box, helpHtml('intro.points.reselect'), {
79925                 duration: 600
79926               });
79927               timeout(function () {
79928                 context.map().on('move.intro drawn.intro', function () {
79929                   var entity = context.hasEntity(_pointID);
79930                   if (!entity) return chapter.restart();
79931                   var box = pointBox(entity.loc, context);
79932                   reveal(box, helpHtml('intro.points.reselect'), {
79933                     duration: 0
79934                   });
79935                 });
79936               }, 600); // after reveal..
79937
79938               context.on('enter.intro', function (mode) {
79939                 if (mode.id !== 'select') return;
79940                 continueTo(updatePoint);
79941               });
79942             }, msec + 100);
79943
79944             function continueTo(nextStep) {
79945               context.map().on('move.intro drawn.intro', null);
79946               context.on('enter.intro', null);
79947               nextStep();
79948             }
79949           }
79950
79951           function updatePoint() {
79952             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79953               return continueTo(reselectPoint);
79954             } // reset pane, in case user happened to untag the point..
79955
79956
79957             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79958             context.on('exit.intro', function () {
79959               continueTo(reselectPoint);
79960             });
79961             context.history().on('change.intro', function () {
79962               continueTo(updateCloseEditor);
79963             });
79964             timeout(function () {
79965               reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
79966                 tooltipClass: 'intro-points-describe'
79967               });
79968             }, 400);
79969
79970             function continueTo(nextStep) {
79971               context.on('exit.intro', null);
79972               context.history().on('change.intro', null);
79973               nextStep();
79974             }
79975           }
79976
79977           function updateCloseEditor() {
79978             if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
79979               return continueTo(reselectPoint);
79980             } // reset pane, in case user happened to change it..
79981
79982
79983             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
79984             context.on('exit.intro', function () {
79985               continueTo(rightClickPoint);
79986             });
79987             timeout(function () {
79988               reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
79989                 button: icon('#iD-icon-close', 'inline')
79990               }));
79991             }, 500);
79992
79993             function continueTo(nextStep) {
79994               context.on('exit.intro', null);
79995               nextStep();
79996             }
79997           }
79998
79999           function rightClickPoint() {
80000             if (!_pointID) return chapter.restart();
80001             var entity = context.hasEntity(_pointID);
80002             if (!entity) return chapter.restart();
80003             context.enter(modeBrowse(context));
80004             var box = pointBox(entity.loc, context);
80005             var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
80006             reveal(box, helpHtml('intro.points.' + textId), {
80007               duration: 600
80008             });
80009             timeout(function () {
80010               context.map().on('move.intro', function () {
80011                 var entity = context.hasEntity(_pointID);
80012                 if (!entity) return chapter.restart();
80013                 var box = pointBox(entity.loc, context);
80014                 reveal(box, helpHtml('intro.points.' + textId), {
80015                   duration: 0
80016                 });
80017               });
80018             }, 600); // after reveal
80019
80020             context.on('enter.intro', function (mode) {
80021               if (mode.id !== 'select') return;
80022               var ids = context.selectedIDs();
80023               if (ids.length !== 1 || ids[0] !== _pointID) return;
80024               timeout(function () {
80025                 var node = selectMenuItem(context, 'delete').node();
80026                 if (!node) return;
80027                 continueTo(enterDelete);
80028               }, 50); // after menu visible
80029             });
80030
80031             function continueTo(nextStep) {
80032               context.on('enter.intro', null);
80033               context.map().on('move.intro', null);
80034               nextStep();
80035             }
80036           }
80037
80038           function enterDelete() {
80039             if (!_pointID) return chapter.restart();
80040             var entity = context.hasEntity(_pointID);
80041             if (!entity) return chapter.restart();
80042             var node = selectMenuItem(context, 'delete').node();
80043
80044             if (!node) {
80045               return continueTo(rightClickPoint);
80046             }
80047
80048             reveal('.edit-menu', helpHtml('intro.points.delete'), {
80049               padding: 50
80050             });
80051             timeout(function () {
80052               context.map().on('move.intro', function () {
80053                 reveal('.edit-menu', helpHtml('intro.points.delete'), {
80054                   duration: 0,
80055                   padding: 50
80056                 });
80057               });
80058             }, 300); // after menu visible
80059
80060             context.on('exit.intro', function () {
80061               if (!_pointID) return chapter.restart();
80062               var entity = context.hasEntity(_pointID);
80063               if (entity) return continueTo(rightClickPoint); // point still exists
80064             });
80065             context.history().on('change.intro', function (changed) {
80066               if (changed.deleted().length) {
80067                 continueTo(undo);
80068               }
80069             });
80070
80071             function continueTo(nextStep) {
80072               context.map().on('move.intro', null);
80073               context.history().on('change.intro', null);
80074               context.on('exit.intro', null);
80075               nextStep();
80076             }
80077           }
80078
80079           function undo() {
80080             context.history().on('change.intro', function () {
80081               continueTo(play);
80082             });
80083             reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
80084
80085             function continueTo(nextStep) {
80086               context.history().on('change.intro', null);
80087               nextStep();
80088             }
80089           }
80090
80091           function play() {
80092             dispatch$1.call('done');
80093             reveal('.ideditor', helpHtml('intro.points.play', {
80094               next: _t('intro.areas.title')
80095             }), {
80096               tooltipBox: '.intro-nav-wrap .chapter-area',
80097               buttonText: _t.html('intro.ok'),
80098               buttonCallback: function buttonCallback() {
80099                 reveal('.ideditor');
80100               }
80101             });
80102           }
80103
80104           chapter.enter = function () {
80105             addPoint();
80106           };
80107
80108           chapter.exit = function () {
80109             timeouts.forEach(window.clearTimeout);
80110             context.on('enter.intro exit.intro', null);
80111             context.map().on('move.intro drawn.intro', null);
80112             context.history().on('change.intro', null);
80113             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80114             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80115           };
80116
80117           chapter.restart = function () {
80118             chapter.exit();
80119             chapter.enter();
80120           };
80121
80122           return utilRebind(chapter, dispatch$1, 'on');
80123         }
80124
80125         function uiIntroArea(context, reveal) {
80126           var dispatch$1 = dispatch('done');
80127           var playground = [-85.63552, 41.94159];
80128           var playgroundPreset = _mainPresetIndex.item('leisure/playground');
80129           var nameField = _mainPresetIndex.field('name');
80130           var descriptionField = _mainPresetIndex.field('description');
80131           var timeouts = [];
80132
80133           var _areaID;
80134
80135           var chapter = {
80136             title: 'intro.areas.title'
80137           };
80138
80139           function timeout(f, t) {
80140             timeouts.push(window.setTimeout(f, t));
80141           }
80142
80143           function eventCancel(d3_event) {
80144             d3_event.stopPropagation();
80145             d3_event.preventDefault();
80146           }
80147
80148           function revealPlayground(center, text, options) {
80149             var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
80150             var box = pad(center, padding, context);
80151             reveal(box, text, options);
80152           }
80153
80154           function addArea() {
80155             context.enter(modeBrowse(context));
80156             context.history().reset('initial');
80157             _areaID = null;
80158             var msec = transitionTime(playground, context.map().center());
80159
80160             if (msec) {
80161               reveal(null, null, {
80162                 duration: 0
80163               });
80164             }
80165
80166             context.map().centerZoomEase(playground, 19, msec);
80167             timeout(function () {
80168               var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
80169               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
80170               context.on('enter.intro', function (mode) {
80171                 if (mode.id !== 'add-area') return;
80172                 continueTo(startPlayground);
80173               });
80174             }, msec + 100);
80175
80176             function continueTo(nextStep) {
80177               context.on('enter.intro', null);
80178               nextStep();
80179             }
80180           }
80181
80182           function startPlayground() {
80183             if (context.mode().id !== 'add-area') {
80184               return chapter.restart();
80185             }
80186
80187             _areaID = null;
80188             context.map().zoomEase(19.5, 500);
80189             timeout(function () {
80190               var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
80191               var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
80192               revealPlayground(playground, startDrawString, {
80193                 duration: 250
80194               });
80195               timeout(function () {
80196                 context.map().on('move.intro drawn.intro', function () {
80197                   revealPlayground(playground, startDrawString, {
80198                     duration: 0
80199                   });
80200                 });
80201                 context.on('enter.intro', function (mode) {
80202                   if (mode.id !== 'draw-area') return chapter.restart();
80203                   continueTo(continuePlayground);
80204                 });
80205               }, 250); // after reveal
80206             }, 550); // after easing
80207
80208             function continueTo(nextStep) {
80209               context.map().on('move.intro drawn.intro', null);
80210               context.on('enter.intro', null);
80211               nextStep();
80212             }
80213           }
80214
80215           function continuePlayground() {
80216             if (context.mode().id !== 'draw-area') {
80217               return chapter.restart();
80218             }
80219
80220             _areaID = null;
80221             revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
80222               duration: 250
80223             });
80224             timeout(function () {
80225               context.map().on('move.intro drawn.intro', function () {
80226                 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
80227                   duration: 0
80228                 });
80229               });
80230             }, 250); // after reveal
80231
80232             context.on('enter.intro', function (mode) {
80233               if (mode.id === 'draw-area') {
80234                 var entity = context.hasEntity(context.selectedIDs()[0]);
80235
80236                 if (entity && entity.nodes.length >= 6) {
80237                   return continueTo(finishPlayground);
80238                 } else {
80239                   return;
80240                 }
80241               } else if (mode.id === 'select') {
80242                 _areaID = context.selectedIDs()[0];
80243                 return continueTo(searchPresets);
80244               } else {
80245                 return chapter.restart();
80246               }
80247             });
80248
80249             function continueTo(nextStep) {
80250               context.map().on('move.intro drawn.intro', null);
80251               context.on('enter.intro', null);
80252               nextStep();
80253             }
80254           }
80255
80256           function finishPlayground() {
80257             if (context.mode().id !== 'draw-area') {
80258               return chapter.restart();
80259             }
80260
80261             _areaID = null;
80262             var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
80263             revealPlayground(playground, finishString, {
80264               duration: 250
80265             });
80266             timeout(function () {
80267               context.map().on('move.intro drawn.intro', function () {
80268                 revealPlayground(playground, finishString, {
80269                   duration: 0
80270                 });
80271               });
80272             }, 250); // after reveal
80273
80274             context.on('enter.intro', function (mode) {
80275               if (mode.id === 'draw-area') {
80276                 return;
80277               } else if (mode.id === 'select') {
80278                 _areaID = context.selectedIDs()[0];
80279                 return continueTo(searchPresets);
80280               } else {
80281                 return chapter.restart();
80282               }
80283             });
80284
80285             function continueTo(nextStep) {
80286               context.map().on('move.intro drawn.intro', null);
80287               context.on('enter.intro', null);
80288               nextStep();
80289             }
80290           }
80291
80292           function searchPresets() {
80293             if (!_areaID || !context.hasEntity(_areaID)) {
80294               return addArea();
80295             }
80296
80297             var ids = context.selectedIDs();
80298
80299             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80300               context.enter(modeSelect(context, [_areaID]));
80301             } // disallow scrolling
80302
80303
80304             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80305             timeout(function () {
80306               // reset pane, in case user somehow happened to change it..
80307               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80308               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
80309               reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
80310                 preset: playgroundPreset.name()
80311               }));
80312             }, 400); // after preset list pane visible..
80313
80314             context.on('enter.intro', function (mode) {
80315               if (!_areaID || !context.hasEntity(_areaID)) {
80316                 return continueTo(addArea);
80317               }
80318
80319               var ids = context.selectedIDs();
80320
80321               if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
80322                 // keep the user's area selected..
80323                 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
80324
80325                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
80326
80327                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80328                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
80329                 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
80330                   preset: playgroundPreset.name()
80331                 }));
80332                 context.history().on('change.intro', null);
80333               }
80334             });
80335
80336             function checkPresetSearch() {
80337               var first = context.container().select('.preset-list-item:first-child');
80338
80339               if (first.classed('preset-leisure-playground')) {
80340                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
80341                   preset: playgroundPreset.name()
80342                 }), {
80343                   duration: 300
80344                 });
80345                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
80346                 context.history().on('change.intro', function () {
80347                   continueTo(clickAddField);
80348                 });
80349               }
80350             }
80351
80352             function continueTo(nextStep) {
80353               context.container().select('.inspector-wrap').on('wheel.intro', null);
80354               context.on('enter.intro', null);
80355               context.history().on('change.intro', null);
80356               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80357               nextStep();
80358             }
80359           }
80360
80361           function clickAddField() {
80362             if (!_areaID || !context.hasEntity(_areaID)) {
80363               return addArea();
80364             }
80365
80366             var ids = context.selectedIDs();
80367
80368             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80369               return searchPresets();
80370             }
80371
80372             if (!context.container().select('.form-field-description').empty()) {
80373               return continueTo(describePlayground);
80374             } // disallow scrolling
80375
80376
80377             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80378             timeout(function () {
80379               // reset pane, in case user somehow happened to change it..
80380               context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
80381               // If they did this already, just continue to next step.
80382
80383               var entity = context.entity(_areaID);
80384
80385               if (entity.tags.description) {
80386                 return continueTo(play);
80387               } // scroll "Add field" into view
80388
80389
80390               var box = context.container().select('.more-fields').node().getBoundingClientRect();
80391
80392               if (box.top > 300) {
80393                 var pane = context.container().select('.entity-editor-pane .inspector-body');
80394                 var start = pane.node().scrollTop;
80395                 var end = start + (box.top - 300);
80396                 pane.transition().duration(250).tween('scroll.inspector', function () {
80397                   var node = this;
80398                   var i = d3_interpolateNumber(start, end);
80399                   return function (t) {
80400                     node.scrollTop = i(t);
80401                   };
80402                 });
80403               }
80404
80405               timeout(function () {
80406                 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
80407                   name: nameField.label(),
80408                   description: descriptionField.label()
80409                 }), {
80410                   duration: 300
80411                 });
80412                 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
80413                   // Watch for the combobox to appear...
80414                   var watcher;
80415                   watcher = window.setInterval(function () {
80416                     if (!context.container().select('div.combobox').empty()) {
80417                       window.clearInterval(watcher);
80418                       continueTo(chooseDescriptionField);
80419                     }
80420                   }, 300);
80421                 });
80422               }, 300); // after "Add Field" visible
80423             }, 400); // after editor pane visible
80424
80425             context.on('exit.intro', function () {
80426               return continueTo(searchPresets);
80427             });
80428
80429             function continueTo(nextStep) {
80430               context.container().select('.inspector-wrap').on('wheel.intro', null);
80431               context.container().select('.more-fields .combobox-input').on('click.intro', null);
80432               context.on('exit.intro', null);
80433               nextStep();
80434             }
80435           }
80436
80437           function chooseDescriptionField() {
80438             if (!_areaID || !context.hasEntity(_areaID)) {
80439               return addArea();
80440             }
80441
80442             var ids = context.selectedIDs();
80443
80444             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80445               return searchPresets();
80446             }
80447
80448             if (!context.container().select('.form-field-description').empty()) {
80449               return continueTo(describePlayground);
80450             } // Make sure combobox is ready..
80451
80452
80453             if (context.container().select('div.combobox').empty()) {
80454               return continueTo(clickAddField);
80455             } // Watch for the combobox to go away..
80456
80457
80458             var watcher;
80459             watcher = window.setInterval(function () {
80460               if (context.container().select('div.combobox').empty()) {
80461                 window.clearInterval(watcher);
80462                 timeout(function () {
80463                   if (context.container().select('.form-field-description').empty()) {
80464                     continueTo(retryChooseDescription);
80465                   } else {
80466                     continueTo(describePlayground);
80467                   }
80468                 }, 300); // after description field added.
80469               }
80470             }, 300);
80471             reveal('div.combobox', helpHtml('intro.areas.choose_field', {
80472               field: descriptionField.label()
80473             }), {
80474               duration: 300
80475             });
80476             context.on('exit.intro', function () {
80477               return continueTo(searchPresets);
80478             });
80479
80480             function continueTo(nextStep) {
80481               if (watcher) window.clearInterval(watcher);
80482               context.on('exit.intro', null);
80483               nextStep();
80484             }
80485           }
80486
80487           function describePlayground() {
80488             if (!_areaID || !context.hasEntity(_areaID)) {
80489               return addArea();
80490             }
80491
80492             var ids = context.selectedIDs();
80493
80494             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80495               return searchPresets();
80496             } // reset pane, in case user happened to change it..
80497
80498
80499             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
80500
80501             if (context.container().select('.form-field-description').empty()) {
80502               return continueTo(retryChooseDescription);
80503             }
80504
80505             context.on('exit.intro', function () {
80506               continueTo(play);
80507             });
80508             reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
80509               button: icon('#iD-icon-close', 'inline')
80510             }), {
80511               duration: 300
80512             });
80513
80514             function continueTo(nextStep) {
80515               context.on('exit.intro', null);
80516               nextStep();
80517             }
80518           }
80519
80520           function retryChooseDescription() {
80521             if (!_areaID || !context.hasEntity(_areaID)) {
80522               return addArea();
80523             }
80524
80525             var ids = context.selectedIDs();
80526
80527             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
80528               return searchPresets();
80529             } // reset pane, in case user happened to change it..
80530
80531
80532             context.container().select('.inspector-wrap .panewrap').style('right', '0%');
80533             reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
80534               field: descriptionField.label()
80535             }), {
80536               buttonText: _t.html('intro.ok'),
80537               buttonCallback: function buttonCallback() {
80538                 continueTo(clickAddField);
80539               }
80540             });
80541             context.on('exit.intro', function () {
80542               return continueTo(searchPresets);
80543             });
80544
80545             function continueTo(nextStep) {
80546               context.on('exit.intro', null);
80547               nextStep();
80548             }
80549           }
80550
80551           function play() {
80552             dispatch$1.call('done');
80553             reveal('.ideditor', helpHtml('intro.areas.play', {
80554               next: _t('intro.lines.title')
80555             }), {
80556               tooltipBox: '.intro-nav-wrap .chapter-line',
80557               buttonText: _t.html('intro.ok'),
80558               buttonCallback: function buttonCallback() {
80559                 reveal('.ideditor');
80560               }
80561             });
80562           }
80563
80564           chapter.enter = function () {
80565             addArea();
80566           };
80567
80568           chapter.exit = function () {
80569             timeouts.forEach(window.clearTimeout);
80570             context.on('enter.intro exit.intro', null);
80571             context.map().on('move.intro drawn.intro', null);
80572             context.history().on('change.intro', null);
80573             context.container().select('.inspector-wrap').on('wheel.intro', null);
80574             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
80575             context.container().select('.more-fields .combobox-input').on('click.intro', null);
80576           };
80577
80578           chapter.restart = function () {
80579             chapter.exit();
80580             chapter.enter();
80581           };
80582
80583           return utilRebind(chapter, dispatch$1, 'on');
80584         }
80585
80586         function uiIntroLine(context, reveal) {
80587           var dispatch$1 = dispatch('done');
80588           var timeouts = [];
80589           var _tulipRoadID = null;
80590           var flowerRoadID = 'w646';
80591           var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
80592           var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
80593           var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
80594           var roadCategory = _mainPresetIndex.item('category-road_minor');
80595           var residentialPreset = _mainPresetIndex.item('highway/residential');
80596           var woodRoadID = 'w525';
80597           var woodRoadEndID = 'n2862';
80598           var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
80599           var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
80600           var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
80601           var washingtonStreetID = 'w522';
80602           var twelfthAvenueID = 'w1';
80603           var eleventhAvenueEndID = 'n3550';
80604           var twelfthAvenueEndID = 'n5';
80605           var _washingtonSegmentID = null;
80606           var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
80607           var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
80608           var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
80609           var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
80610           var chapter = {
80611             title: 'intro.lines.title'
80612           };
80613
80614           function timeout(f, t) {
80615             timeouts.push(window.setTimeout(f, t));
80616           }
80617
80618           function eventCancel(d3_event) {
80619             d3_event.stopPropagation();
80620             d3_event.preventDefault();
80621           }
80622
80623           function addLine() {
80624             context.enter(modeBrowse(context));
80625             context.history().reset('initial');
80626             var msec = transitionTime(tulipRoadStart, context.map().center());
80627
80628             if (msec) {
80629               reveal(null, null, {
80630                 duration: 0
80631               });
80632             }
80633
80634             context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
80635             timeout(function () {
80636               var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
80637               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
80638               context.on('enter.intro', function (mode) {
80639                 if (mode.id !== 'add-line') return;
80640                 continueTo(startLine);
80641               });
80642             }, msec + 100);
80643
80644             function continueTo(nextStep) {
80645               context.on('enter.intro', null);
80646               nextStep();
80647             }
80648           }
80649
80650           function startLine() {
80651             if (context.mode().id !== 'add-line') return chapter.restart();
80652             _tulipRoadID = null;
80653             var padding = 70 * Math.pow(2, context.map().zoom() - 18);
80654             var box = pad(tulipRoadStart, padding, context);
80655             box.height = box.height + 100;
80656             var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
80657             var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
80658             reveal(box, startLineString);
80659             context.map().on('move.intro drawn.intro', function () {
80660               padding = 70 * Math.pow(2, context.map().zoom() - 18);
80661               box = pad(tulipRoadStart, padding, context);
80662               box.height = box.height + 100;
80663               reveal(box, startLineString, {
80664                 duration: 0
80665               });
80666             });
80667             context.on('enter.intro', function (mode) {
80668               if (mode.id !== 'draw-line') return chapter.restart();
80669               continueTo(drawLine);
80670             });
80671
80672             function continueTo(nextStep) {
80673               context.map().on('move.intro drawn.intro', null);
80674               context.on('enter.intro', null);
80675               nextStep();
80676             }
80677           }
80678
80679           function drawLine() {
80680             if (context.mode().id !== 'draw-line') return chapter.restart();
80681             _tulipRoadID = context.mode().selectedIDs()[0];
80682             context.map().centerEase(tulipRoadMidpoint, 500);
80683             timeout(function () {
80684               var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
80685               var box = pad(tulipRoadMidpoint, padding, context);
80686               box.height = box.height * 2;
80687               reveal(box, helpHtml('intro.lines.intersect', {
80688                 name: _t('intro.graph.name.flower-street')
80689               }));
80690               context.map().on('move.intro drawn.intro', function () {
80691                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
80692                 box = pad(tulipRoadMidpoint, padding, context);
80693                 box.height = box.height * 2;
80694                 reveal(box, helpHtml('intro.lines.intersect', {
80695                   name: _t('intro.graph.name.flower-street')
80696                 }), {
80697                   duration: 0
80698                 });
80699               });
80700             }, 550); // after easing..
80701
80702             context.history().on('change.intro', function () {
80703               if (isLineConnected()) {
80704                 continueTo(continueLine);
80705               }
80706             });
80707             context.on('enter.intro', function (mode) {
80708               if (mode.id === 'draw-line') {
80709                 return;
80710               } else if (mode.id === 'select') {
80711                 continueTo(retryIntersect);
80712                 return;
80713               } else {
80714                 return chapter.restart();
80715               }
80716             });
80717
80718             function continueTo(nextStep) {
80719               context.map().on('move.intro drawn.intro', null);
80720               context.history().on('change.intro', null);
80721               context.on('enter.intro', null);
80722               nextStep();
80723             }
80724           }
80725
80726           function isLineConnected() {
80727             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
80728
80729             if (!entity) return false;
80730             var drawNodes = context.graph().childNodes(entity);
80731             return drawNodes.some(function (node) {
80732               return context.graph().parentWays(node).some(function (parent) {
80733                 return parent.id === flowerRoadID;
80734               });
80735             });
80736           }
80737
80738           function retryIntersect() {
80739             select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
80740             var box = pad(tulipRoadIntersection, 80, context);
80741             reveal(box, helpHtml('intro.lines.retry_intersect', {
80742               name: _t('intro.graph.name.flower-street')
80743             }));
80744             timeout(chapter.restart, 3000);
80745           }
80746
80747           function continueLine() {
80748             if (context.mode().id !== 'draw-line') return chapter.restart();
80749
80750             var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
80751
80752             if (!entity) return chapter.restart();
80753             context.map().centerEase(tulipRoadIntersection, 500);
80754             var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
80755             reveal('.surface', continueLineText);
80756             context.on('enter.intro', function (mode) {
80757               if (mode.id === 'draw-line') return;else if (mode.id === 'select') return continueTo(chooseCategoryRoad);else return chapter.restart();
80758             });
80759
80760             function continueTo(nextStep) {
80761               context.on('enter.intro', null);
80762               nextStep();
80763             }
80764           }
80765
80766           function chooseCategoryRoad() {
80767             if (context.mode().id !== 'select') return chapter.restart();
80768             context.on('exit.intro', function () {
80769               return chapter.restart();
80770             });
80771             var button = context.container().select('.preset-category-road_minor .preset-list-button');
80772             if (button.empty()) return chapter.restart(); // disallow scrolling
80773
80774             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80775             timeout(function () {
80776               // reset pane, in case user somehow happened to change it..
80777               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
80778               reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
80779                 category: roadCategory.name()
80780               }));
80781               button.on('click.intro', function () {
80782                 continueTo(choosePresetResidential);
80783               });
80784             }, 400); // after editor pane visible
80785
80786             function continueTo(nextStep) {
80787               context.container().select('.inspector-wrap').on('wheel.intro', null);
80788               context.container().select('.preset-list-button').on('click.intro', null);
80789               context.on('exit.intro', null);
80790               nextStep();
80791             }
80792           }
80793
80794           function choosePresetResidential() {
80795             if (context.mode().id !== 'select') return chapter.restart();
80796             context.on('exit.intro', function () {
80797               return chapter.restart();
80798             });
80799             var subgrid = context.container().select('.preset-category-road_minor .subgrid');
80800             if (subgrid.empty()) return chapter.restart();
80801             subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
80802               continueTo(retryPresetResidential);
80803             });
80804             subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
80805               continueTo(nameRoad);
80806             });
80807             timeout(function () {
80808               reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
80809                 preset: residentialPreset.name()
80810               }), {
80811                 tooltipBox: '.preset-highway-residential .preset-list-button',
80812                 duration: 300
80813               });
80814             }, 300);
80815
80816             function continueTo(nextStep) {
80817               context.container().select('.preset-list-button').on('click.intro', null);
80818               context.on('exit.intro', null);
80819               nextStep();
80820             }
80821           } // selected wrong road type
80822
80823
80824           function retryPresetResidential() {
80825             if (context.mode().id !== 'select') return chapter.restart();
80826             context.on('exit.intro', function () {
80827               return chapter.restart();
80828             }); // disallow scrolling
80829
80830             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
80831             timeout(function () {
80832               var button = context.container().select('.entity-editor-pane .preset-list-button');
80833               reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
80834                 preset: residentialPreset.name()
80835               }));
80836               button.on('click.intro', function () {
80837                 continueTo(chooseCategoryRoad);
80838               });
80839             }, 500);
80840
80841             function continueTo(nextStep) {
80842               context.container().select('.inspector-wrap').on('wheel.intro', null);
80843               context.container().select('.preset-list-button').on('click.intro', null);
80844               context.on('exit.intro', null);
80845               nextStep();
80846             }
80847           }
80848
80849           function nameRoad() {
80850             context.on('exit.intro', function () {
80851               continueTo(didNameRoad);
80852             });
80853             timeout(function () {
80854               reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
80855                 button: icon('#iD-icon-close', 'inline')
80856               }), {
80857                 tooltipClass: 'intro-lines-name_road'
80858               });
80859             }, 500);
80860
80861             function continueTo(nextStep) {
80862               context.on('exit.intro', null);
80863               nextStep();
80864             }
80865           }
80866
80867           function didNameRoad() {
80868             context.history().checkpoint('doneAddLine');
80869             timeout(function () {
80870               reveal('.surface', helpHtml('intro.lines.did_name_road'), {
80871                 buttonText: _t.html('intro.ok'),
80872                 buttonCallback: function buttonCallback() {
80873                   continueTo(updateLine);
80874                 }
80875               });
80876             }, 500);
80877
80878             function continueTo(nextStep) {
80879               nextStep();
80880             }
80881           }
80882
80883           function updateLine() {
80884             context.history().reset('doneAddLine');
80885
80886             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80887               return chapter.restart();
80888             }
80889
80890             var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
80891
80892             if (msec) {
80893               reveal(null, null, {
80894                 duration: 0
80895               });
80896             }
80897
80898             context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
80899             timeout(function () {
80900               var padding = 250 * Math.pow(2, context.map().zoom() - 19);
80901               var box = pad(woodRoadDragMidpoint, padding, context);
80902
80903               var advance = function advance() {
80904                 continueTo(addNode);
80905               };
80906
80907               reveal(box, helpHtml('intro.lines.update_line'), {
80908                 buttonText: _t.html('intro.ok'),
80909                 buttonCallback: advance
80910               });
80911               context.map().on('move.intro drawn.intro', function () {
80912                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
80913                 var box = pad(woodRoadDragMidpoint, padding, context);
80914                 reveal(box, helpHtml('intro.lines.update_line'), {
80915                   duration: 0,
80916                   buttonText: _t.html('intro.ok'),
80917                   buttonCallback: advance
80918                 });
80919               });
80920             }, msec + 100);
80921
80922             function continueTo(nextStep) {
80923               context.map().on('move.intro drawn.intro', null);
80924               nextStep();
80925             }
80926           }
80927
80928           function addNode() {
80929             context.history().reset('doneAddLine');
80930
80931             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80932               return chapter.restart();
80933             }
80934
80935             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
80936             var box = pad(woodRoadAddNode, padding, context);
80937             var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
80938             reveal(box, addNodeString);
80939             context.map().on('move.intro drawn.intro', function () {
80940               var padding = 40 * Math.pow(2, context.map().zoom() - 19);
80941               var box = pad(woodRoadAddNode, padding, context);
80942               reveal(box, addNodeString, {
80943                 duration: 0
80944               });
80945             });
80946             context.history().on('change.intro', function (changed) {
80947               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80948                 return continueTo(updateLine);
80949               }
80950
80951               if (changed.created().length === 1) {
80952                 timeout(function () {
80953                   continueTo(startDragEndpoint);
80954                 }, 500);
80955               }
80956             });
80957             context.on('enter.intro', function (mode) {
80958               if (mode.id !== 'select') {
80959                 continueTo(updateLine);
80960               }
80961             });
80962
80963             function continueTo(nextStep) {
80964               context.map().on('move.intro drawn.intro', null);
80965               context.history().on('change.intro', null);
80966               context.on('enter.intro', null);
80967               nextStep();
80968             }
80969           }
80970
80971           function startDragEndpoint() {
80972             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80973               return continueTo(updateLine);
80974             }
80975
80976             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80977             var box = pad(woodRoadDragEndpoint, padding, context);
80978             var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
80979             reveal(box, startDragString);
80980             context.map().on('move.intro drawn.intro', function () {
80981               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
80982                 return continueTo(updateLine);
80983               }
80984
80985               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
80986               var box = pad(woodRoadDragEndpoint, padding, context);
80987               reveal(box, startDragString, {
80988                 duration: 0
80989               });
80990               var entity = context.entity(woodRoadEndID);
80991
80992               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
80993                 continueTo(finishDragEndpoint);
80994               }
80995             });
80996
80997             function continueTo(nextStep) {
80998               context.map().on('move.intro drawn.intro', null);
80999               nextStep();
81000             }
81001           }
81002
81003           function finishDragEndpoint() {
81004             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81005               return continueTo(updateLine);
81006             }
81007
81008             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
81009             var box = pad(woodRoadDragEndpoint, padding, context);
81010             var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
81011             reveal(box, finishDragString);
81012             context.map().on('move.intro drawn.intro', function () {
81013               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81014                 return continueTo(updateLine);
81015               }
81016
81017               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
81018               var box = pad(woodRoadDragEndpoint, padding, context);
81019               reveal(box, finishDragString, {
81020                 duration: 0
81021               });
81022               var entity = context.entity(woodRoadEndID);
81023
81024               if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
81025                 continueTo(startDragEndpoint);
81026               }
81027             });
81028             context.on('enter.intro', function () {
81029               continueTo(startDragMidpoint);
81030             });
81031
81032             function continueTo(nextStep) {
81033               context.map().on('move.intro drawn.intro', null);
81034               context.on('enter.intro', null);
81035               nextStep();
81036             }
81037           }
81038
81039           function startDragMidpoint() {
81040             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81041               return continueTo(updateLine);
81042             }
81043
81044             if (context.selectedIDs().indexOf(woodRoadID) === -1) {
81045               context.enter(modeSelect(context, [woodRoadID]));
81046             }
81047
81048             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
81049             var box = pad(woodRoadDragMidpoint, padding, context);
81050             reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
81051             context.map().on('move.intro drawn.intro', function () {
81052               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81053                 return continueTo(updateLine);
81054               }
81055
81056               var padding = 80 * Math.pow(2, context.map().zoom() - 19);
81057               var box = pad(woodRoadDragMidpoint, padding, context);
81058               reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
81059                 duration: 0
81060               });
81061             });
81062             context.history().on('change.intro', function (changed) {
81063               if (changed.created().length === 1) {
81064                 continueTo(continueDragMidpoint);
81065               }
81066             });
81067             context.on('enter.intro', function (mode) {
81068               if (mode.id !== 'select') {
81069                 // keep Wood Road selected so midpoint triangles are drawn..
81070                 context.enter(modeSelect(context, [woodRoadID]));
81071               }
81072             });
81073
81074             function continueTo(nextStep) {
81075               context.map().on('move.intro drawn.intro', null);
81076               context.history().on('change.intro', null);
81077               context.on('enter.intro', null);
81078               nextStep();
81079             }
81080           }
81081
81082           function continueDragMidpoint() {
81083             if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81084               return continueTo(updateLine);
81085             }
81086
81087             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
81088             var box = pad(woodRoadDragEndpoint, padding, context);
81089             box.height += 400;
81090
81091             var advance = function advance() {
81092               context.history().checkpoint('doneUpdateLine');
81093               continueTo(deleteLines);
81094             };
81095
81096             reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
81097               buttonText: _t.html('intro.ok'),
81098               buttonCallback: advance
81099             });
81100             context.map().on('move.intro drawn.intro', function () {
81101               if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
81102                 return continueTo(updateLine);
81103               }
81104
81105               var padding = 100 * Math.pow(2, context.map().zoom() - 19);
81106               var box = pad(woodRoadDragEndpoint, padding, context);
81107               box.height += 400;
81108               reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
81109                 duration: 0,
81110                 buttonText: _t.html('intro.ok'),
81111                 buttonCallback: advance
81112               });
81113             });
81114
81115             function continueTo(nextStep) {
81116               context.map().on('move.intro drawn.intro', null);
81117               nextStep();
81118             }
81119           }
81120
81121           function deleteLines() {
81122             context.history().reset('doneUpdateLine');
81123             context.enter(modeBrowse(context));
81124
81125             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81126               return chapter.restart();
81127             }
81128
81129             var msec = transitionTime(deleteLinesLoc, context.map().center());
81130
81131             if (msec) {
81132               reveal(null, null, {
81133                 duration: 0
81134               });
81135             }
81136
81137             context.map().centerZoomEase(deleteLinesLoc, 18, msec);
81138             timeout(function () {
81139               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81140               var box = pad(deleteLinesLoc, padding, context);
81141               box.top -= 200;
81142               box.height += 400;
81143
81144               var advance = function advance() {
81145                 continueTo(rightClickIntersection);
81146               };
81147
81148               reveal(box, helpHtml('intro.lines.delete_lines', {
81149                 street: _t('intro.graph.name.12th-avenue')
81150               }), {
81151                 buttonText: _t.html('intro.ok'),
81152                 buttonCallback: advance
81153               });
81154               context.map().on('move.intro drawn.intro', function () {
81155                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81156                 var box = pad(deleteLinesLoc, padding, context);
81157                 box.top -= 200;
81158                 box.height += 400;
81159                 reveal(box, helpHtml('intro.lines.delete_lines', {
81160                   street: _t('intro.graph.name.12th-avenue')
81161                 }), {
81162                   duration: 0,
81163                   buttonText: _t.html('intro.ok'),
81164                   buttonCallback: advance
81165                 });
81166               });
81167               context.history().on('change.intro', function () {
81168                 timeout(function () {
81169                   continueTo(deleteLines);
81170                 }, 500); // after any transition (e.g. if user deleted intersection)
81171               });
81172             }, msec + 100);
81173
81174             function continueTo(nextStep) {
81175               context.map().on('move.intro drawn.intro', null);
81176               context.history().on('change.intro', null);
81177               nextStep();
81178             }
81179           }
81180
81181           function rightClickIntersection() {
81182             context.history().reset('doneUpdateLine');
81183             context.enter(modeBrowse(context));
81184             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
81185             var rightClickString = helpHtml('intro.lines.split_street', {
81186               street1: _t('intro.graph.name.11th-avenue'),
81187               street2: _t('intro.graph.name.washington-street')
81188             }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
81189             timeout(function () {
81190               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81191               var box = pad(eleventhAvenueEnd, padding, context);
81192               reveal(box, rightClickString);
81193               context.map().on('move.intro drawn.intro', function () {
81194                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81195                 var box = pad(eleventhAvenueEnd, padding, context);
81196                 reveal(box, rightClickString, {
81197                   duration: 0
81198                 });
81199               });
81200               context.on('enter.intro', function (mode) {
81201                 if (mode.id !== 'select') return;
81202                 var ids = context.selectedIDs();
81203                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
81204                 timeout(function () {
81205                   var node = selectMenuItem(context, 'split').node();
81206                   if (!node) return;
81207                   continueTo(splitIntersection);
81208                 }, 50); // after menu visible
81209               });
81210               context.history().on('change.intro', function () {
81211                 timeout(function () {
81212                   continueTo(deleteLines);
81213                 }, 300); // after any transition (e.g. if user deleted intersection)
81214               });
81215             }, 600);
81216
81217             function continueTo(nextStep) {
81218               context.map().on('move.intro drawn.intro', null);
81219               context.on('enter.intro', null);
81220               context.history().on('change.intro', null);
81221               nextStep();
81222             }
81223           }
81224
81225           function splitIntersection() {
81226             if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81227               return continueTo(deleteLines);
81228             }
81229
81230             var node = selectMenuItem(context, 'split').node();
81231
81232             if (!node) {
81233               return continueTo(rightClickIntersection);
81234             }
81235
81236             var wasChanged = false;
81237             _washingtonSegmentID = null;
81238             reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
81239               street: _t('intro.graph.name.washington-street')
81240             }), {
81241               padding: 50
81242             });
81243             context.map().on('move.intro drawn.intro', function () {
81244               var node = selectMenuItem(context, 'split').node();
81245
81246               if (!wasChanged && !node) {
81247                 return continueTo(rightClickIntersection);
81248               }
81249
81250               reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
81251                 street: _t('intro.graph.name.washington-street')
81252               }), {
81253                 duration: 0,
81254                 padding: 50
81255               });
81256             });
81257             context.history().on('change.intro', function (changed) {
81258               wasChanged = true;
81259               timeout(function () {
81260                 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
81261                   n: 1
81262                 })) {
81263                   _washingtonSegmentID = changed.created()[0].id;
81264                   continueTo(didSplit);
81265                 } else {
81266                   _washingtonSegmentID = null;
81267                   continueTo(retrySplit);
81268                 }
81269               }, 300); // after any transition (e.g. if user deleted intersection)
81270             });
81271
81272             function continueTo(nextStep) {
81273               context.map().on('move.intro drawn.intro', null);
81274               context.history().on('change.intro', null);
81275               nextStep();
81276             }
81277           }
81278
81279           function retrySplit() {
81280             context.enter(modeBrowse(context));
81281             context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
81282
81283             var advance = function advance() {
81284               continueTo(rightClickIntersection);
81285             };
81286
81287             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81288             var box = pad(eleventhAvenueEnd, padding, context);
81289             reveal(box, helpHtml('intro.lines.retry_split'), {
81290               buttonText: _t.html('intro.ok'),
81291               buttonCallback: advance
81292             });
81293             context.map().on('move.intro drawn.intro', function () {
81294               var padding = 60 * Math.pow(2, context.map().zoom() - 18);
81295               var box = pad(eleventhAvenueEnd, padding, context);
81296               reveal(box, helpHtml('intro.lines.retry_split'), {
81297                 duration: 0,
81298                 buttonText: _t.html('intro.ok'),
81299                 buttonCallback: advance
81300               });
81301             });
81302
81303             function continueTo(nextStep) {
81304               context.map().on('move.intro drawn.intro', null);
81305               nextStep();
81306             }
81307           }
81308
81309           function didSplit() {
81310             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81311               return continueTo(rightClickIntersection);
81312             }
81313
81314             var ids = context.selectedIDs();
81315             var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
81316             var street = _t('intro.graph.name.washington-street');
81317             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81318             var box = pad(twelfthAvenue, padding, context);
81319             box.width = box.width / 2;
81320             reveal(box, helpHtml(string, {
81321               street1: street,
81322               street2: street
81323             }), {
81324               duration: 500
81325             });
81326             timeout(function () {
81327               context.map().centerZoomEase(twelfthAvenue, 18, 500);
81328               context.map().on('move.intro drawn.intro', function () {
81329                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81330                 var box = pad(twelfthAvenue, padding, context);
81331                 box.width = box.width / 2;
81332                 reveal(box, helpHtml(string, {
81333                   street1: street,
81334                   street2: street
81335                 }), {
81336                   duration: 0
81337                 });
81338               });
81339             }, 600); // after initial reveal and curtain cut
81340
81341             context.on('enter.intro', function () {
81342               var ids = context.selectedIDs();
81343
81344               if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
81345                 continueTo(multiSelect);
81346               }
81347             });
81348             context.history().on('change.intro', function () {
81349               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81350                 return continueTo(rightClickIntersection);
81351               }
81352             });
81353
81354             function continueTo(nextStep) {
81355               context.map().on('move.intro drawn.intro', null);
81356               context.on('enter.intro', null);
81357               context.history().on('change.intro', null);
81358               nextStep();
81359             }
81360           }
81361
81362           function multiSelect() {
81363             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81364               return continueTo(rightClickIntersection);
81365             }
81366
81367             var ids = context.selectedIDs();
81368             var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
81369             var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
81370
81371             if (hasWashington && hasTwelfth) {
81372               return continueTo(multiRightClick);
81373             } else if (!hasWashington && !hasTwelfth) {
81374               return continueTo(didSplit);
81375             }
81376
81377             context.map().centerZoomEase(twelfthAvenue, 18, 500);
81378             timeout(function () {
81379               var selected, other, padding, box;
81380
81381               if (hasWashington) {
81382                 selected = _t('intro.graph.name.washington-street');
81383                 other = _t('intro.graph.name.12th-avenue');
81384                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
81385                 box = pad(twelfthAvenueEnd, padding, context);
81386                 box.width *= 3;
81387               } else {
81388                 selected = _t('intro.graph.name.12th-avenue');
81389                 other = _t('intro.graph.name.washington-street');
81390                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
81391                 box = pad(twelfthAvenue, padding, context);
81392                 box.width /= 2;
81393               }
81394
81395               reveal(box, helpHtml('intro.lines.multi_select', {
81396                 selected: selected,
81397                 other1: other
81398               }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
81399                 selected: selected,
81400                 other2: other
81401               }));
81402               context.map().on('move.intro drawn.intro', function () {
81403                 if (hasWashington) {
81404                   selected = _t('intro.graph.name.washington-street');
81405                   other = _t('intro.graph.name.12th-avenue');
81406                   padding = 60 * Math.pow(2, context.map().zoom() - 18);
81407                   box = pad(twelfthAvenueEnd, padding, context);
81408                   box.width *= 3;
81409                 } else {
81410                   selected = _t('intro.graph.name.12th-avenue');
81411                   other = _t('intro.graph.name.washington-street');
81412                   padding = 200 * Math.pow(2, context.map().zoom() - 18);
81413                   box = pad(twelfthAvenue, padding, context);
81414                   box.width /= 2;
81415                 }
81416
81417                 reveal(box, helpHtml('intro.lines.multi_select', {
81418                   selected: selected,
81419                   other1: other
81420                 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
81421                   selected: selected,
81422                   other2: other
81423                 }), {
81424                   duration: 0
81425                 });
81426               });
81427               context.on('enter.intro', function () {
81428                 continueTo(multiSelect);
81429               });
81430               context.history().on('change.intro', function () {
81431                 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81432                   return continueTo(rightClickIntersection);
81433                 }
81434               });
81435             }, 600);
81436
81437             function continueTo(nextStep) {
81438               context.map().on('move.intro drawn.intro', null);
81439               context.on('enter.intro', null);
81440               context.history().on('change.intro', null);
81441               nextStep();
81442             }
81443           }
81444
81445           function multiRightClick() {
81446             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81447               return continueTo(rightClickIntersection);
81448             }
81449
81450             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81451             var box = pad(twelfthAvenue, padding, context);
81452             var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
81453             reveal(box, rightClickString);
81454             context.map().on('move.intro drawn.intro', function () {
81455               var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81456               var box = pad(twelfthAvenue, padding, context);
81457               reveal(box, rightClickString, {
81458                 duration: 0
81459               });
81460             });
81461             context.ui().editMenu().on('toggled.intro', function (open) {
81462               if (!open) return;
81463               timeout(function () {
81464                 var ids = context.selectedIDs();
81465
81466                 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
81467                   var node = selectMenuItem(context, 'delete').node();
81468                   if (!node) return;
81469                   continueTo(multiDelete);
81470                 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
81471                   return continueTo(multiSelect);
81472                 } else {
81473                   return continueTo(didSplit);
81474                 }
81475               }, 300); // after edit menu visible
81476             });
81477             context.history().on('change.intro', function () {
81478               if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81479                 return continueTo(rightClickIntersection);
81480               }
81481             });
81482
81483             function continueTo(nextStep) {
81484               context.map().on('move.intro drawn.intro', null);
81485               context.ui().editMenu().on('toggled.intro', null);
81486               context.history().on('change.intro', null);
81487               nextStep();
81488             }
81489           }
81490
81491           function multiDelete() {
81492             if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
81493               return continueTo(rightClickIntersection);
81494             }
81495
81496             var node = selectMenuItem(context, 'delete').node();
81497             if (!node) return continueTo(multiRightClick);
81498             reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
81499               padding: 50
81500             });
81501             context.map().on('move.intro drawn.intro', function () {
81502               reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
81503                 duration: 0,
81504                 padding: 50
81505               });
81506             });
81507             context.on('exit.intro', function () {
81508               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
81509                 return continueTo(multiSelect); // left select mode but roads still exist
81510               }
81511             });
81512             context.history().on('change.intro', function () {
81513               if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
81514                 continueTo(retryDelete); // changed something but roads still exist
81515               } else {
81516                 continueTo(play);
81517               }
81518             });
81519
81520             function continueTo(nextStep) {
81521               context.map().on('move.intro drawn.intro', null);
81522               context.on('exit.intro', null);
81523               context.history().on('change.intro', null);
81524               nextStep();
81525             }
81526           }
81527
81528           function retryDelete() {
81529             context.enter(modeBrowse(context));
81530             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
81531             var box = pad(twelfthAvenue, padding, context);
81532             reveal(box, helpHtml('intro.lines.retry_delete'), {
81533               buttonText: _t.html('intro.ok'),
81534               buttonCallback: function buttonCallback() {
81535                 continueTo(multiSelect);
81536               }
81537             });
81538
81539             function continueTo(nextStep) {
81540               nextStep();
81541             }
81542           }
81543
81544           function play() {
81545             dispatch$1.call('done');
81546             reveal('.ideditor', helpHtml('intro.lines.play', {
81547               next: _t('intro.buildings.title')
81548             }), {
81549               tooltipBox: '.intro-nav-wrap .chapter-building',
81550               buttonText: _t.html('intro.ok'),
81551               buttonCallback: function buttonCallback() {
81552                 reveal('.ideditor');
81553               }
81554             });
81555           }
81556
81557           chapter.enter = function () {
81558             addLine();
81559           };
81560
81561           chapter.exit = function () {
81562             timeouts.forEach(window.clearTimeout);
81563             select(window).on('pointerdown.intro mousedown.intro', null, true);
81564             context.on('enter.intro exit.intro', null);
81565             context.map().on('move.intro drawn.intro', null);
81566             context.history().on('change.intro', null);
81567             context.container().select('.inspector-wrap').on('wheel.intro', null);
81568             context.container().select('.preset-list-button').on('click.intro', null);
81569           };
81570
81571           chapter.restart = function () {
81572             chapter.exit();
81573             chapter.enter();
81574           };
81575
81576           return utilRebind(chapter, dispatch$1, 'on');
81577         }
81578
81579         function uiIntroBuilding(context, reveal) {
81580           var dispatch$1 = dispatch('done');
81581           var house = [-85.62815, 41.95638];
81582           var tank = [-85.62732, 41.95347];
81583           var buildingCatetory = _mainPresetIndex.item('category-building');
81584           var housePreset = _mainPresetIndex.item('building/house');
81585           var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
81586           var timeouts = [];
81587           var _houseID = null;
81588           var _tankID = null;
81589           var chapter = {
81590             title: 'intro.buildings.title'
81591           };
81592
81593           function timeout(f, t) {
81594             timeouts.push(window.setTimeout(f, t));
81595           }
81596
81597           function eventCancel(d3_event) {
81598             d3_event.stopPropagation();
81599             d3_event.preventDefault();
81600           }
81601
81602           function revealHouse(center, text, options) {
81603             var padding = 160 * Math.pow(2, context.map().zoom() - 20);
81604             var box = pad(center, padding, context);
81605             reveal(box, text, options);
81606           }
81607
81608           function revealTank(center, text, options) {
81609             var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
81610             var box = pad(center, padding, context);
81611             reveal(box, text, options);
81612           }
81613
81614           function addHouse() {
81615             context.enter(modeBrowse(context));
81616             context.history().reset('initial');
81617             _houseID = null;
81618             var msec = transitionTime(house, context.map().center());
81619
81620             if (msec) {
81621               reveal(null, null, {
81622                 duration: 0
81623               });
81624             }
81625
81626             context.map().centerZoomEase(house, 19, msec);
81627             timeout(function () {
81628               var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
81629               tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
81630               context.on('enter.intro', function (mode) {
81631                 if (mode.id !== 'add-area') return;
81632                 continueTo(startHouse);
81633               });
81634             }, msec + 100);
81635
81636             function continueTo(nextStep) {
81637               context.on('enter.intro', null);
81638               nextStep();
81639             }
81640           }
81641
81642           function startHouse() {
81643             if (context.mode().id !== 'add-area') {
81644               return continueTo(addHouse);
81645             }
81646
81647             _houseID = null;
81648             context.map().zoomEase(20, 500);
81649             timeout(function () {
81650               var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
81651               revealHouse(house, startString);
81652               context.map().on('move.intro drawn.intro', function () {
81653                 revealHouse(house, startString, {
81654                   duration: 0
81655                 });
81656               });
81657               context.on('enter.intro', function (mode) {
81658                 if (mode.id !== 'draw-area') return chapter.restart();
81659                 continueTo(continueHouse);
81660               });
81661             }, 550); // after easing
81662
81663             function continueTo(nextStep) {
81664               context.map().on('move.intro drawn.intro', null);
81665               context.on('enter.intro', null);
81666               nextStep();
81667             }
81668           }
81669
81670           function continueHouse() {
81671             if (context.mode().id !== 'draw-area') {
81672               return continueTo(addHouse);
81673             }
81674
81675             _houseID = null;
81676             var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
81677             revealHouse(house, continueString);
81678             context.map().on('move.intro drawn.intro', function () {
81679               revealHouse(house, continueString, {
81680                 duration: 0
81681               });
81682             });
81683             context.on('enter.intro', function (mode) {
81684               if (mode.id === 'draw-area') {
81685                 return;
81686               } else if (mode.id === 'select') {
81687                 var graph = context.graph();
81688                 var way = context.entity(context.selectedIDs()[0]);
81689                 var nodes = graph.childNodes(way);
81690                 var points = utilArrayUniq(nodes).map(function (n) {
81691                   return context.projection(n.loc);
81692                 });
81693
81694                 if (isMostlySquare(points)) {
81695                   _houseID = way.id;
81696                   return continueTo(chooseCategoryBuilding);
81697                 } else {
81698                   return continueTo(retryHouse);
81699                 }
81700               } else {
81701                 return chapter.restart();
81702               }
81703             });
81704
81705             function continueTo(nextStep) {
81706               context.map().on('move.intro drawn.intro', null);
81707               context.on('enter.intro', null);
81708               nextStep();
81709             }
81710           }
81711
81712           function retryHouse() {
81713             var onClick = function onClick() {
81714               continueTo(addHouse);
81715             };
81716
81717             revealHouse(house, helpHtml('intro.buildings.retry_building'), {
81718               buttonText: _t.html('intro.ok'),
81719               buttonCallback: onClick
81720             });
81721             context.map().on('move.intro drawn.intro', function () {
81722               revealHouse(house, helpHtml('intro.buildings.retry_building'), {
81723                 duration: 0,
81724                 buttonText: _t.html('intro.ok'),
81725                 buttonCallback: onClick
81726               });
81727             });
81728
81729             function continueTo(nextStep) {
81730               context.map().on('move.intro drawn.intro', null);
81731               nextStep();
81732             }
81733           }
81734
81735           function chooseCategoryBuilding() {
81736             if (!_houseID || !context.hasEntity(_houseID)) {
81737               return addHouse();
81738             }
81739
81740             var ids = context.selectedIDs();
81741
81742             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81743               context.enter(modeSelect(context, [_houseID]));
81744             } // disallow scrolling
81745
81746
81747             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81748             timeout(function () {
81749               // reset pane, in case user somehow happened to change it..
81750               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81751               var button = context.container().select('.preset-category-building .preset-list-button');
81752               reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
81753                 category: buildingCatetory.name()
81754               }));
81755               button.on('click.intro', function () {
81756                 button.on('click.intro', null);
81757                 continueTo(choosePresetHouse);
81758               });
81759             }, 400); // after preset list pane visible..
81760
81761             context.on('enter.intro', function (mode) {
81762               if (!_houseID || !context.hasEntity(_houseID)) {
81763                 return continueTo(addHouse);
81764               }
81765
81766               var ids = context.selectedIDs();
81767
81768               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
81769                 return continueTo(chooseCategoryBuilding);
81770               }
81771             });
81772
81773             function continueTo(nextStep) {
81774               context.container().select('.inspector-wrap').on('wheel.intro', null);
81775               context.container().select('.preset-list-button').on('click.intro', null);
81776               context.on('enter.intro', null);
81777               nextStep();
81778             }
81779           }
81780
81781           function choosePresetHouse() {
81782             if (!_houseID || !context.hasEntity(_houseID)) {
81783               return addHouse();
81784             }
81785
81786             var ids = context.selectedIDs();
81787
81788             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81789               context.enter(modeSelect(context, [_houseID]));
81790             } // disallow scrolling
81791
81792
81793             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
81794             timeout(function () {
81795               // reset pane, in case user somehow happened to change it..
81796               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
81797               var button = context.container().select('.preset-building-house .preset-list-button');
81798               reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
81799                 preset: housePreset.name()
81800               }), {
81801                 duration: 300
81802               });
81803               button.on('click.intro', function () {
81804                 button.on('click.intro', null);
81805                 continueTo(closeEditorHouse);
81806               });
81807             }, 400); // after preset list pane visible..
81808
81809             context.on('enter.intro', function (mode) {
81810               if (!_houseID || !context.hasEntity(_houseID)) {
81811                 return continueTo(addHouse);
81812               }
81813
81814               var ids = context.selectedIDs();
81815
81816               if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
81817                 return continueTo(chooseCategoryBuilding);
81818               }
81819             });
81820
81821             function continueTo(nextStep) {
81822               context.container().select('.inspector-wrap').on('wheel.intro', null);
81823               context.container().select('.preset-list-button').on('click.intro', null);
81824               context.on('enter.intro', null);
81825               nextStep();
81826             }
81827           }
81828
81829           function closeEditorHouse() {
81830             if (!_houseID || !context.hasEntity(_houseID)) {
81831               return addHouse();
81832             }
81833
81834             var ids = context.selectedIDs();
81835
81836             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
81837               context.enter(modeSelect(context, [_houseID]));
81838             }
81839
81840             context.history().checkpoint('hasHouse');
81841             context.on('exit.intro', function () {
81842               continueTo(rightClickHouse);
81843             });
81844             timeout(function () {
81845               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
81846                 button: icon('#iD-icon-close', 'inline')
81847               }));
81848             }, 500);
81849
81850             function continueTo(nextStep) {
81851               context.on('exit.intro', null);
81852               nextStep();
81853             }
81854           }
81855
81856           function rightClickHouse() {
81857             if (!_houseID) return chapter.restart();
81858             context.enter(modeBrowse(context));
81859             context.history().reset('hasHouse');
81860             var zoom = context.map().zoom();
81861
81862             if (zoom < 20) {
81863               zoom = 20;
81864             }
81865
81866             context.map().centerZoomEase(house, zoom, 500);
81867             context.on('enter.intro', function (mode) {
81868               if (mode.id !== 'select') return;
81869               var ids = context.selectedIDs();
81870               if (ids.length !== 1 || ids[0] !== _houseID) return;
81871               timeout(function () {
81872                 var node = selectMenuItem(context, 'orthogonalize').node();
81873                 if (!node) return;
81874                 continueTo(clickSquare);
81875               }, 50); // after menu visible
81876             });
81877             context.map().on('move.intro drawn.intro', function () {
81878               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
81879               revealHouse(house, rightclickString, {
81880                 duration: 0
81881               });
81882             });
81883             context.history().on('change.intro', function () {
81884               continueTo(rightClickHouse);
81885             });
81886
81887             function continueTo(nextStep) {
81888               context.on('enter.intro', null);
81889               context.map().on('move.intro drawn.intro', null);
81890               context.history().on('change.intro', null);
81891               nextStep();
81892             }
81893           }
81894
81895           function clickSquare() {
81896             if (!_houseID) return chapter.restart();
81897             var entity = context.hasEntity(_houseID);
81898             if (!entity) return continueTo(rightClickHouse);
81899             var node = selectMenuItem(context, 'orthogonalize').node();
81900
81901             if (!node) {
81902               return continueTo(rightClickHouse);
81903             }
81904
81905             var wasChanged = false;
81906             reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
81907               padding: 50
81908             });
81909             context.on('enter.intro', function (mode) {
81910               if (mode.id === 'browse') {
81911                 continueTo(rightClickHouse);
81912               } else if (mode.id === 'move' || mode.id === 'rotate') {
81913                 continueTo(retryClickSquare);
81914               }
81915             });
81916             context.map().on('move.intro', function () {
81917               var node = selectMenuItem(context, 'orthogonalize').node();
81918
81919               if (!wasChanged && !node) {
81920                 return continueTo(rightClickHouse);
81921               }
81922
81923               reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
81924                 duration: 0,
81925                 padding: 50
81926               });
81927             });
81928             context.history().on('change.intro', function () {
81929               wasChanged = true;
81930               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
81931
81932               timeout(function () {
81933                 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
81934                   n: 1
81935                 })) {
81936                   continueTo(doneSquare);
81937                 } else {
81938                   continueTo(retryClickSquare);
81939                 }
81940               }, 500); // after transitioned actions
81941             });
81942
81943             function continueTo(nextStep) {
81944               context.on('enter.intro', null);
81945               context.map().on('move.intro', null);
81946               context.history().on('change.intro', null);
81947               nextStep();
81948             }
81949           }
81950
81951           function retryClickSquare() {
81952             context.enter(modeBrowse(context));
81953             revealHouse(house, helpHtml('intro.buildings.retry_square'), {
81954               buttonText: _t.html('intro.ok'),
81955               buttonCallback: function buttonCallback() {
81956                 continueTo(rightClickHouse);
81957               }
81958             });
81959
81960             function continueTo(nextStep) {
81961               nextStep();
81962             }
81963           }
81964
81965           function doneSquare() {
81966             context.history().checkpoint('doneSquare');
81967             revealHouse(house, helpHtml('intro.buildings.done_square'), {
81968               buttonText: _t.html('intro.ok'),
81969               buttonCallback: function buttonCallback() {
81970                 continueTo(addTank);
81971               }
81972             });
81973
81974             function continueTo(nextStep) {
81975               nextStep();
81976             }
81977           }
81978
81979           function addTank() {
81980             context.enter(modeBrowse(context));
81981             context.history().reset('doneSquare');
81982             _tankID = null;
81983             var msec = transitionTime(tank, context.map().center());
81984
81985             if (msec) {
81986               reveal(null, null, {
81987                 duration: 0
81988               });
81989             }
81990
81991             context.map().centerZoomEase(tank, 19.5, msec);
81992             timeout(function () {
81993               reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
81994               context.on('enter.intro', function (mode) {
81995                 if (mode.id !== 'add-area') return;
81996                 continueTo(startTank);
81997               });
81998             }, msec + 100);
81999
82000             function continueTo(nextStep) {
82001               context.on('enter.intro', null);
82002               nextStep();
82003             }
82004           }
82005
82006           function startTank() {
82007             if (context.mode().id !== 'add-area') {
82008               return continueTo(addTank);
82009             }
82010
82011             _tankID = null;
82012             timeout(function () {
82013               var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
82014               revealTank(tank, startString);
82015               context.map().on('move.intro drawn.intro', function () {
82016                 revealTank(tank, startString, {
82017                   duration: 0
82018                 });
82019               });
82020               context.on('enter.intro', function (mode) {
82021                 if (mode.id !== 'draw-area') return chapter.restart();
82022                 continueTo(continueTank);
82023               });
82024             }, 550); // after easing
82025
82026             function continueTo(nextStep) {
82027               context.map().on('move.intro drawn.intro', null);
82028               context.on('enter.intro', null);
82029               nextStep();
82030             }
82031           }
82032
82033           function continueTank() {
82034             if (context.mode().id !== 'draw-area') {
82035               return continueTo(addTank);
82036             }
82037
82038             _tankID = null;
82039             var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
82040             revealTank(tank, continueString);
82041             context.map().on('move.intro drawn.intro', function () {
82042               revealTank(tank, continueString, {
82043                 duration: 0
82044               });
82045             });
82046             context.on('enter.intro', function (mode) {
82047               if (mode.id === 'draw-area') {
82048                 return;
82049               } else if (mode.id === 'select') {
82050                 _tankID = context.selectedIDs()[0];
82051                 return continueTo(searchPresetTank);
82052               } else {
82053                 return continueTo(addTank);
82054               }
82055             });
82056
82057             function continueTo(nextStep) {
82058               context.map().on('move.intro drawn.intro', null);
82059               context.on('enter.intro', null);
82060               nextStep();
82061             }
82062           }
82063
82064           function searchPresetTank() {
82065             if (!_tankID || !context.hasEntity(_tankID)) {
82066               return addTank();
82067             }
82068
82069             var ids = context.selectedIDs();
82070
82071             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
82072               context.enter(modeSelect(context, [_tankID]));
82073             } // disallow scrolling
82074
82075
82076             context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
82077             timeout(function () {
82078               // reset pane, in case user somehow happened to change it..
82079               context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
82080               context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
82081               reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
82082                 preset: tankPreset.name()
82083               }));
82084             }, 400); // after preset list pane visible..
82085
82086             context.on('enter.intro', function (mode) {
82087               if (!_tankID || !context.hasEntity(_tankID)) {
82088                 return continueTo(addTank);
82089               }
82090
82091               var ids = context.selectedIDs();
82092
82093               if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
82094                 // keep the user's area selected..
82095                 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
82096
82097                 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
82098
82099                 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
82100                 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
82101                 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
82102                   preset: tankPreset.name()
82103                 }));
82104                 context.history().on('change.intro', null);
82105               }
82106             });
82107
82108             function checkPresetSearch() {
82109               var first = context.container().select('.preset-list-item:first-child');
82110
82111               if (first.classed('preset-man_made-storage_tank')) {
82112                 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
82113                   preset: tankPreset.name()
82114                 }), {
82115                   duration: 300
82116                 });
82117                 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
82118                 context.history().on('change.intro', function () {
82119                   continueTo(closeEditorTank);
82120                 });
82121               }
82122             }
82123
82124             function continueTo(nextStep) {
82125               context.container().select('.inspector-wrap').on('wheel.intro', null);
82126               context.on('enter.intro', null);
82127               context.history().on('change.intro', null);
82128               context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
82129               nextStep();
82130             }
82131           }
82132
82133           function closeEditorTank() {
82134             if (!_tankID || !context.hasEntity(_tankID)) {
82135               return addTank();
82136             }
82137
82138             var ids = context.selectedIDs();
82139
82140             if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
82141               context.enter(modeSelect(context, [_tankID]));
82142             }
82143
82144             context.history().checkpoint('hasTank');
82145             context.on('exit.intro', function () {
82146               continueTo(rightClickTank);
82147             });
82148             timeout(function () {
82149               reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
82150                 button: icon('#iD-icon-close', 'inline')
82151               }));
82152             }, 500);
82153
82154             function continueTo(nextStep) {
82155               context.on('exit.intro', null);
82156               nextStep();
82157             }
82158           }
82159
82160           function rightClickTank() {
82161             if (!_tankID) return continueTo(addTank);
82162             context.enter(modeBrowse(context));
82163             context.history().reset('hasTank');
82164             context.map().centerEase(tank, 500);
82165             timeout(function () {
82166               context.on('enter.intro', function (mode) {
82167                 if (mode.id !== 'select') return;
82168                 var ids = context.selectedIDs();
82169                 if (ids.length !== 1 || ids[0] !== _tankID) return;
82170                 timeout(function () {
82171                   var node = selectMenuItem(context, 'circularize').node();
82172                   if (!node) return;
82173                   continueTo(clickCircle);
82174                 }, 50); // after menu visible
82175               });
82176               var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
82177               revealTank(tank, rightclickString);
82178               context.map().on('move.intro drawn.intro', function () {
82179                 revealTank(tank, rightclickString, {
82180                   duration: 0
82181                 });
82182               });
82183               context.history().on('change.intro', function () {
82184                 continueTo(rightClickTank);
82185               });
82186             }, 600);
82187
82188             function continueTo(nextStep) {
82189               context.on('enter.intro', null);
82190               context.map().on('move.intro drawn.intro', null);
82191               context.history().on('change.intro', null);
82192               nextStep();
82193             }
82194           }
82195
82196           function clickCircle() {
82197             if (!_tankID) return chapter.restart();
82198             var entity = context.hasEntity(_tankID);
82199             if (!entity) return continueTo(rightClickTank);
82200             var node = selectMenuItem(context, 'circularize').node();
82201
82202             if (!node) {
82203               return continueTo(rightClickTank);
82204             }
82205
82206             var wasChanged = false;
82207             reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
82208               padding: 50
82209             });
82210             context.on('enter.intro', function (mode) {
82211               if (mode.id === 'browse') {
82212                 continueTo(rightClickTank);
82213               } else if (mode.id === 'move' || mode.id === 'rotate') {
82214                 continueTo(retryClickCircle);
82215               }
82216             });
82217             context.map().on('move.intro', function () {
82218               var node = selectMenuItem(context, 'circularize').node();
82219
82220               if (!wasChanged && !node) {
82221                 return continueTo(rightClickTank);
82222               }
82223
82224               reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
82225                 duration: 0,
82226                 padding: 50
82227               });
82228             });
82229             context.history().on('change.intro', function () {
82230               wasChanged = true;
82231               context.history().on('change.intro', null); // Something changed.  Wait for transition to complete and check undo annotation.
82232
82233               timeout(function () {
82234                 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
82235                   n: 1
82236                 })) {
82237                   continueTo(play);
82238                 } else {
82239                   continueTo(retryClickCircle);
82240                 }
82241               }, 500); // after transitioned actions
82242             });
82243
82244             function continueTo(nextStep) {
82245               context.on('enter.intro', null);
82246               context.map().on('move.intro', null);
82247               context.history().on('change.intro', null);
82248               nextStep();
82249             }
82250           }
82251
82252           function retryClickCircle() {
82253             context.enter(modeBrowse(context));
82254             revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
82255               buttonText: _t.html('intro.ok'),
82256               buttonCallback: function buttonCallback() {
82257                 continueTo(rightClickTank);
82258               }
82259             });
82260
82261             function continueTo(nextStep) {
82262               nextStep();
82263             }
82264           }
82265
82266           function play() {
82267             dispatch$1.call('done');
82268             reveal('.ideditor', helpHtml('intro.buildings.play', {
82269               next: _t('intro.startediting.title')
82270             }), {
82271               tooltipBox: '.intro-nav-wrap .chapter-startEditing',
82272               buttonText: _t.html('intro.ok'),
82273               buttonCallback: function buttonCallback() {
82274                 reveal('.ideditor');
82275               }
82276             });
82277           }
82278
82279           chapter.enter = function () {
82280             addHouse();
82281           };
82282
82283           chapter.exit = function () {
82284             timeouts.forEach(window.clearTimeout);
82285             context.on('enter.intro exit.intro', null);
82286             context.map().on('move.intro drawn.intro', null);
82287             context.history().on('change.intro', null);
82288             context.container().select('.inspector-wrap').on('wheel.intro', null);
82289             context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
82290             context.container().select('.more-fields .combobox-input').on('click.intro', null);
82291           };
82292
82293           chapter.restart = function () {
82294             chapter.exit();
82295             chapter.enter();
82296           };
82297
82298           return utilRebind(chapter, dispatch$1, 'on');
82299         }
82300
82301         function uiIntroStartEditing(context, reveal) {
82302           var dispatch$1 = dispatch('done', 'startEditing');
82303           var modalSelection = select(null);
82304           var chapter = {
82305             title: 'intro.startediting.title'
82306           };
82307
82308           function showHelp() {
82309             reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
82310               buttonText: _t.html('intro.ok'),
82311               buttonCallback: function buttonCallback() {
82312                 shortcuts();
82313               }
82314             });
82315           }
82316
82317           function shortcuts() {
82318             reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
82319               buttonText: _t.html('intro.ok'),
82320               buttonCallback: function buttonCallback() {
82321                 showSave();
82322               }
82323             });
82324           }
82325
82326           function showSave() {
82327             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82328
82329             reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
82330               buttonText: _t.html('intro.ok'),
82331               buttonCallback: function buttonCallback() {
82332                 showStart();
82333               }
82334             });
82335           }
82336
82337           function showStart() {
82338             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82339
82340             modalSelection = uiModal(context.container());
82341             modalSelection.select('.modal').attr('class', 'modal-splash modal');
82342             modalSelection.selectAll('.close').remove();
82343             var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
82344               modalSelection.remove();
82345             });
82346             startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
82347             startbutton.append('h2').html(_t.html('intro.startediting.start'));
82348             dispatch$1.call('startEditing');
82349           }
82350
82351           chapter.enter = function () {
82352             showHelp();
82353           };
82354
82355           chapter.exit = function () {
82356             modalSelection.remove();
82357             context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
82358           };
82359
82360           return utilRebind(chapter, dispatch$1, 'on');
82361         }
82362
82363         var chapterUi = {
82364           welcome: uiIntroWelcome,
82365           navigation: uiIntroNavigation,
82366           point: uiIntroPoint,
82367           area: uiIntroArea,
82368           line: uiIntroLine,
82369           building: uiIntroBuilding,
82370           startEditing: uiIntroStartEditing
82371         };
82372         var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
82373         function uiIntro(context) {
82374           var INTRO_IMAGERY = 'EsriWorldImageryClarity';
82375           var _introGraph = {};
82376
82377           var _currChapter;
82378
82379           function intro(selection) {
82380             _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
82381               // create entities for intro graph and localize names
82382               for (var id in dataIntroGraph) {
82383                 if (!_introGraph[id]) {
82384                   _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
82385                 }
82386               }
82387
82388               selection.call(startIntro);
82389             })["catch"](function () {
82390               /* ignore */
82391             });
82392           }
82393
82394           function startIntro(selection) {
82395             context.enter(modeBrowse(context)); // Save current map state
82396
82397             var osm = context.connection();
82398             var history = context.history().toJSON();
82399             var hash = window.location.hash;
82400             var center = context.map().center();
82401             var zoom = context.map().zoom();
82402             var background = context.background().baseLayerSource();
82403             var overlays = context.background().overlayLayerSources();
82404             var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
82405             var caches = osm && osm.caches();
82406             var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
82407             // (this needs to be before `context.inIntro(true)`)
82408
82409             context.ui().sidebar.expand();
82410             context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
82411
82412             context.inIntro(true); // Load semi-real data used in intro
82413
82414             if (osm) {
82415               osm.toggle(false).reset();
82416             }
82417
82418             context.history().reset();
82419             context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
82420             context.history().checkpoint('initial'); // Setup imagery
82421
82422             var imagery = context.background().findSource(INTRO_IMAGERY);
82423
82424             if (imagery) {
82425               context.background().baseLayerSource(imagery);
82426             } else {
82427               context.background().bing();
82428             }
82429
82430             overlays.forEach(function (d) {
82431               return context.background().toggleOverlayLayer(d);
82432             }); // Setup data layers (only OSM)
82433
82434             var layers = context.layers();
82435             layers.all().forEach(function (item) {
82436               // if the layer has the function `enabled`
82437               if (typeof item.layer.enabled === 'function') {
82438                 item.layer.enabled(item.id === 'osm');
82439               }
82440             });
82441             context.container().selectAll('.main-map .layer-background').style('opacity', 1);
82442             var curtain = uiCurtain(context.container().node());
82443             selection.call(curtain); // Store that the user started the walkthrough..
82444
82445             corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
82446
82447             var storedProgress = corePreferences('walkthrough_progress') || '';
82448             var progress = storedProgress.split(';').filter(Boolean);
82449             var chapters = chapterFlow.map(function (chapter, i) {
82450               var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
82451                 buttons.filter(function (d) {
82452                   return d.title === s.title;
82453                 }).classed('finished', true);
82454
82455                 if (i < chapterFlow.length - 1) {
82456                   var next = chapterFlow[i + 1];
82457                   context.container().select("button.chapter-".concat(next)).classed('next', true);
82458                 } // Store walkthrough progress..
82459
82460
82461                 progress.push(chapter);
82462                 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
82463               });
82464               return s;
82465             });
82466             chapters[chapters.length - 1].on('startEditing', function () {
82467               // Store walkthrough progress..
82468               progress.push('startEditing');
82469               corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
82470
82471               var incomplete = utilArrayDifference(chapterFlow, progress);
82472
82473               if (!incomplete.length) {
82474                 corePreferences('walkthrough_completed', 'yes');
82475               }
82476
82477               curtain.remove();
82478               navwrap.remove();
82479               context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
82480               context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
82481
82482               if (osm) {
82483                 osm.toggle(true).reset().caches(caches);
82484               }
82485
82486               context.history().reset().merge(Object.values(baseEntities));
82487               context.background().baseLayerSource(background);
82488               overlays.forEach(function (d) {
82489                 return context.background().toggleOverlayLayer(d);
82490               });
82491
82492               if (history) {
82493                 context.history().fromJSON(history, false);
82494               }
82495
82496               context.map().centerZoom(center, zoom);
82497               window.location.replace(hash);
82498               context.inIntro(false);
82499             });
82500             var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
82501             navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
82502             var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
82503             var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
82504               return "chapter chapter-".concat(chapterFlow[i]);
82505             }).on('click', enterChapter);
82506             buttons.append('span').html(function (d) {
82507               return _t.html(d.title);
82508             });
82509             buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
82510             enterChapter(null, chapters[0]);
82511
82512             function enterChapter(d3_event, newChapter) {
82513               if (_currChapter) {
82514                 _currChapter.exit();
82515               }
82516
82517               context.enter(modeBrowse(context));
82518               _currChapter = newChapter;
82519
82520               _currChapter.enter();
82521
82522               buttons.classed('next', false).classed('active', function (d) {
82523                 return d.title === _currChapter.title;
82524               });
82525             }
82526           }
82527
82528           return intro;
82529         }
82530
82531         function uiIssuesInfo(context) {
82532           var warningsItem = {
82533             id: 'warnings',
82534             count: 0,
82535             iconID: 'iD-icon-alert',
82536             descriptionID: 'issues.warnings_and_errors'
82537           };
82538           var resolvedItem = {
82539             id: 'resolved',
82540             count: 0,
82541             iconID: 'iD-icon-apply',
82542             descriptionID: 'issues.user_resolved_issues'
82543           };
82544
82545           function update(selection) {
82546             var shownItems = [];
82547             var liveIssues = context.validator().getIssues({
82548               what: corePreferences('validate-what') || 'edited',
82549               where: corePreferences('validate-where') || 'all'
82550             });
82551
82552             if (liveIssues.length) {
82553               warningsItem.count = liveIssues.length;
82554               shownItems.push(warningsItem);
82555             }
82556
82557             if (corePreferences('validate-what') === 'all') {
82558               var resolvedIssues = context.validator().getResolvedIssues();
82559
82560               if (resolvedIssues.length) {
82561                 resolvedItem.count = resolvedIssues.length;
82562                 shownItems.push(resolvedItem);
82563               }
82564             }
82565
82566             var chips = selection.selectAll('.chip').data(shownItems, function (d) {
82567               return d.id;
82568             });
82569             chips.exit().remove();
82570             var enter = chips.enter().append('a').attr('class', function (d) {
82571               return 'chip ' + d.id + '-count';
82572             }).attr('href', '#').each(function (d) {
82573               var chipSelection = select(this);
82574               var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
82575               chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
82576                 d3_event.preventDefault();
82577                 tooltipBehavior.hide(select(this)); // open the Issues pane
82578
82579                 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
82580               });
82581               chipSelection.call(svgIcon('#' + d.iconID));
82582             });
82583             enter.append('span').attr('class', 'count');
82584             enter.merge(chips).selectAll('span.count').html(function (d) {
82585               return d.count.toString();
82586             });
82587           }
82588
82589           return function (selection) {
82590             update(selection);
82591             context.validator().on('validated.infobox', function () {
82592               update(selection);
82593             });
82594           };
82595         }
82596
82597         function uiMapInMap(context) {
82598           function mapInMap(selection) {
82599             var backgroundLayer = rendererTileLayer(context);
82600             var overlayLayers = {};
82601             var projection = geoRawMercator();
82602             var dataLayer = svgData(projection, context).showLabels(false);
82603             var debugLayer = svgDebug(projection, context);
82604             var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
82605             var wrap = select(null);
82606             var tiles = select(null);
82607             var viewport = select(null);
82608             var _isTransformed = false;
82609             var _isHidden = true;
82610             var _skipEvents = false;
82611             var _gesture = null;
82612             var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
82613
82614             var _dMini; // dimensions of minimap
82615
82616
82617             var _cMini; // center pixel of minimap
82618
82619
82620             var _tStart; // transform at start of gesture
82621
82622
82623             var _tCurr; // transform at most recent event
82624
82625
82626             var _timeoutID;
82627
82628             function zoomStarted() {
82629               if (_skipEvents) return;
82630               _tStart = _tCurr = projection.transform();
82631               _gesture = null;
82632             }
82633
82634             function zoomed(d3_event) {
82635               if (_skipEvents) return;
82636               var x = d3_event.transform.x;
82637               var y = d3_event.transform.y;
82638               var k = d3_event.transform.k;
82639               var isZooming = k !== _tStart.k;
82640               var isPanning = x !== _tStart.x || y !== _tStart.y;
82641
82642               if (!isZooming && !isPanning) {
82643                 return; // no change
82644               } // lock in either zooming or panning, don't allow both in minimap.
82645
82646
82647               if (!_gesture) {
82648                 _gesture = isZooming ? 'zoom' : 'pan';
82649               }
82650
82651               var tMini = projection.transform();
82652               var tX, tY, scale;
82653
82654               if (_gesture === 'zoom') {
82655                 scale = k / tMini.k;
82656                 tX = (_cMini[0] / scale - _cMini[0]) * scale;
82657                 tY = (_cMini[1] / scale - _cMini[1]) * scale;
82658               } else {
82659                 k = tMini.k;
82660                 scale = 1;
82661                 tX = x - tMini.x;
82662                 tY = y - tMini.y;
82663               }
82664
82665               utilSetTransform(tiles, tX, tY, scale);
82666               utilSetTransform(viewport, 0, 0, scale);
82667               _isTransformed = true;
82668               _tCurr = identity$2.translate(x, y).scale(k);
82669               var zMain = geoScaleToZoom(context.projection.scale());
82670               var zMini = geoScaleToZoom(k);
82671               _zDiff = zMain - zMini;
82672               queueRedraw();
82673             }
82674
82675             function zoomEnded() {
82676               if (_skipEvents) return;
82677               if (_gesture !== 'pan') return;
82678               updateProjection();
82679               _gesture = null;
82680               context.map().center(projection.invert(_cMini)); // recenter main map..
82681             }
82682
82683             function updateProjection() {
82684               var loc = context.map().center();
82685               var tMain = context.projection.transform();
82686               var zMain = geoScaleToZoom(tMain.k);
82687               var zMini = Math.max(zMain - _zDiff, 0.5);
82688               var kMini = geoZoomToScale(zMini);
82689               projection.translate([tMain.x, tMain.y]).scale(kMini);
82690               var point = projection(loc);
82691               var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
82692               var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
82693               var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
82694               projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
82695               _tCurr = projection.transform();
82696
82697               if (_isTransformed) {
82698                 utilSetTransform(tiles, 0, 0);
82699                 utilSetTransform(viewport, 0, 0);
82700                 _isTransformed = false;
82701               }
82702
82703               zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
82704               _skipEvents = true;
82705               wrap.call(zoom.transform, _tCurr);
82706               _skipEvents = false;
82707             }
82708
82709             function redraw() {
82710               clearTimeout(_timeoutID);
82711               if (_isHidden) return;
82712               updateProjection();
82713               var zMini = geoScaleToZoom(projection.scale()); // setup tile container
82714
82715               tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
82716               tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
82717
82718               backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
82719               var background = tiles.selectAll('.map-in-map-background').data([0]);
82720               background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
82721
82722               var overlaySources = context.background().overlayLayerSources();
82723               var activeOverlayLayers = [];
82724
82725               for (var i = 0; i < overlaySources.length; i++) {
82726                 if (overlaySources[i].validZoom(zMini)) {
82727                   if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
82728                   activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
82729                 }
82730               }
82731
82732               var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
82733               overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
82734               var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
82735                 return d.source().name();
82736               });
82737               overlays.exit().remove();
82738               overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
82739                 select(this).call(layer);
82740               });
82741               var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
82742               dataLayers.exit().remove();
82743               dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
82744
82745               if (_gesture !== 'pan') {
82746                 var getPath = d3_geoPath(projection);
82747                 var bbox = {
82748                   type: 'Polygon',
82749                   coordinates: [context.map().extent().polygon()]
82750                 };
82751                 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
82752                 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
82753                 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
82754                 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
82755                   return getPath.area(d) < 30;
82756                 });
82757               }
82758             }
82759
82760             function queueRedraw() {
82761               clearTimeout(_timeoutID);
82762               _timeoutID = setTimeout(function () {
82763                 redraw();
82764               }, 750);
82765             }
82766
82767             function toggle(d3_event) {
82768               if (d3_event) d3_event.preventDefault();
82769               _isHidden = !_isHidden;
82770               context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
82771
82772               if (_isHidden) {
82773                 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
82774                   selection.selectAll('.map-in-map').style('display', 'none');
82775                 });
82776               } else {
82777                 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
82778                   redraw();
82779                 });
82780               }
82781             }
82782
82783             uiMapInMap.toggle = toggle;
82784             wrap = selection.selectAll('.map-in-map').data([0]);
82785             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..
82786
82787             _dMini = [200, 150]; //utilGetDimensions(wrap);
82788
82789             _cMini = geoVecScale(_dMini, 0.5);
82790             context.map().on('drawn.map-in-map', function (drawn) {
82791               if (drawn.full === true) {
82792                 redraw();
82793               }
82794             });
82795             redraw();
82796             context.keybinding().on(_t('background.minimap.key'), toggle);
82797           }
82798
82799           return mapInMap;
82800         }
82801
82802         function uiNotice(context) {
82803           return function (selection) {
82804             var div = selection.append('div').attr('class', 'notice');
82805             var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
82806               context.map().zoomEase(context.minEditableZoom());
82807             }).on('wheel', function (d3_event) {
82808               // let wheel events pass through #4482
82809               var e2 = new WheelEvent(d3_event.type, d3_event);
82810               context.surface().node().dispatchEvent(e2);
82811             });
82812             button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
82813
82814             function disableTooHigh() {
82815               var canEdit = context.map().zoom() >= context.minEditableZoom();
82816               div.style('display', canEdit ? 'none' : 'block');
82817             }
82818
82819             context.map().on('move.notice', debounce(disableTooHigh, 500));
82820             disableTooHigh();
82821           };
82822         }
82823
82824         function uiPhotoviewer(context) {
82825           var dispatch$1 = dispatch('resize');
82826
82827           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
82828
82829           function photoviewer(selection) {
82830             selection.append('button').attr('class', 'thumb-hide').on('click', function () {
82831               if (services.streetside) {
82832                 services.streetside.hideViewer(context);
82833               }
82834
82835               if (services.mapillary) {
82836                 services.mapillary.hideViewer(context);
82837               }
82838
82839               if (services.openstreetcam) {
82840                 services.openstreetcam.hideViewer(context);
82841               }
82842             }).append('div').call(svgIcon('#iD-icon-close'));
82843
82844             function preventDefault(d3_event) {
82845               d3_event.preventDefault();
82846             }
82847
82848             selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82849               resizeOnX: true,
82850               resizeOnY: true
82851             }));
82852             selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82853               resizeOnX: true
82854             }));
82855             selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch$1, {
82856               resizeOnY: true
82857             }));
82858
82859             function buildResizeListener(target, eventName, dispatch, options) {
82860               var resizeOnX = !!options.resizeOnX;
82861               var resizeOnY = !!options.resizeOnY;
82862               var minHeight = options.minHeight || 240;
82863               var minWidth = options.minWidth || 320;
82864               var pointerId;
82865               var startX;
82866               var startY;
82867               var startWidth;
82868               var startHeight;
82869
82870               function startResize(d3_event) {
82871                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
82872                 d3_event.preventDefault();
82873                 d3_event.stopPropagation();
82874                 var mapSize = context.map().dimensions();
82875
82876                 if (resizeOnX) {
82877                   var maxWidth = mapSize[0];
82878                   var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
82879                   target.style('width', newWidth + 'px');
82880                 }
82881
82882                 if (resizeOnY) {
82883                   var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
82884
82885                   var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
82886                   target.style('height', newHeight + 'px');
82887                 }
82888
82889                 dispatch.call(eventName, target, utilGetDimensions(target, true));
82890               }
82891
82892               function clamp(num, min, max) {
82893                 return Math.max(min, Math.min(num, max));
82894               }
82895
82896               function stopResize(d3_event) {
82897                 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
82898                 d3_event.preventDefault();
82899                 d3_event.stopPropagation(); // remove all the listeners we added
82900
82901                 select(window).on('.' + eventName, null);
82902               }
82903
82904               return function initResize(d3_event) {
82905                 d3_event.preventDefault();
82906                 d3_event.stopPropagation();
82907                 pointerId = d3_event.pointerId || 'mouse';
82908                 startX = d3_event.clientX;
82909                 startY = d3_event.clientY;
82910                 var targetRect = target.node().getBoundingClientRect();
82911                 startWidth = targetRect.width;
82912                 startHeight = targetRect.height;
82913                 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
82914
82915                 if (_pointerPrefix === 'pointer') {
82916                   select(window).on('pointercancel.' + eventName, stopResize, false);
82917                 }
82918               };
82919             }
82920           }
82921
82922           photoviewer.onMapResize = function () {
82923             var photoviewer = context.container().select('.photoviewer');
82924             var content = context.container().select('.main-content');
82925             var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
82926             // (-90 preserves space at top and bottom of map used by menus)
82927
82928             var photoDimensions = utilGetDimensions(photoviewer, true);
82929
82930             if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
82931               var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
82932               photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
82933               dispatch$1.call('resize', photoviewer, setPhotoDimensions);
82934             }
82935           };
82936
82937           return utilRebind(photoviewer, dispatch$1, 'on');
82938         }
82939
82940         function uiRestore(context) {
82941           return function (selection) {
82942             if (!context.history().hasRestorableChanges()) return;
82943             var modalSelection = uiModal(selection, true);
82944             modalSelection.select('.modal').attr('class', 'modal fillL');
82945             var introModal = modalSelection.select('.content');
82946             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
82947             introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
82948             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
82949             var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
82950               context.history().restore();
82951               modalSelection.remove();
82952             });
82953             restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
82954             restore.append('div').html(_t.html('restore.restore'));
82955             var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
82956               context.history().clearSaved();
82957               modalSelection.remove();
82958             });
82959             reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
82960             reset.append('div').html(_t.html('restore.reset'));
82961             restore.node().focus();
82962           };
82963         }
82964
82965         function uiScale(context) {
82966           var projection = context.projection,
82967               isImperial = !_mainLocalizer.usesMetric(),
82968               maxLength = 180,
82969               tickHeight = 8;
82970
82971           function scaleDefs(loc1, loc2) {
82972             var lat = (loc2[1] + loc1[1]) / 2,
82973                 conversion = isImperial ? 3.28084 : 1,
82974                 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
82975                 scale = {
82976               dist: 0,
82977               px: 0,
82978               text: ''
82979             },
82980                 buckets,
82981                 i,
82982                 val,
82983                 dLon;
82984
82985             if (isImperial) {
82986               buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
82987             } else {
82988               buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
82989             } // determine a user-friendly endpoint for the scale
82990
82991
82992             for (i = 0; i < buckets.length; i++) {
82993               val = buckets[i];
82994
82995               if (dist >= val) {
82996                 scale.dist = Math.floor(dist / val) * val;
82997                 break;
82998               } else {
82999                 scale.dist = +dist.toFixed(2);
83000               }
83001             }
83002
83003             dLon = geoMetersToLon(scale.dist / conversion, lat);
83004             scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
83005             scale.text = displayLength(scale.dist / conversion, isImperial);
83006             return scale;
83007           }
83008
83009           function update(selection) {
83010             // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
83011             var dims = context.map().dimensions(),
83012                 loc1 = projection.invert([0, dims[1]]),
83013                 loc2 = projection.invert([maxLength, dims[1]]),
83014                 scale = scaleDefs(loc1, loc2);
83015             selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
83016             selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
83017           }
83018
83019           return function (selection) {
83020             function switchUnits() {
83021               isImperial = !isImperial;
83022               selection.call(update);
83023             }
83024
83025             var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
83026             scalegroup.append('path').attr('class', 'scale-path');
83027             selection.append('div').attr('class', 'scale-text');
83028             selection.call(update);
83029             context.map().on('move.scale', function () {
83030               update(selection);
83031             });
83032           };
83033         }
83034
83035         function uiShortcuts(context) {
83036           var detected = utilDetect();
83037           var _activeTab = 0;
83038
83039           var _modalSelection;
83040
83041           var _selection = select(null);
83042
83043           var _dataShortcuts;
83044
83045           function shortcutsModal(_modalSelection) {
83046             _modalSelection.select('.modal').classed('modal-shortcuts', true);
83047
83048             var content = _modalSelection.select('.content');
83049
83050             content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
83051             _mainFileFetcher.get('shortcuts').then(function (data) {
83052               _dataShortcuts = data;
83053               content.call(render);
83054             })["catch"](function () {
83055               /* ignore */
83056             });
83057           }
83058
83059           function render(selection) {
83060             if (!_dataShortcuts) return;
83061             var wrapper = selection.selectAll('.wrapper').data([0]);
83062             var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
83063             var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
83064             var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
83065             wrapper = wrapper.merge(wrapperEnter);
83066             var tabs = tabsBar.selectAll('.tab').data(_dataShortcuts);
83067             var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event, d) {
83068               d3_event.preventDefault();
83069
83070               var i = _dataShortcuts.indexOf(d);
83071
83072               _activeTab = i;
83073               render(selection);
83074             });
83075             tabsEnter.append('span').html(function (d) {
83076               return _t.html(d.text);
83077             }); // Update
83078
83079             wrapper.selectAll('.tab').classed('active', function (d, i) {
83080               return i === _activeTab;
83081             });
83082             var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(_dataShortcuts);
83083             var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
83084               return 'shortcut-tab shortcut-tab-' + d.tab;
83085             });
83086             var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
83087               return d.columns;
83088             }).enter().append('table').attr('class', 'shortcut-column');
83089             var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
83090               return d.rows;
83091             }).enter().append('tr').attr('class', 'shortcut-row');
83092             var sectionRows = rowsEnter.filter(function (d) {
83093               return !d.shortcuts;
83094             });
83095             sectionRows.append('td');
83096             sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
83097               return _t.html(d.text);
83098             });
83099             var shortcutRows = rowsEnter.filter(function (d) {
83100               return d.shortcuts;
83101             });
83102             var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
83103             var modifierKeys = shortcutKeys.filter(function (d) {
83104               return d.modifiers;
83105             });
83106             modifierKeys.selectAll('kbd.modifier').data(function (d) {
83107               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
83108                 return ['⌘'];
83109               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
83110                 return [];
83111               } else {
83112                 return d.modifiers;
83113               }
83114             }).enter().each(function () {
83115               var selection = select(this);
83116               selection.append('kbd').attr('class', 'modifier').html(function (d) {
83117                 return uiCmd.display(d);
83118               });
83119               selection.append('span').html('+');
83120             });
83121             shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
83122               var arr = d.shortcuts;
83123
83124               if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
83125                 arr = ['Y'];
83126               } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
83127                 arr = ['F11'];
83128               } // replace translations
83129
83130
83131               arr = arr.map(function (s) {
83132                 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
83133               });
83134               return utilArrayUniq(arr).map(function (s) {
83135                 return {
83136                   shortcut: s,
83137                   separator: d.separator,
83138                   suffix: d.suffix
83139                 };
83140               });
83141             }).enter().each(function (d, i, nodes) {
83142               var selection = select(this);
83143               var click = d.shortcut.toLowerCase().match(/(.*).click/);
83144
83145               if (click && click[1]) {
83146                 // replace "left_click", "right_click" with mouse icon
83147                 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
83148               } else if (d.shortcut.toLowerCase() === 'long-press') {
83149                 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
83150               } else if (d.shortcut.toLowerCase() === 'tap') {
83151                 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
83152               } else {
83153                 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
83154                   return d.shortcut;
83155                 });
83156               }
83157
83158               if (i < nodes.length - 1) {
83159                 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
83160               } else if (i === nodes.length - 1 && d.suffix) {
83161                 selection.append('span').html(d.suffix);
83162               }
83163             });
83164             shortcutKeys.filter(function (d) {
83165               return d.gesture;
83166             }).each(function () {
83167               var selection = select(this);
83168               selection.append('span').html('+');
83169               selection.append('span').attr('class', 'gesture').html(function (d) {
83170                 return _t.html(d.gesture);
83171               });
83172             });
83173             shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
83174               return d.text ? _t.html(d.text) : "\xA0";
83175             }); // Update
83176
83177             wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
83178               return i === _activeTab ? 'flex' : 'none';
83179             });
83180           }
83181
83182           return function (selection, show) {
83183             _selection = selection;
83184
83185             if (show) {
83186               _modalSelection = uiModal(selection);
83187
83188               _modalSelection.call(shortcutsModal);
83189             } else {
83190               context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
83191                 if (context.container().selectAll('.modal-shortcuts').size()) {
83192                   // already showing
83193                   if (_modalSelection) {
83194                     _modalSelection.close();
83195
83196                     _modalSelection = null;
83197                   }
83198                 } else {
83199                   _modalSelection = uiModal(_selection);
83200
83201                   _modalSelection.call(shortcutsModal);
83202                 }
83203               });
83204             }
83205           };
83206         }
83207
83208         var pair_1 = pair;
83209
83210         function search(input, dims) {
83211           if (!dims) dims = 'NSEW';
83212           if (typeof input !== 'string') return null;
83213           input = input.toUpperCase();
83214           var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
83215           var m = input.match(regex);
83216           if (!m) return null; // no match
83217
83218           var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
83219
83220           var dim;
83221
83222           if (m[1] && m[5]) {
83223             // if matched both..
83224             dim = m[1]; // keep leading
83225
83226             matched = matched.slice(0, -1); // remove trailing dimension from match
83227           } else {
83228             dim = m[1] || m[5];
83229           } // if unrecognized dimension
83230
83231
83232           if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
83233
83234           var deg = m[2] ? parseFloat(m[2]) : 0;
83235           var min = m[3] ? parseFloat(m[3]) / 60 : 0;
83236           var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
83237           var sign = deg < 0 ? -1 : 1;
83238           if (dim === 'S' || dim === 'W') sign *= -1;
83239           return {
83240             val: (Math.abs(deg) + min + sec) * sign,
83241             dim: dim,
83242             matched: matched,
83243             remain: input.slice(matched.length)
83244           };
83245         }
83246
83247         function pair(input, dims) {
83248           input = input.trim();
83249           var one = search(input, dims);
83250           if (!one) return null;
83251           input = one.remain.trim();
83252           var two = search(input, dims);
83253           if (!two || two.remain) return null;
83254
83255           if (one.dim) {
83256             return swapdim(one.val, two.val, one.dim);
83257           } else {
83258             return [one.val, two.val];
83259           }
83260         }
83261
83262         function swapdim(a, b, dim) {
83263           if (dim === 'N' || dim === 'S') return [a, b];
83264           if (dim === 'W' || dim === 'E') return [b, a];
83265         }
83266
83267         function uiFeatureList(context) {
83268           var _geocodeResults;
83269
83270           function featureList(selection) {
83271             var header = selection.append('div').attr('class', 'header fillL');
83272             header.append('h3').html(_t.html('inspector.feature_list'));
83273             var searchWrap = selection.append('div').attr('class', 'search-header');
83274             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
83275             var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
83276             var listWrap = selection.append('div').attr('class', 'inspector-body');
83277             var list = listWrap.append('div').attr('class', 'feature-list');
83278             context.on('exit.feature-list', clearSearch);
83279             context.map().on('drawn.feature-list', mapDrawn);
83280             context.keybinding().on(uiCmd('⌘F'), focusSearch);
83281
83282             function focusSearch(d3_event) {
83283               var mode = context.mode() && context.mode().id;
83284               if (mode !== 'browse') return;
83285               d3_event.preventDefault();
83286               search.node().focus();
83287             }
83288
83289             function keydown(d3_event) {
83290               if (d3_event.keyCode === 27) {
83291                 // escape
83292                 search.node().blur();
83293               }
83294             }
83295
83296             function keypress(d3_event) {
83297               var q = search.property('value'),
83298                   items = list.selectAll('.feature-list-item');
83299
83300               if (d3_event.keyCode === 13 && // ↩ Return
83301               q.length && items.size()) {
83302                 click(items.datum());
83303               }
83304             }
83305
83306             function inputevent() {
83307               _geocodeResults = undefined;
83308               drawList();
83309             }
83310
83311             function clearSearch() {
83312               search.property('value', '');
83313               drawList();
83314             }
83315
83316             function mapDrawn(e) {
83317               if (e.full) {
83318                 drawList();
83319               }
83320             }
83321
83322             function features() {
83323               var result = [];
83324               var graph = context.graph();
83325               var visibleCenter = context.map().extent().center();
83326               var q = search.property('value').toLowerCase();
83327               if (!q) return result;
83328               var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
83329
83330               if (locationMatch) {
83331                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
83332                 result.push({
83333                   id: -1,
83334                   geometry: 'point',
83335                   type: _t('inspector.location'),
83336                   name: dmsCoordinatePair([loc[1], loc[0]]),
83337                   location: loc
83338                 });
83339               } // A location search takes priority over an ID search
83340
83341
83342               var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
83343
83344               if (idMatch) {
83345                 var elemType = idMatch[1].charAt(0);
83346                 var elemId = idMatch[2];
83347                 result.push({
83348                   id: elemType + elemId,
83349                   geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
83350                   type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
83351                   name: elemId
83352                 });
83353               }
83354
83355               var allEntities = graph.entities;
83356               var localResults = [];
83357
83358               for (var id in allEntities) {
83359                 var entity = allEntities[id];
83360                 if (!entity) continue;
83361                 var name = utilDisplayName(entity) || '';
83362                 if (name.toLowerCase().indexOf(q) < 0) continue;
83363                 var matched = _mainPresetIndex.match(entity, graph);
83364                 var type = matched && matched.name() || utilDisplayType(entity.id);
83365                 var extent = entity.extent(graph);
83366                 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
83367                 localResults.push({
83368                   id: entity.id,
83369                   entity: entity,
83370                   geometry: entity.geometry(graph),
83371                   type: type,
83372                   name: name,
83373                   distance: distance
83374                 });
83375                 if (localResults.length > 100) break;
83376               }
83377
83378               localResults = localResults.sort(function byDistance(a, b) {
83379                 return a.distance - b.distance;
83380               });
83381               result = result.concat(localResults);
83382
83383               (_geocodeResults || []).forEach(function (d) {
83384                 if (d.osm_type && d.osm_id) {
83385                   // some results may be missing these - #1890
83386                   // Make a temporary osmEntity so we can preset match
83387                   // and better localize the search result - #4725
83388                   var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
83389                   var tags = {};
83390                   tags[d["class"]] = d.type;
83391                   var attrs = {
83392                     id: id,
83393                     type: d.osm_type,
83394                     tags: tags
83395                   };
83396
83397                   if (d.osm_type === 'way') {
83398                     // for ways, add some fake closed nodes
83399                     attrs.nodes = ['a', 'a']; // so that geometry area is possible
83400                   }
83401
83402                   var tempEntity = osmEntity(attrs);
83403                   var tempGraph = coreGraph([tempEntity]);
83404                   var matched = _mainPresetIndex.match(tempEntity, tempGraph);
83405                   var type = matched && matched.name() || utilDisplayType(id);
83406                   result.push({
83407                     id: tempEntity.id,
83408                     geometry: tempEntity.geometry(tempGraph),
83409                     type: type,
83410                     name: d.display_name,
83411                     extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
83412                   });
83413                 }
83414               });
83415
83416               if (q.match(/^[0-9]+$/)) {
83417                 // if query is just a number, possibly an OSM ID without a prefix
83418                 result.push({
83419                   id: 'n' + q,
83420                   geometry: 'point',
83421                   type: _t('inspector.node'),
83422                   name: q
83423                 });
83424                 result.push({
83425                   id: 'w' + q,
83426                   geometry: 'line',
83427                   type: _t('inspector.way'),
83428                   name: q
83429                 });
83430                 result.push({
83431                   id: 'r' + q,
83432                   geometry: 'relation',
83433                   type: _t('inspector.relation'),
83434                   name: q
83435                 });
83436               }
83437
83438               return result;
83439             }
83440
83441             function drawList() {
83442               var value = search.property('value');
83443               var results = features();
83444               list.classed('filtered', value.length);
83445               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'));
83446               resultsIndicator.append('span').attr('class', 'entity-name');
83447               list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
83448
83449               if (services.geocoder) {
83450                 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'));
83451               }
83452
83453               list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
83454               list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
83455               list.selectAll('.feature-list-item').data([-1]).remove();
83456               var items = list.selectAll('.feature-list-item').data(results, function (d) {
83457                 return d.id;
83458               });
83459               var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
83460               var label = enter.append('div').attr('class', 'label');
83461               label.each(function (d) {
83462                 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
83463               });
83464               label.append('span').attr('class', 'entity-type').html(function (d) {
83465                 return d.type;
83466               });
83467               label.append('span').attr('class', 'entity-name').html(function (d) {
83468                 return d.name;
83469               });
83470               enter.style('opacity', 0).transition().style('opacity', 1);
83471               items.order();
83472               items.exit().remove();
83473             }
83474
83475             function mouseover(d3_event, d) {
83476               if (d.id === -1) return;
83477               utilHighlightEntities([d.id], true, context);
83478             }
83479
83480             function mouseout(d3_event, d) {
83481               if (d.id === -1) return;
83482               utilHighlightEntities([d.id], false, context);
83483             }
83484
83485             function click(d3_event, d) {
83486               d3_event.preventDefault();
83487
83488               if (d.location) {
83489                 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
83490               } else if (d.entity) {
83491                 utilHighlightEntities([d.id], false, context);
83492                 context.enter(modeSelect(context, [d.entity.id]));
83493                 context.map().zoomToEase(d.entity);
83494               } else {
83495                 // download, zoom to, and select the entity with the given ID
83496                 context.zoomToEntity(d.id);
83497               }
83498             }
83499
83500             function geocoderSearch() {
83501               services.geocoder.search(search.property('value'), function (err, resp) {
83502                 _geocodeResults = resp || [];
83503                 drawList();
83504               });
83505             }
83506           }
83507
83508           return featureList;
83509         }
83510
83511         function uiSectionEntityIssues(context) {
83512           var _entityIDs = [];
83513           var _issues = [];
83514
83515           var _activeIssueID;
83516
83517           var section = uiSection('entity-issues', context).shouldDisplay(function () {
83518             return _issues.length > 0;
83519           }).label(function () {
83520             return _t('inspector.title_count', {
83521               title: _t.html('issues.list_title'),
83522               count: _issues.length
83523             });
83524           }).disclosureContent(renderDisclosureContent);
83525           context.validator().on('validated.entity_issues', function () {
83526             // Refresh on validated events
83527             reloadIssues();
83528             section.reRender();
83529           }).on('focusedIssue.entity_issues', function (issue) {
83530             makeActiveIssue(issue.id);
83531           });
83532
83533           function reloadIssues() {
83534             _issues = context.validator().getSharedEntityIssues(_entityIDs, {
83535               includeDisabledRules: true
83536             });
83537           }
83538
83539           function makeActiveIssue(issueID) {
83540             _activeIssueID = issueID;
83541             section.selection().selectAll('.issue-container').classed('active', function (d) {
83542               return d.id === _activeIssueID;
83543             });
83544           }
83545
83546           function renderDisclosureContent(selection) {
83547             selection.classed('grouped-items-area', true);
83548             _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
83549             var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
83550               return d.id;
83551             }); // Exit
83552
83553             containers.exit().remove(); // Enter
83554
83555             var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
83556             var itemsEnter = containersEnter.append('div').attr('class', function (d) {
83557               return 'issue severity-' + d.severity;
83558             }).on('mouseover.highlight', function (d3_event, d) {
83559               // don't hover-highlight the selected entity
83560               var ids = d.entityIds.filter(function (e) {
83561                 return _entityIDs.indexOf(e) === -1;
83562               });
83563               utilHighlightEntities(ids, true, context);
83564             }).on('mouseout.highlight', function (d3_event, d) {
83565               var ids = d.entityIds.filter(function (e) {
83566                 return _entityIDs.indexOf(e) === -1;
83567               });
83568               utilHighlightEntities(ids, false, context);
83569             });
83570             var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
83571             var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
83572               makeActiveIssue(d.id); // expand only the clicked item
83573
83574               var extent = d.extent(context.graph());
83575
83576               if (extent) {
83577                 var setZoom = Math.max(context.map().zoom(), 19);
83578                 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
83579               }
83580             });
83581             textEnter.each(function (d) {
83582               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
83583               select(this).call(svgIcon(iconName, 'issue-icon'));
83584             });
83585             textEnter.append('span').attr('class', 'issue-message');
83586             var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
83587             infoButton.on('click', function (d3_event) {
83588               d3_event.stopPropagation();
83589               d3_event.preventDefault();
83590               this.blur(); // avoid keeping focus on the button - #4641
83591
83592               var container = select(this.parentNode.parentNode.parentNode);
83593               var info = container.selectAll('.issue-info');
83594               var isExpanded = info.classed('expanded');
83595
83596               if (isExpanded) {
83597                 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
83598                   info.classed('expanded', false);
83599                 });
83600               } else {
83601                 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
83602                   info.style('max-height', null);
83603                 });
83604               }
83605             });
83606             itemsEnter.append('ul').attr('class', 'issue-fix-list');
83607             containersEnter.append('div').attr('class', 'issue-info').style('max-height', '0').style('opacity', '0').each(function (d) {
83608               if (typeof d.reference === 'function') {
83609                 select(this).call(d.reference);
83610               } else {
83611                 select(this).html(_t.html('inspector.no_documentation_key'));
83612               }
83613             }); // Update
83614
83615             containers = containers.merge(containersEnter).classed('active', function (d) {
83616               return d.id === _activeIssueID;
83617             });
83618             containers.selectAll('.issue-message').html(function (d) {
83619               return d.message(context);
83620             }); // fixes
83621
83622             var fixLists = containers.selectAll('.issue-fix-list');
83623             var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
83624               return d.fixes ? d.fixes(context) : [];
83625             }, function (fix) {
83626               return fix.id;
83627             });
83628             fixes.exit().remove();
83629             var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
83630             var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
83631               // not all fixes are actionable
83632               if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
83633               // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
83634
83635               if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
83636               d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
83637
83638               utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
83639               new Promise(function (resolve, reject) {
83640                 d.onClick(context, resolve, reject);
83641
83642                 if (d.onClick.length <= 1) {
83643                   // if the fix doesn't take any completion parameters then consider it resolved
83644                   resolve();
83645                 }
83646               }).then(function () {
83647                 // revalidate whenever the fix has finished running successfully
83648                 context.validator().validate();
83649               });
83650             }).on('mouseover.highlight', function (d3_event, d) {
83651               utilHighlightEntities(d.entityIds, true, context);
83652             }).on('mouseout.highlight', function (d3_event, d) {
83653               utilHighlightEntities(d.entityIds, false, context);
83654             });
83655             buttons.each(function (d) {
83656               var iconName = d.icon || 'iD-icon-wrench';
83657
83658               if (iconName.startsWith('maki')) {
83659                 iconName += '-15';
83660               }
83661
83662               select(this).call(svgIcon('#' + iconName, 'fix-icon'));
83663             });
83664             buttons.append('span').attr('class', 'fix-message').html(function (d) {
83665               return d.title;
83666             });
83667             fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
83668               return d.onClick;
83669             }).attr('disabled', function (d) {
83670               return d.onClick ? null : 'true';
83671             }).attr('title', function (d) {
83672               if (d.disabledReason) {
83673                 return d.disabledReason;
83674               }
83675
83676               return null;
83677             });
83678           }
83679
83680           section.entityIDs = function (val) {
83681             if (!arguments.length) return _entityIDs;
83682
83683             if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
83684               _entityIDs = val;
83685               _activeIssueID = null;
83686               reloadIssues();
83687             }
83688
83689             return section;
83690           };
83691
83692           return section;
83693         }
83694
83695         function uiPresetIcon() {
83696           var _preset;
83697
83698           var _geometry;
83699
83700           var _sizeClass = 'medium';
83701
83702           function isSmall() {
83703             return _sizeClass === 'small';
83704           }
83705
83706           function presetIcon(selection) {
83707             selection.each(render);
83708           }
83709
83710           function getIcon(p, geom) {
83711             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';
83712           }
83713
83714           function renderPointBorder(container, drawPoint) {
83715             var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
83716             pointBorder.exit().remove();
83717             var pointBorderEnter = pointBorder.enter();
83718             var w = 40;
83719             var h = 40;
83720             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');
83721             pointBorder = pointBorderEnter.merge(pointBorder);
83722           }
83723
83724           function renderCircleFill(container, drawVertex) {
83725             var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
83726             vertexFill.exit().remove();
83727             var vertexFillEnter = vertexFill.enter();
83728             var w = 60;
83729             var h = 60;
83730             var d = 40;
83731             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);
83732             vertexFill = vertexFillEnter.merge(vertexFill);
83733           }
83734
83735           function renderSquareFill(container, drawArea, tagClasses) {
83736             var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
83737             fill.exit().remove();
83738             var fillEnter = fill.enter();
83739             var d = isSmall() ? 40 : 60;
83740             var w = d;
83741             var h = d;
83742             var l = d * 2 / 3;
83743             var c1 = (w - l) / 2;
83744             var c2 = c1 + l;
83745             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));
83746             ['fill', 'stroke'].forEach(function (klass) {
83747               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));
83748             });
83749             var rVertex = 2.5;
83750             [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
83751               fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
83752             });
83753
83754             if (!isSmall()) {
83755               var rMidpoint = 1.25;
83756               [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
83757                 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
83758               });
83759             }
83760
83761             fill = fillEnter.merge(fill);
83762             fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
83763             fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
83764           }
83765
83766           function renderLine(container, drawLine, tagClasses) {
83767             var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
83768             line.exit().remove();
83769             var lineEnter = line.enter();
83770             var d = isSmall() ? 40 : 60; // draw the line parametrically
83771
83772             var w = d;
83773             var h = d;
83774             var y = Math.round(d * 0.72);
83775             var l = Math.round(d * 0.6);
83776             var r = 2.5;
83777             var x1 = (w - l) / 2;
83778             var x2 = x1 + l;
83779             lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
83780             ['casing', 'stroke'].forEach(function (klass) {
83781               lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
83782             });
83783             [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
83784               lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
83785             });
83786             line = lineEnter.merge(line);
83787             line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
83788             line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
83789           }
83790
83791           function renderRoute(container, drawRoute, p) {
83792             var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
83793             route.exit().remove();
83794             var routeEnter = route.enter();
83795             var d = isSmall() ? 40 : 60; // draw the route parametrically
83796
83797             var w = d;
83798             var h = d;
83799             var y1 = Math.round(d * 0.80);
83800             var y2 = Math.round(d * 0.68);
83801             var l = Math.round(d * 0.6);
83802             var r = 2;
83803             var x1 = (w - l) / 2;
83804             var x2 = x1 + l / 3;
83805             var x3 = x2 + l / 3;
83806             var x4 = x3 + l / 3;
83807             routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
83808             ['casing', 'stroke'].forEach(function (klass) {
83809               routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
83810               routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
83811               routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
83812             });
83813             [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
83814               routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
83815             });
83816             route = routeEnter.merge(route);
83817
83818             if (drawRoute) {
83819               var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
83820               var segmentPresetIDs = routeSegments[routeType];
83821
83822               for (var i in segmentPresetIDs) {
83823                 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
83824                 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
83825                 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
83826                 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
83827               }
83828             }
83829           } // Route icons are drawn with a zigzag annotation underneath:
83830           //     o   o
83831           //    / \ /
83832           //   o   o
83833           // This dataset defines the styles that are used to draw the zigzag segments.
83834
83835
83836           var routeSegments = {
83837             bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
83838             bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
83839             trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
83840             detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
83841             ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
83842             foot: ['highway/footway', 'highway/footway', 'highway/footway'],
83843             hiking: ['highway/path', 'highway/path', 'highway/path'],
83844             horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
83845             light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
83846             monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
83847             pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
83848             piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
83849             power: ['power/line', 'power/line', 'power/line'],
83850             road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
83851             subway: ['railway/subway', 'railway/subway', 'railway/subway'],
83852             train: ['railway/rail', 'railway/rail', 'railway/rail'],
83853             tram: ['railway/tram', 'railway/tram', 'railway/tram'],
83854             waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
83855           };
83856
83857           function render() {
83858             var p = _preset.apply(this, arguments);
83859
83860             var geom = _geometry ? _geometry.apply(this, arguments) : null;
83861
83862             if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
83863               geom = 'route';
83864             }
83865
83866             var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
83867             var isFallback = isSmall() && p.isFallback && p.isFallback();
83868             var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
83869             var picon = getIcon(p, geom);
83870             var isMaki = picon && /^maki-/.test(picon);
83871             var isTemaki = picon && /^temaki-/.test(picon);
83872             var isFa = picon && /^fa[srb]-/.test(picon);
83873             var isiDIcon = picon && !(isMaki || isTemaki || isFa);
83874             var isCategory = !p.setTags;
83875             var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
83876             var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
83877             var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
83878             var drawArea = picon && geom === 'area' && !isFallback;
83879             var drawRoute = picon && geom === 'route';
83880             var isFramed = drawVertex || drawArea || drawLine || drawRoute;
83881             var tags = !isCategory ? p.setTags({}, geom) : {};
83882
83883             for (var k in tags) {
83884               if (tags[k] === '*') {
83885                 tags[k] = 'yes';
83886               }
83887             }
83888
83889             var tagClasses = svgTagClasses().getClassesString(tags, '');
83890             var selection = select(this);
83891             var container = selection.selectAll('.preset-icon-container').data([0]);
83892             container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
83893             container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
83894             renderPointBorder(container, drawPoint);
83895             renderCircleFill(container, drawVertex);
83896             renderSquareFill(container, drawArea, tagClasses);
83897             renderLine(container, drawLine, tagClasses);
83898             renderRoute(container, drawRoute, p);
83899             var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
83900             icon.exit().remove();
83901             icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
83902             icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
83903             icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
83904             icon.selectAll('use').attr('href', '#' + picon + (isMaki ? isSmall() && geom === 'point' ? '-11' : '-15' : ''));
83905             var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
83906             imageIcon.exit().remove();
83907             imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
83908               return container.classed('showing-img', true);
83909             }).on('error', function () {
83910               return container.classed('showing-img', false);
83911             }).merge(imageIcon);
83912             imageIcon.attr('src', imageURL);
83913           }
83914
83915           presetIcon.preset = function (val) {
83916             if (!arguments.length) return _preset;
83917             _preset = utilFunctor(val);
83918             return presetIcon;
83919           };
83920
83921           presetIcon.geometry = function (val) {
83922             if (!arguments.length) return _geometry;
83923             _geometry = utilFunctor(val);
83924             return presetIcon;
83925           };
83926
83927           presetIcon.sizeClass = function (val) {
83928             if (!arguments.length) return _sizeClass;
83929             _sizeClass = val;
83930             return presetIcon;
83931           };
83932
83933           return presetIcon;
83934         }
83935
83936         function uiSectionFeatureType(context) {
83937           var dispatch$1 = dispatch('choose');
83938           var _entityIDs = [];
83939           var _presets = [];
83940
83941           var _tagReference;
83942
83943           var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
83944
83945           function renderDisclosureContent(selection) {
83946             selection.classed('preset-list-item', true);
83947             selection.classed('mixed-types', _presets.length > 1);
83948             var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
83949             var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
83950             presetButton.append('div').attr('class', 'preset-icon-container');
83951             presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
83952             presetButtonWrap.append('div').attr('class', 'accessory-buttons');
83953             var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
83954             tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
83955
83956             if (_tagReference) {
83957               selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
83958               tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
83959             }
83960
83961             selection.selectAll('.preset-reset').on('click', function () {
83962               dispatch$1.call('choose', this, _presets);
83963             }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
83964               d3_event.preventDefault();
83965               d3_event.stopPropagation();
83966             });
83967             var geometries = entityGeometries();
83968             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')));
83969             var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
83970             var label = selection.select('.label-inner');
83971             var nameparts = label.selectAll('.namepart').data(names, function (d) {
83972               return d;
83973             });
83974             nameparts.exit().remove();
83975             nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
83976               return d;
83977             });
83978           }
83979
83980           section.entityIDs = function (val) {
83981             if (!arguments.length) return _entityIDs;
83982             _entityIDs = val;
83983             return section;
83984           };
83985
83986           section.presets = function (val) {
83987             if (!arguments.length) return _presets; // don't reload the same preset
83988
83989             if (!utilArrayIdentical(val, _presets)) {
83990               _presets = val;
83991
83992               if (_presets.length === 1) {
83993                 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
83994               }
83995             }
83996
83997             return section;
83998           };
83999
84000           function entityGeometries() {
84001             var counts = {};
84002
84003             for (var i in _entityIDs) {
84004               var geometry = context.graph().geometry(_entityIDs[i]);
84005               if (!counts[geometry]) counts[geometry] = 0;
84006               counts[geometry] += 1;
84007             }
84008
84009             return Object.keys(counts).sort(function (geom1, geom2) {
84010               return counts[geom2] - counts[geom1];
84011             });
84012           }
84013
84014           return utilRebind(section, dispatch$1, 'on');
84015         }
84016
84017         // It borrows some code from uiHelp
84018
84019         function uiFieldHelp(context, fieldName) {
84020           var fieldHelp = {};
84021
84022           var _inspector = select(null);
84023
84024           var _wrap = select(null);
84025
84026           var _body = select(null);
84027
84028           var fieldHelpKeys = {
84029             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']]]
84030           };
84031           var fieldHelpHeadings = {};
84032           var replacements = {
84033             distField: _t.html('restriction.controls.distance'),
84034             viaField: _t.html('restriction.controls.via'),
84035             fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
84036             allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
84037             restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
84038             onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
84039             allowTurn: icon('#iD-turn-yes', 'inline turn'),
84040             restrictTurn: icon('#iD-turn-no', 'inline turn'),
84041             onlyTurn: icon('#iD-turn-only', 'inline turn')
84042           }; // For each section, squash all the texts into a single markdown document
84043
84044           var docs = fieldHelpKeys[fieldName].map(function (key) {
84045             var helpkey = 'help.field.' + fieldName + '.' + key[0];
84046             var text = key[1].reduce(function (all, part) {
84047               var subkey = helpkey + '.' + part;
84048               var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
84049
84050               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
84051
84052               return all + hhh + _t.html(subkey, replacements) + '\n\n';
84053             }, '');
84054             return {
84055               key: helpkey,
84056               title: _t.html(helpkey + '.title'),
84057               html: marked_1(text.trim())
84058             };
84059           });
84060
84061           function show() {
84062             updatePosition();
84063
84064             _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
84065           }
84066
84067           function hide() {
84068             _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
84069               _body.classed('hide', true);
84070             });
84071           }
84072
84073           function clickHelp(index) {
84074             var d = docs[index];
84075             var tkeys = fieldHelpKeys[fieldName][index][1];
84076
84077             _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
84078               return i === index;
84079             });
84080
84081             var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
84082
84083
84084             content.selectAll('p').attr('class', function (d, i) {
84085               return tkeys[i];
84086             }); // insert special content for certain help sections
84087
84088             if (d.key === 'help.field.restrictions.inspecting') {
84089               content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
84090             } else if (d.key === 'help.field.restrictions.modifying') {
84091               content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
84092             }
84093           }
84094
84095           fieldHelp.button = function (selection) {
84096             if (_body.empty()) return;
84097             var button = selection.selectAll('.field-help-button').data([0]); // enter/update
84098
84099             button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
84100               d3_event.stopPropagation();
84101               d3_event.preventDefault();
84102
84103               if (_body.classed('hide')) {
84104                 show();
84105               } else {
84106                 hide();
84107               }
84108             });
84109           };
84110
84111           function updatePosition() {
84112             var wrap = _wrap.node();
84113
84114             var inspector = _inspector.node();
84115
84116             var wRect = wrap.getBoundingClientRect();
84117             var iRect = inspector.getBoundingClientRect();
84118
84119             _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
84120           }
84121
84122           fieldHelp.body = function (selection) {
84123             // This control expects the field to have a form-field-input-wrap div
84124             _wrap = selection.selectAll('.form-field-input-wrap');
84125             if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
84126
84127             _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
84128             if (_inspector.empty()) return;
84129             _body = _inspector.selectAll('.field-help-body').data([0]);
84130
84131             var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
84132
84133
84134             var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
84135             titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
84136             titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
84137               d3_event.stopPropagation();
84138               d3_event.preventDefault();
84139               hide();
84140             }).call(svgIcon('#iD-icon-close'));
84141             var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
84142             var titles = docs.map(function (d) {
84143               return d.title;
84144             });
84145             navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
84146               return d;
84147             }).on('click', function (d3_event, d) {
84148               d3_event.stopPropagation();
84149               d3_event.preventDefault();
84150               clickHelp(titles.indexOf(d));
84151             });
84152             enter.append('div').attr('class', 'field-help-content');
84153             _body = _body.merge(enter);
84154             clickHelp(0);
84155           };
84156
84157           return fieldHelp;
84158         }
84159
84160         function uiFieldCheck(field, context) {
84161           var dispatch$1 = dispatch('change');
84162           var options = field.strings && field.strings.options;
84163           var values = [];
84164           var texts = [];
84165
84166           var _tags;
84167
84168           var input = select(null);
84169           var text = select(null);
84170           var label = select(null);
84171           var reverser = select(null);
84172
84173           var _impliedYes;
84174
84175           var _entityIDs = [];
84176
84177           var _value;
84178
84179           if (options) {
84180             for (var k in options) {
84181               values.push(k === 'undefined' ? undefined : k);
84182               texts.push(field.t.html('options.' + k, {
84183                 'default': options[k]
84184               }));
84185             }
84186           } else {
84187             values = [undefined, 'yes'];
84188             texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
84189
84190             if (field.type !== 'defaultCheck') {
84191               values.push('no');
84192               texts.push(_t.html('inspector.check.no'));
84193             }
84194           } // Checks tags to see whether an undefined value is "Assumed to be Yes"
84195
84196
84197           function checkImpliedYes() {
84198             _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
84199             // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
84200
84201             if (field.id === 'oneway') {
84202               var entity = context.entity(_entityIDs[0]);
84203
84204               for (var key in entity.tags) {
84205                 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
84206                   _impliedYes = true;
84207                   texts[0] = _t.html('presets.fields.oneway_yes.options.undefined');
84208                   break;
84209                 }
84210               }
84211             }
84212           }
84213
84214           function reverserHidden() {
84215             if (!context.container().select('div.inspector-hover').empty()) return true;
84216             return !(_value === 'yes' || _impliedYes && !_value);
84217           }
84218
84219           function reverserSetText(selection) {
84220             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84221             if (reverserHidden() || !entity) return selection;
84222             var first = entity.first();
84223             var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
84224             var pseudoDirection = first < last;
84225             var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
84226             selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
84227             return selection;
84228           }
84229
84230           var check = function check(selection) {
84231             checkImpliedYes();
84232             label = selection.selectAll('.form-field-input-wrap').data([0]);
84233             var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
84234             enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
84235             enter.append('span').html(texts[0]).attr('class', 'value');
84236
84237             if (field.type === 'onewayCheck') {
84238               enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
84239             }
84240
84241             label = label.merge(enter);
84242             input = label.selectAll('input');
84243             text = label.selectAll('span.value');
84244             input.on('click', function (d3_event) {
84245               d3_event.stopPropagation();
84246               var t = {};
84247
84248               if (Array.isArray(_tags[field.key])) {
84249                 if (values.indexOf('yes') !== -1) {
84250                   t[field.key] = 'yes';
84251                 } else {
84252                   t[field.key] = values[0];
84253                 }
84254               } else {
84255                 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
84256               } // Don't cycle through `alternating` or `reversible` states - #4970
84257               // (They are supported as translated strings, but should not toggle with clicks)
84258
84259
84260               if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
84261                 t[field.key] = values[0];
84262               }
84263
84264               dispatch$1.call('change', this, t);
84265             });
84266
84267             if (field.type === 'onewayCheck') {
84268               reverser = label.selectAll('.reverser');
84269               reverser.call(reverserSetText).on('click', function (d3_event) {
84270                 d3_event.preventDefault();
84271                 d3_event.stopPropagation();
84272                 context.perform(function (graph) {
84273                   for (var i in _entityIDs) {
84274                     graph = actionReverse(_entityIDs[i])(graph);
84275                   }
84276
84277                   return graph;
84278                 }, _t('operations.reverse.annotation.line', {
84279                   n: 1
84280                 })); // must manually revalidate since no 'change' event was called
84281
84282                 context.validator().validate();
84283                 select(this).call(reverserSetText);
84284               });
84285             }
84286           };
84287
84288           check.entityIDs = function (val) {
84289             if (!arguments.length) return _entityIDs;
84290             _entityIDs = val;
84291             return check;
84292           };
84293
84294           check.tags = function (tags) {
84295             _tags = tags;
84296
84297             function isChecked(val) {
84298               return val !== 'no' && val !== '' && val !== undefined && val !== null;
84299             }
84300
84301             function textFor(val) {
84302               if (val === '') val = undefined;
84303               var index = values.indexOf(val);
84304               return index !== -1 ? texts[index] : '"' + val + '"';
84305             }
84306
84307             checkImpliedYes();
84308             var isMixed = Array.isArray(tags[field.key]);
84309             _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
84310
84311             if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
84312               _value = 'yes';
84313             }
84314
84315             input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
84316             text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
84317             label.classed('set', !!_value);
84318
84319             if (field.type === 'onewayCheck') {
84320               reverser.classed('hide', reverserHidden()).call(reverserSetText);
84321             }
84322           };
84323
84324           check.focus = function () {
84325             input.node().focus();
84326           };
84327
84328           return utilRebind(check, dispatch$1, 'on');
84329         }
84330
84331         function uiFieldCombo(field, context) {
84332           var dispatch$1 = dispatch('change');
84333
84334           var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
84335
84336           var _isNetwork = field.type === 'networkCombo';
84337
84338           var _isSemi = field.type === 'semiCombo';
84339
84340           var _optstrings = field.strings && field.strings.options;
84341
84342           var _optarray = field.options;
84343
84344           var _snake_case = field.snake_case || field.snake_case === undefined;
84345
84346           var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
84347
84348           var _container = select(null);
84349
84350           var _inputWrap = select(null);
84351
84352           var _input = select(null);
84353
84354           var _comboData = [];
84355           var _multiData = [];
84356           var _entityIDs = [];
84357
84358           var _tags;
84359
84360           var _countryCode;
84361
84362           var _staticPlaceholder; // initialize deprecated tags array
84363
84364
84365           var _dataDeprecated = [];
84366           _mainFileFetcher.get('deprecated').then(function (d) {
84367             _dataDeprecated = d;
84368           })["catch"](function () {
84369             /* ignore */
84370           }); // ensure multiCombo field.key ends with a ':'
84371
84372           if (_isMulti && field.key && /[^:]$/.test(field.key)) {
84373             field.key += ':';
84374           }
84375
84376           function snake(s) {
84377             return s.replace(/\s+/g, '_');
84378           }
84379
84380           function unsnake(s) {
84381             return s.replace(/_+/g, ' ');
84382           }
84383
84384           function clean(s) {
84385             return s.split(';').map(function (s) {
84386               return s.trim();
84387             }).join(';');
84388           } // returns the tag value for a display value
84389           // (for multiCombo, dval should be the key suffix, not the entire key)
84390
84391
84392           function tagValue(dval) {
84393             dval = clean(dval || '');
84394
84395             if (_optstrings) {
84396               var found = _comboData.find(function (o) {
84397                 return o.key && clean(o.value) === dval;
84398               });
84399
84400               if (found) {
84401                 return found.key;
84402               }
84403             }
84404
84405             if (field.type === 'typeCombo' && !dval) {
84406               return 'yes';
84407             }
84408
84409             return (_snake_case ? snake(dval) : dval) || undefined;
84410           } // returns the display value for a tag value
84411           // (for multiCombo, tval should be the key suffix, not the entire key)
84412
84413
84414           function displayValue(tval) {
84415             tval = tval || '';
84416
84417             if (_optstrings) {
84418               var found = _comboData.find(function (o) {
84419                 return o.key === tval && o.value;
84420               });
84421
84422               if (found) {
84423                 return found.value;
84424               }
84425             }
84426
84427             if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
84428               return '';
84429             }
84430
84431             return _snake_case ? unsnake(tval) : tval;
84432           } // Compute the difference between arrays of objects by `value` property
84433           //
84434           // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
84435           // > [{value:1}, {value:3}]
84436           //
84437
84438
84439           function objectDifference(a, b) {
84440             return a.filter(function (d1) {
84441               return !b.some(function (d2) {
84442                 return !d2.isMixed && d1.value === d2.value;
84443               });
84444             });
84445           }
84446
84447           function initCombo(selection, attachTo) {
84448             if (_optstrings) {
84449               selection.attr('readonly', 'readonly');
84450               selection.call(_combobox, attachTo);
84451               setStaticValues(setPlaceholder);
84452             } else if (_optarray) {
84453               selection.call(_combobox, attachTo);
84454               setStaticValues(setPlaceholder);
84455             } else if (services.taginfo) {
84456               selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
84457               setTaginfoValues('', setPlaceholder);
84458             }
84459           }
84460
84461           function setStaticValues(callback) {
84462             if (!(_optstrings || _optarray)) return;
84463
84464             if (_optstrings) {
84465               _comboData = Object.keys(_optstrings).map(function (k) {
84466                 var v = field.t('options.' + k, {
84467                   'default': _optstrings[k]
84468                 });
84469                 return {
84470                   key: k,
84471                   value: v,
84472                   title: v,
84473                   display: field.t.html('options.' + k, {
84474                     'default': _optstrings[k]
84475                   })
84476                 };
84477               });
84478             } else if (_optarray) {
84479               _comboData = _optarray.map(function (k) {
84480                 var v = _snake_case ? unsnake(k) : k;
84481                 return {
84482                   key: k,
84483                   value: v,
84484                   title: v
84485                 };
84486               });
84487             }
84488
84489             _combobox.data(objectDifference(_comboData, _multiData));
84490
84491             if (callback) callback(_comboData);
84492           }
84493
84494           function setTaginfoValues(q, callback) {
84495             var fn = _isMulti ? 'multikeys' : 'values';
84496             var query = (_isMulti ? field.key : '') + q;
84497             var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
84498
84499             if (hasCountryPrefix) {
84500               query = _countryCode + ':';
84501             }
84502
84503             var params = {
84504               debounce: q !== '',
84505               key: field.key,
84506               query: query
84507             };
84508
84509             if (_entityIDs.length) {
84510               params.geometry = context.graph().geometry(_entityIDs[0]);
84511             }
84512
84513             services.taginfo[fn](params, function (err, data) {
84514               if (err) return;
84515               data = data.filter(function (d) {
84516                 if (field.type === 'typeCombo' && d.value === 'yes') {
84517                   // don't show the fallback value
84518                   return false;
84519                 } // don't show values with very low usage
84520
84521
84522                 return !d.count || d.count > 10;
84523               });
84524               var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
84525
84526               if (deprecatedValues) {
84527                 // don't suggest deprecated tag values
84528                 data = data.filter(function (d) {
84529                   return deprecatedValues.indexOf(d.value) === -1;
84530                 });
84531               }
84532
84533               if (hasCountryPrefix) {
84534                 data = data.filter(function (d) {
84535                   return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
84536                 });
84537               } // hide the caret if there are no suggestions
84538
84539
84540               _container.classed('empty-combobox', data.length === 0);
84541
84542               _comboData = data.map(function (d) {
84543                 var k = d.value;
84544                 if (_isMulti) k = k.replace(field.key, '');
84545                 var v = _snake_case ? unsnake(k) : k;
84546                 return {
84547                   key: k,
84548                   value: v,
84549                   title: _isMulti ? v : d.title
84550                 };
84551               });
84552               _comboData = objectDifference(_comboData, _multiData);
84553               if (callback) callback(_comboData);
84554             });
84555           }
84556
84557           function setPlaceholder(values) {
84558             if (_isMulti || _isSemi) {
84559               _staticPlaceholder = field.placeholder() || _t('inspector.add');
84560             } else {
84561               var vals = values.map(function (d) {
84562                 return d.value;
84563               }).filter(function (s) {
84564                 return s.length < 20;
84565               });
84566               var placeholders = vals.length > 1 ? vals : values.map(function (d) {
84567                 return d.key;
84568               });
84569               _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
84570             }
84571
84572             if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
84573               _staticPlaceholder += '…';
84574             }
84575
84576             var ph;
84577
84578             if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
84579               ph = _t('inspector.multiple_values');
84580             } else {
84581               ph = _staticPlaceholder;
84582             }
84583
84584             _container.selectAll('input').attr('placeholder', ph);
84585           }
84586
84587           function change() {
84588             var t = {};
84589             var val;
84590
84591             if (_isMulti || _isSemi) {
84592               val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
84593
84594               _container.classed('active', false);
84595
84596               utilGetSetValue(_input, '');
84597               var vals = val.split(';').filter(Boolean);
84598               if (!vals.length) return;
84599
84600               if (_isMulti) {
84601                 utilArrayUniq(vals).forEach(function (v) {
84602                   var key = (field.key || '') + v;
84603
84604                   if (_tags) {
84605                     // don't set a multicombo value to 'yes' if it already has a non-'no' value
84606                     // e.g. `language:de=main`
84607                     var old = _tags[key];
84608                     if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
84609                   }
84610
84611                   key = context.cleanTagKey(key);
84612                   field.keys.push(key);
84613                   t[key] = 'yes';
84614                 });
84615               } else if (_isSemi) {
84616                 var arr = _multiData.map(function (d) {
84617                   return d.key;
84618                 });
84619
84620                 arr = arr.concat(vals);
84621                 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
84622               }
84623
84624               window.setTimeout(function () {
84625                 _input.node().focus();
84626               }, 10);
84627             } else {
84628               var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
84629
84630               if (!rawValue && Array.isArray(_tags[field.key])) return;
84631               val = context.cleanTagValue(tagValue(rawValue));
84632               t[field.key] = val || undefined;
84633             }
84634
84635             dispatch$1.call('change', this, t);
84636           }
84637
84638           function removeMultikey(d3_event, d) {
84639             d3_event.preventDefault();
84640             d3_event.stopPropagation();
84641             var t = {};
84642
84643             if (_isMulti) {
84644               t[d.key] = undefined;
84645             } else if (_isSemi) {
84646               var arr = _multiData.map(function (md) {
84647                 return md.key === d.key ? null : md.key;
84648               }).filter(Boolean);
84649
84650               arr = utilArrayUniq(arr);
84651               t[field.key] = arr.length ? arr.join(';') : undefined;
84652             }
84653
84654             dispatch$1.call('change', this, t);
84655           }
84656
84657           function combo(selection) {
84658             _container = selection.selectAll('.form-field-input-wrap').data([0]);
84659             var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
84660             _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
84661
84662             if (_isMulti || _isSemi) {
84663               _container = _container.selectAll('.chiplist').data([0]);
84664               var listClass = 'chiplist'; // Use a separate line for each value in the Destinations field
84665               // to mimic highway exit signs
84666
84667               if (field.key === 'destination') {
84668                 listClass += ' full-line-chips';
84669               }
84670
84671               _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
84672                 window.setTimeout(function () {
84673                   _input.node().focus();
84674                 }, 10);
84675               }).merge(_container);
84676               _inputWrap = _container.selectAll('.input-wrap').data([0]);
84677               _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
84678               _input = _inputWrap.selectAll('input').data([0]);
84679             } else {
84680               _input = _container.selectAll('input').data([0]);
84681             }
84682
84683             _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
84684
84685             if (_isNetwork) {
84686               var extent = combinedEntityExtent();
84687               var countryCode = extent && iso1A2Code(extent.center());
84688               _countryCode = countryCode && countryCode.toLowerCase();
84689             }
84690
84691             _input.on('change', change).on('blur', change);
84692
84693             _input.on('keydown.field', function (d3_event) {
84694               switch (d3_event.keyCode) {
84695                 case 13:
84696                   // ↩ Return
84697                   _input.node().blur(); // blurring also enters the value
84698
84699
84700                   d3_event.stopPropagation();
84701                   break;
84702               }
84703             });
84704
84705             if (_isMulti || _isSemi) {
84706               _combobox.on('accept', function () {
84707                 _input.node().blur();
84708
84709                 _input.node().focus();
84710               });
84711
84712               _input.on('focus', function () {
84713                 _container.classed('active', true);
84714               });
84715             }
84716           }
84717
84718           combo.tags = function (tags) {
84719             _tags = tags;
84720
84721             if (_isMulti || _isSemi) {
84722               _multiData = [];
84723               var maxLength;
84724
84725               if (_isMulti) {
84726                 // Build _multiData array containing keys already set..
84727                 for (var k in tags) {
84728                   if (field.key && k.indexOf(field.key) !== 0) continue;
84729                   if (!field.key && field.keys.indexOf(k) === -1) continue;
84730                   var v = tags[k];
84731                   if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
84732                   var suffix = field.key ? k.substr(field.key.length) : k;
84733
84734                   _multiData.push({
84735                     key: k,
84736                     value: displayValue(suffix),
84737                     isMixed: Array.isArray(v)
84738                   });
84739                 }
84740
84741                 if (field.key) {
84742                   // Set keys for form-field modified (needed for undo and reset buttons)..
84743                   field.keys = _multiData.map(function (d) {
84744                     return d.key;
84745                   }); // limit the input length so it fits after prepending the key prefix
84746
84747                   maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
84748                 } else {
84749                   maxLength = context.maxCharsForTagKey();
84750                 }
84751               } else if (_isSemi) {
84752                 var allValues = [];
84753                 var commonValues;
84754
84755                 if (Array.isArray(tags[field.key])) {
84756                   tags[field.key].forEach(function (tagVal) {
84757                     var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
84758                     allValues = allValues.concat(thisVals);
84759
84760                     if (!commonValues) {
84761                       commonValues = thisVals;
84762                     } else {
84763                       commonValues = commonValues.filter(function (value) {
84764                         return thisVals.includes(value);
84765                       });
84766                     }
84767                   });
84768                   allValues = utilArrayUniq(allValues).filter(Boolean);
84769                 } else {
84770                   allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
84771                   commonValues = allValues;
84772                 }
84773
84774                 _multiData = allValues.map(function (v) {
84775                   return {
84776                     key: v,
84777                     value: displayValue(v),
84778                     isMixed: !commonValues.includes(v)
84779                   };
84780                 });
84781                 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
84782
84783                 maxLength = context.maxCharsForTagValue() - currLength;
84784
84785                 if (currLength > 0) {
84786                   // account for the separator if a new value will be appended to existing
84787                   maxLength -= 1;
84788                 }
84789               } // a negative maxlength doesn't make sense
84790
84791
84792               maxLength = Math.max(0, maxLength);
84793               var allowDragAndDrop = _isSemi // only semiCombo values are ordered
84794               && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
84795
84796               var available = objectDifference(_comboData, _multiData);
84797
84798               _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
84799               // translateable _optstrings and they're all currently used,
84800               // or if the field is already at its character limit
84801
84802
84803               var hideAdd = _optstrings && !available.length || maxLength <= 0;
84804
84805               _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
84806
84807
84808               var chips = _container.selectAll('.chip').data(_multiData);
84809
84810               chips.exit().remove();
84811               var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
84812               enter.append('span');
84813               enter.append('a');
84814               chips = chips.merge(enter).order().classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
84815                 return d.isMixed;
84816               }).attr('title', function (d) {
84817                 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
84818               });
84819
84820               if (allowDragAndDrop) {
84821                 registerDragAndDrop(chips);
84822               }
84823
84824               chips.select('span').html(function (d) {
84825                 return d.value;
84826               });
84827               chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
84828             } else {
84829               var isMixed = Array.isArray(tags[field.key]);
84830               var mixedValues = isMixed && tags[field.key].map(function (val) {
84831                 return displayValue(val);
84832               }).filter(Boolean);
84833               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);
84834             }
84835           };
84836
84837           function registerDragAndDrop(selection) {
84838             // allow drag and drop re-ordering of chips
84839             var dragOrigin, targetIndex;
84840             selection.call(d3_drag().on('start', function (d3_event) {
84841               dragOrigin = {
84842                 x: d3_event.x,
84843                 y: d3_event.y
84844               };
84845               targetIndex = null;
84846             }).on('drag', function (d3_event) {
84847               var x = d3_event.x - dragOrigin.x,
84848                   y = d3_event.y - dragOrigin.y;
84849               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
84850               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
84851               var index = selection.nodes().indexOf(this);
84852               select(this).classed('dragging', true);
84853               targetIndex = null;
84854               var targetIndexOffsetTop = null;
84855               var draggedTagWidth = select(this).node().offsetWidth;
84856
84857               if (field.key === 'destination') {
84858                 // meaning tags are full width
84859                 _container.selectAll('.chip').style('transform', function (d2, index2) {
84860                   var node = select(this).node();
84861
84862                   if (index === index2) {
84863                     return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
84864                   } else if (index2 > index && d3_event.y > node.offsetTop) {
84865                     if (targetIndex === null || index2 > targetIndex) {
84866                       targetIndex = index2;
84867                     }
84868
84869                     return 'translateY(-100%)'; // move the dragged tag down the order
84870                   } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
84871                     if (targetIndex === null || index2 < targetIndex) {
84872                       targetIndex = index2;
84873                     }
84874
84875                     return 'translateY(100%)';
84876                   }
84877
84878                   return null;
84879                 });
84880               } else {
84881                 _container.selectAll('.chip').each(function (d2, index2) {
84882                   var node = select(this).node(); // check the cursor is in the bounding box
84883
84884                   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) {
84885                     targetIndex = index2;
84886                     targetIndexOffsetTop = node.offsetTop;
84887                   }
84888                 }).style('transform', function (d2, index2) {
84889                   var node = select(this).node();
84890
84891                   if (index === index2) {
84892                     return 'translate(' + x + 'px, ' + y + 'px)';
84893                   } // only translate tags in the same row
84894
84895
84896                   if (node.offsetTop === targetIndexOffsetTop) {
84897                     if (index2 < index && index2 >= targetIndex) {
84898                       return 'translateX(' + draggedTagWidth + 'px)';
84899                     } else if (index2 > index && index2 <= targetIndex) {
84900                       return 'translateX(-' + draggedTagWidth + 'px)';
84901                     }
84902                   }
84903
84904                   return null;
84905                 });
84906               }
84907             }).on('end', function () {
84908               if (!select(this).classed('dragging')) {
84909                 return;
84910               }
84911
84912               var index = selection.nodes().indexOf(this);
84913               select(this).classed('dragging', false);
84914
84915               _container.selectAll('.chip').style('transform', null);
84916
84917               if (typeof targetIndex === 'number') {
84918                 var element = _multiData[index];
84919
84920                 _multiData.splice(index, 1);
84921
84922                 _multiData.splice(targetIndex, 0, element);
84923
84924                 var t = {};
84925
84926                 if (_multiData.length) {
84927                   t[field.key] = _multiData.map(function (element) {
84928                     return element.key;
84929                   }).join(';');
84930                 } else {
84931                   t[field.key] = undefined;
84932                 }
84933
84934                 dispatch$1.call('change', this, t);
84935               }
84936
84937               dragOrigin = undefined;
84938               targetIndex = undefined;
84939             }));
84940           }
84941
84942           combo.focus = function () {
84943             _input.node().focus();
84944           };
84945
84946           combo.entityIDs = function (val) {
84947             if (!arguments.length) return _entityIDs;
84948             _entityIDs = val;
84949             return combo;
84950           };
84951
84952           function combinedEntityExtent() {
84953             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
84954           }
84955
84956           return utilRebind(combo, dispatch$1, 'on');
84957         }
84958
84959         function uiFieldText(field, context) {
84960           var dispatch$1 = dispatch('change');
84961           var input = select(null);
84962           var outlinkButton = select(null);
84963           var _entityIDs = [];
84964
84965           var _tags;
84966
84967           var _phoneFormats = {};
84968
84969           if (field.type === 'tel') {
84970             _mainFileFetcher.get('phone_formats').then(function (d) {
84971               _phoneFormats = d;
84972               updatePhonePlaceholder();
84973             })["catch"](function () {
84974               /* ignore */
84975             });
84976           }
84977
84978           function i(selection) {
84979             var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
84980             var preset = entity && _mainPresetIndex.match(entity, context.graph());
84981             var isLocked = preset && preset.suggestion && field.id === 'brand';
84982             field.locked(isLocked);
84983             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
84984             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
84985             input = wrap.selectAll('input').data([0]);
84986             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);
84987             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
84988
84989             if (field.type === 'tel') {
84990               updatePhonePlaceholder();
84991             } else if (field.type === 'number') {
84992               var rtl = _mainLocalizer.textDirection() === 'rtl';
84993               input.attr('type', 'text');
84994               var inc = field.increment;
84995               var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
84996               buttons.enter().append('button').attr('class', function (d) {
84997                 var which = d > 0 ? 'increment' : 'decrement';
84998                 return 'form-field-button ' + which;
84999               }).merge(buttons).on('click', function (d3_event, d) {
85000                 d3_event.preventDefault();
85001                 var raw_vals = input.node().value || '0';
85002                 var vals = raw_vals.split(';');
85003                 vals = vals.map(function (v) {
85004                   var num = parseFloat(v.trim(), 10);
85005                   return isFinite(num) ? clamped(num + d) : v.trim();
85006                 });
85007                 input.node().value = vals.join(';');
85008                 change()();
85009               });
85010             } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
85011               input.attr('type', 'text');
85012               outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
85013               outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
85014                 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
85015
85016                 if (domainResults.length >= 2 && domainResults[1]) {
85017                   var domain = domainResults[1];
85018                   return _t('icons.view_on', {
85019                     domain: domain
85020                   });
85021                 }
85022
85023                 return '';
85024               }).on('click', function (d3_event) {
85025                 d3_event.preventDefault();
85026                 var value = validIdentifierValueForLink();
85027
85028                 if (value) {
85029                   var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
85030                   window.open(url, '_blank');
85031                 }
85032               }).merge(outlinkButton);
85033             }
85034           }
85035
85036           function updatePhonePlaceholder() {
85037             if (input.empty() || !Object.keys(_phoneFormats).length) return;
85038             var extent = combinedEntityExtent();
85039             var countryCode = extent && iso1A2Code(extent.center());
85040
85041             var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
85042
85043             if (format) input.attr('placeholder', format);
85044           }
85045
85046           function validIdentifierValueForLink() {
85047             if (field.type === 'identifier' && field.pattern) {
85048               var value = utilGetSetValue(input).trim().split(';')[0];
85049               return value && value.match(new RegExp(field.pattern));
85050             }
85051
85052             return null;
85053           } // clamp number to min/max
85054
85055
85056           function clamped(num) {
85057             if (field.minValue !== undefined) {
85058               num = Math.max(num, field.minValue);
85059             }
85060
85061             if (field.maxValue !== undefined) {
85062               num = Math.min(num, field.maxValue);
85063             }
85064
85065             return num;
85066           }
85067
85068           function change(onInput) {
85069             return function () {
85070               var t = {};
85071               var val = utilGetSetValue(input);
85072               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
85073
85074               if (!val && Array.isArray(_tags[field.key])) return;
85075
85076               if (!onInput) {
85077                 if (field.type === 'number' && val) {
85078                   var vals = val.split(';');
85079                   vals = vals.map(function (v) {
85080                     var num = parseFloat(v.trim(), 10);
85081                     return isFinite(num) ? clamped(num) : v.trim();
85082                   });
85083                   val = vals.join(';');
85084                 }
85085
85086                 utilGetSetValue(input, val);
85087               }
85088
85089               t[field.key] = val || undefined;
85090               dispatch$1.call('change', this, t, onInput);
85091             };
85092           }
85093
85094           i.entityIDs = function (val) {
85095             if (!arguments.length) return _entityIDs;
85096             _entityIDs = val;
85097             return i;
85098           };
85099
85100           i.tags = function (tags) {
85101             _tags = tags;
85102             var isMixed = Array.isArray(tags[field.key]);
85103             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);
85104
85105             if (outlinkButton && !outlinkButton.empty()) {
85106               var disabled = !validIdentifierValueForLink();
85107               outlinkButton.classed('disabled', disabled);
85108             }
85109           };
85110
85111           i.focus = function () {
85112             var node = input.node();
85113             if (node) node.focus();
85114           };
85115
85116           function combinedEntityExtent() {
85117             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85118           }
85119
85120           return utilRebind(i, dispatch$1, 'on');
85121         }
85122
85123         function uiFieldAccess(field, context) {
85124           var dispatch$1 = dispatch('change');
85125           var items = select(null);
85126
85127           var _tags;
85128
85129           function access(selection) {
85130             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85131             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85132             var list = wrap.selectAll('ul').data([0]);
85133             list = list.enter().append('ul').attr('class', 'rows').merge(list);
85134             items = list.selectAll('li').data(field.keys); // Enter
85135
85136             var enter = items.enter().append('li').attr('class', function (d) {
85137               return 'labeled-input preset-access-' + d;
85138             });
85139             enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
85140               return 'preset-input-access-' + d;
85141             }).html(function (d) {
85142               return field.t.html('types.' + d);
85143             });
85144             enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
85145               return 'preset-input-access preset-input-access-' + d;
85146             }).call(utilNoAuto).each(function (d) {
85147               select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
85148             }); // Update
85149
85150             items = items.merge(enter);
85151             wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
85152           }
85153
85154           function change(d3_event, d) {
85155             var tag = {};
85156             var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
85157
85158             if (!value && typeof _tags[d] !== 'string') return;
85159             tag[d] = value || undefined;
85160             dispatch$1.call('change', this, tag);
85161           }
85162
85163           access.options = function (type) {
85164             var options = ['no', 'permissive', 'private', 'permit', 'destination'];
85165
85166             if (type !== 'access') {
85167               options.unshift('yes');
85168               options.push('designated');
85169
85170               if (type === 'bicycle') {
85171                 options.push('dismount');
85172               }
85173             }
85174
85175             return options.map(function (option) {
85176               return {
85177                 title: field.t('options.' + option + '.description'),
85178                 value: option
85179               };
85180             });
85181           };
85182
85183           var placeholdersByHighway = {
85184             footway: {
85185               foot: 'designated',
85186               motor_vehicle: 'no'
85187             },
85188             steps: {
85189               foot: 'yes',
85190               motor_vehicle: 'no',
85191               bicycle: 'no',
85192               horse: 'no'
85193             },
85194             pedestrian: {
85195               foot: 'yes',
85196               motor_vehicle: 'no'
85197             },
85198             cycleway: {
85199               motor_vehicle: 'no',
85200               bicycle: 'designated'
85201             },
85202             bridleway: {
85203               motor_vehicle: 'no',
85204               horse: 'designated'
85205             },
85206             path: {
85207               foot: 'yes',
85208               motor_vehicle: 'no',
85209               bicycle: 'yes',
85210               horse: 'yes'
85211             },
85212             motorway: {
85213               foot: 'no',
85214               motor_vehicle: 'yes',
85215               bicycle: 'no',
85216               horse: 'no'
85217             },
85218             trunk: {
85219               motor_vehicle: 'yes'
85220             },
85221             primary: {
85222               foot: 'yes',
85223               motor_vehicle: 'yes',
85224               bicycle: 'yes',
85225               horse: 'yes'
85226             },
85227             secondary: {
85228               foot: 'yes',
85229               motor_vehicle: 'yes',
85230               bicycle: 'yes',
85231               horse: 'yes'
85232             },
85233             tertiary: {
85234               foot: 'yes',
85235               motor_vehicle: 'yes',
85236               bicycle: 'yes',
85237               horse: 'yes'
85238             },
85239             residential: {
85240               foot: 'yes',
85241               motor_vehicle: 'yes',
85242               bicycle: 'yes',
85243               horse: 'yes'
85244             },
85245             unclassified: {
85246               foot: 'yes',
85247               motor_vehicle: 'yes',
85248               bicycle: 'yes',
85249               horse: 'yes'
85250             },
85251             service: {
85252               foot: 'yes',
85253               motor_vehicle: 'yes',
85254               bicycle: 'yes',
85255               horse: 'yes'
85256             },
85257             motorway_link: {
85258               foot: 'no',
85259               motor_vehicle: 'yes',
85260               bicycle: 'no',
85261               horse: 'no'
85262             },
85263             trunk_link: {
85264               motor_vehicle: 'yes'
85265             },
85266             primary_link: {
85267               foot: 'yes',
85268               motor_vehicle: 'yes',
85269               bicycle: 'yes',
85270               horse: 'yes'
85271             },
85272             secondary_link: {
85273               foot: 'yes',
85274               motor_vehicle: 'yes',
85275               bicycle: 'yes',
85276               horse: 'yes'
85277             },
85278             tertiary_link: {
85279               foot: 'yes',
85280               motor_vehicle: 'yes',
85281               bicycle: 'yes',
85282               horse: 'yes'
85283             }
85284           };
85285
85286           access.tags = function (tags) {
85287             _tags = tags;
85288             utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
85289               return typeof tags[d] === 'string' ? tags[d] : '';
85290             }).classed('mixed', function (d) {
85291               return tags[d] && Array.isArray(tags[d]);
85292             }).attr('title', function (d) {
85293               return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
85294             }).attr('placeholder', function (d) {
85295               if (tags[d] && Array.isArray(tags[d])) {
85296                 return _t('inspector.multiple_values');
85297               }
85298
85299               if (d === 'access') {
85300                 return 'yes';
85301               }
85302
85303               if (tags.access && typeof tags.access === 'string') {
85304                 return tags.access;
85305               }
85306
85307               if (tags.highway) {
85308                 if (typeof tags.highway === 'string') {
85309                   if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
85310                     return placeholdersByHighway[tags.highway][d];
85311                   }
85312                 } else {
85313                   var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
85314                     return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
85315                   }).filter(Boolean);
85316
85317                   if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
85318                     // if all the highway values have the same implied access for this type then use that
85319                     return impliedAccesses[0];
85320                   }
85321                 }
85322               }
85323
85324               return field.placeholder();
85325             });
85326           };
85327
85328           access.focus = function () {
85329             items.selectAll('.preset-input-access').node().focus();
85330           };
85331
85332           return utilRebind(access, dispatch$1, 'on');
85333         }
85334
85335         function uiFieldAddress(field, context) {
85336           var dispatch$1 = dispatch('change');
85337
85338           var _selection = select(null);
85339
85340           var _wrap = select(null);
85341
85342           var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
85343
85344           var _entityIDs = [];
85345
85346           var _tags;
85347
85348           var _countryCode;
85349
85350           var _addressFormats = [{
85351             format: [['housenumber', 'street'], ['city', 'postcode']]
85352           }];
85353           _mainFileFetcher.get('address_formats').then(function (d) {
85354             _addressFormats = d;
85355
85356             if (!_selection.empty()) {
85357               _selection.call(address);
85358             }
85359           })["catch"](function () {
85360             /* ignore */
85361           });
85362
85363           function getNearStreets() {
85364             var extent = combinedEntityExtent();
85365             var l = extent.center();
85366             var box = geoExtent(l).padByMeters(200);
85367             var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
85368               var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
85369               var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
85370               return {
85371                 title: d.tags.name,
85372                 value: d.tags.name,
85373                 dist: choice.distance
85374               };
85375             }).sort(function (a, b) {
85376               return a.dist - b.dist;
85377             });
85378             return utilArrayUniqBy(streets, 'value');
85379
85380             function isAddressable(d) {
85381               return d.tags.highway && d.tags.name && d.type === 'way';
85382             }
85383           }
85384
85385           function getNearCities() {
85386             var extent = combinedEntityExtent();
85387             var l = extent.center();
85388             var box = geoExtent(l).padByMeters(200);
85389             var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
85390               return {
85391                 title: d.tags['addr:city'] || d.tags.name,
85392                 value: d.tags['addr:city'] || d.tags.name,
85393                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
85394               };
85395             }).sort(function (a, b) {
85396               return a.dist - b.dist;
85397             });
85398             return utilArrayUniqBy(cities, 'value');
85399
85400             function isAddressable(d) {
85401               if (d.tags.name) {
85402                 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
85403                 if (d.tags.border_type === 'city') return true;
85404                 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
85405               }
85406
85407               if (d.tags['addr:city']) return true;
85408               return false;
85409             }
85410           }
85411
85412           function getNearValues(key) {
85413             var extent = combinedEntityExtent();
85414             var l = extent.center();
85415             var box = geoExtent(l).padByMeters(200);
85416             var results = context.history().intersects(box).filter(function hasTag(d) {
85417               return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
85418             }).map(function (d) {
85419               return {
85420                 title: d.tags[key],
85421                 value: d.tags[key],
85422                 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
85423               };
85424             }).sort(function (a, b) {
85425               return a.dist - b.dist;
85426             });
85427             return utilArrayUniqBy(results, 'value');
85428           }
85429
85430           function updateForCountryCode() {
85431             if (!_countryCode) return;
85432             var addressFormat;
85433
85434             for (var i = 0; i < _addressFormats.length; i++) {
85435               var format = _addressFormats[i];
85436
85437               if (!format.countryCodes) {
85438                 addressFormat = format; // choose the default format, keep going
85439               } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
85440                 addressFormat = format; // choose the country format, stop here
85441
85442                 break;
85443               }
85444             }
85445
85446             var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
85447             var widths = addressFormat.widths || {
85448               housenumber: 1 / 3,
85449               street: 2 / 3,
85450               city: 2 / 3,
85451               state: 1 / 4,
85452               postcode: 1 / 3
85453             };
85454
85455             function row(r) {
85456               // Normalize widths.
85457               var total = r.reduce(function (sum, key) {
85458                 return sum + (widths[key] || 0.5);
85459               }, 0);
85460               return r.map(function (key) {
85461                 return {
85462                   id: key,
85463                   width: (widths[key] || 0.5) / total
85464                 };
85465               });
85466             }
85467
85468             var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
85469               return d.toString();
85470             });
85471
85472             rows.exit().remove();
85473             rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
85474               return 'addr-' + d.id;
85475             }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
85476               return d.width * 100 + '%';
85477             });
85478
85479             function addDropdown(d) {
85480               if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
85481
85482               var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
85483               select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
85484                 callback(nearValues('addr:' + d.id));
85485               }));
85486             }
85487
85488             _wrap.selectAll('input').on('blur', change()).on('change', change());
85489
85490             _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
85491
85492             if (_tags) updateTags(_tags);
85493           }
85494
85495           function address(selection) {
85496             _selection = selection;
85497             _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85498             _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
85499             var extent = combinedEntityExtent();
85500
85501             if (extent) {
85502               var countryCode;
85503
85504               if (context.inIntro()) {
85505                 // localize the address format for the walkthrough
85506                 countryCode = _t('intro.graph.countrycode');
85507               } else {
85508                 var center = extent.center();
85509                 countryCode = iso1A2Code(center);
85510               }
85511
85512               if (countryCode) {
85513                 _countryCode = countryCode.toLowerCase();
85514                 updateForCountryCode();
85515               }
85516             }
85517           }
85518
85519           function change(onInput) {
85520             return function () {
85521               var tags = {};
85522
85523               _wrap.selectAll('input').each(function (subfield) {
85524                 var key = field.key + ':' + subfield.id;
85525                 var value = this.value;
85526                 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
85527
85528                 if (Array.isArray(_tags[key]) && !value) return;
85529                 tags[key] = value || undefined;
85530               });
85531
85532               dispatch$1.call('change', this, tags, onInput);
85533             };
85534           }
85535
85536           function updatePlaceholder(inputSelection) {
85537             return inputSelection.attr('placeholder', function (subfield) {
85538               if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
85539                 return _t('inspector.multiple_values');
85540               }
85541
85542               if (_countryCode) {
85543                 var localkey = subfield.id + '!' + _countryCode;
85544                 var tkey = addrField.strings.placeholders[localkey] ? localkey : subfield.id;
85545                 return addrField.t('placeholders.' + tkey);
85546               }
85547             });
85548           }
85549
85550           function updateTags(tags) {
85551             utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
85552               var val = tags[field.key + ':' + subfield.id];
85553               return typeof val === 'string' ? val : '';
85554             }).attr('title', function (subfield) {
85555               var val = tags[field.key + ':' + subfield.id];
85556               return val && Array.isArray(val) && val.filter(Boolean).join('\n');
85557             }).classed('mixed', function (subfield) {
85558               return Array.isArray(tags[field.key + ':' + subfield.id]);
85559             }).call(updatePlaceholder);
85560           }
85561
85562           function combinedEntityExtent() {
85563             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
85564           }
85565
85566           address.entityIDs = function (val) {
85567             if (!arguments.length) return _entityIDs;
85568             _entityIDs = val;
85569             return address;
85570           };
85571
85572           address.tags = function (tags) {
85573             _tags = tags;
85574             updateTags(tags);
85575           };
85576
85577           address.focus = function () {
85578             var node = _wrap.selectAll('input').node();
85579
85580             if (node) node.focus();
85581           };
85582
85583           return utilRebind(address, dispatch$1, 'on');
85584         }
85585
85586         function uiFieldCycleway(field, context) {
85587           var dispatch$1 = dispatch('change');
85588           var items = select(null);
85589           var wrap = select(null);
85590
85591           var _tags;
85592
85593           function cycleway(selection) {
85594             function stripcolon(s) {
85595               return s.replace(':', '');
85596             }
85597
85598             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85599             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85600             var div = wrap.selectAll('ul').data([0]);
85601             div = div.enter().append('ul').attr('class', 'rows').merge(div);
85602             var keys = ['cycleway:left', 'cycleway:right'];
85603             items = div.selectAll('li').data(keys);
85604             var enter = items.enter().append('li').attr('class', function (d) {
85605               return 'labeled-input preset-cycleway-' + stripcolon(d);
85606             });
85607             enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
85608               return 'preset-input-cycleway-' + stripcolon(d);
85609             }).html(function (d) {
85610               return field.t.html('types.' + d);
85611             });
85612             enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
85613               return 'preset-input-cycleway preset-input-' + stripcolon(d);
85614             }).call(utilNoAuto).each(function (d) {
85615               select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
85616             });
85617             items = items.merge(enter); // Update
85618
85619             wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
85620           }
85621
85622           function change(d3_event, key) {
85623             var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
85624
85625             if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
85626
85627             if (newValue === 'none' || newValue === '') {
85628               newValue = undefined;
85629             }
85630
85631             var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
85632             var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
85633
85634             if (otherValue && Array.isArray(otherValue)) {
85635               // we must always have an explicit value for comparison
85636               otherValue = otherValue[0];
85637             }
85638
85639             if (otherValue === 'none' || otherValue === '') {
85640               otherValue = undefined;
85641             }
85642
85643             var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
85644             // sides the same way
85645
85646             if (newValue === otherValue) {
85647               tag = {
85648                 cycleway: newValue,
85649                 'cycleway:left': undefined,
85650                 'cycleway:right': undefined
85651               };
85652             } else {
85653               // Always set both left and right as changing one can affect the other
85654               tag = {
85655                 cycleway: undefined
85656               };
85657               tag[key] = newValue;
85658               tag[otherKey] = otherValue;
85659             }
85660
85661             dispatch$1.call('change', this, tag);
85662           }
85663
85664           cycleway.options = function () {
85665             return Object.keys(field.strings.options).map(function (option) {
85666               return {
85667                 title: field.t('options.' + option + '.description'),
85668                 value: option
85669               };
85670             });
85671           };
85672
85673           cycleway.tags = function (tags) {
85674             _tags = tags; // If cycleway is set, use that instead of individual values
85675
85676             var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
85677             utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
85678               if (commonValue) return commonValue;
85679               return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
85680             }).attr('title', function (d) {
85681               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
85682                 var vals = [];
85683
85684                 if (Array.isArray(tags.cycleway)) {
85685                   vals = vals.concat(tags.cycleway);
85686                 }
85687
85688                 if (Array.isArray(tags[d])) {
85689                   vals = vals.concat(tags[d]);
85690                 }
85691
85692                 return vals.filter(Boolean).join('\n');
85693               }
85694
85695               return null;
85696             }).attr('placeholder', function (d) {
85697               if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
85698                 return _t('inspector.multiple_values');
85699               }
85700
85701               return field.placeholder();
85702             }).classed('mixed', function (d) {
85703               return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
85704             });
85705           };
85706
85707           cycleway.focus = function () {
85708             var node = wrap.selectAll('input').node();
85709             if (node) node.focus();
85710           };
85711
85712           return utilRebind(cycleway, dispatch$1, 'on');
85713         }
85714
85715         function uiFieldLanes(field, context) {
85716           var dispatch$1 = dispatch('change');
85717           var LANE_WIDTH = 40;
85718           var LANE_HEIGHT = 200;
85719           var _entityIDs = [];
85720
85721           function lanes(selection) {
85722             var lanesData = context.entity(_entityIDs[0]).lanes();
85723
85724             if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
85725               selection.call(lanes.off);
85726               return;
85727             }
85728
85729             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
85730             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85731             var surface = wrap.selectAll('.surface').data([0]);
85732             var d = utilGetDimensions(wrap);
85733             var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
85734             surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
85735             var lanesSelection = surface.selectAll('.lanes').data([0]);
85736             lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
85737             lanesSelection.attr('transform', function () {
85738               return 'translate(' + freeSpace / 2 + ', 0)';
85739             });
85740             var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
85741             lane.exit().remove();
85742             var enter = lane.enter().append('g').attr('class', 'lane');
85743             enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
85744             enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
85745             enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
85746             enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
85747             lane = lane.merge(enter);
85748             lane.attr('transform', function (d) {
85749               return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
85750             });
85751             lane.select('.forward').style('visibility', function (d) {
85752               return d.direction === 'forward' ? 'visible' : 'hidden';
85753             });
85754             lane.select('.bothways').style('visibility', function (d) {
85755               return d.direction === 'bothways' ? 'visible' : 'hidden';
85756             });
85757             lane.select('.backward').style('visibility', function (d) {
85758               return d.direction === 'backward' ? 'visible' : 'hidden';
85759             });
85760           }
85761
85762           lanes.entityIDs = function (val) {
85763             _entityIDs = val;
85764           };
85765
85766           lanes.tags = function () {};
85767
85768           lanes.focus = function () {};
85769
85770           lanes.off = function () {};
85771
85772           return utilRebind(lanes, dispatch$1, 'on');
85773         }
85774         uiFieldLanes.supportsMultiselection = false;
85775
85776         var _languagesArray = [];
85777         function uiFieldLocalized(field, context) {
85778           var dispatch$1 = dispatch('change', 'input');
85779           var wikipedia = services.wikipedia;
85780           var input = select(null);
85781           var localizedInputs = select(null);
85782
85783           var _countryCode;
85784
85785           var _tags; // A concern here in switching to async data means that _languagesArray will not
85786           // be available the first time through, so things like the fetchers and
85787           // the language() function will not work immediately.
85788
85789
85790           _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
85791             /* ignore */
85792           });
85793           var _territoryLanguages = {};
85794           _mainFileFetcher.get('territory_languages').then(function (d) {
85795             _territoryLanguages = d;
85796           })["catch"](function () {
85797             /* ignore */
85798           });
85799           var allSuggestions = _mainPresetIndex.collection.filter(function (p) {
85800             return p.suggestion === true;
85801           }); // reuse these combos
85802
85803           var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
85804           var brandCombo = uiCombobox(context, 'localized-brand').canAutocomplete(false).minItems(1);
85805
85806           var _selection = select(null);
85807
85808           var _multilingual = [];
85809
85810           var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
85811
85812           var _wikiTitles;
85813
85814           var _entityIDs = [];
85815
85816           function loadLanguagesArray(dataLanguages) {
85817             if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
85818
85819             var replacements = {
85820               sr: 'sr-Cyrl',
85821               // in OSM, `sr` implies Cyrillic
85822               'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
85823
85824             };
85825
85826             for (var code in dataLanguages) {
85827               if (replacements[code] === false) continue;
85828               var metaCode = code;
85829               if (replacements[code]) metaCode = replacements[code];
85830
85831               _languagesArray.push({
85832                 localName: _mainLocalizer.languageName(metaCode, {
85833                   localOnly: true
85834                 }),
85835                 nativeName: dataLanguages[metaCode].nativeName,
85836                 code: code,
85837                 label: _mainLocalizer.languageName(metaCode)
85838               });
85839             }
85840           }
85841
85842           function calcLocked() {
85843             // only lock the Name field
85844             var isLocked = field.id === 'name' && _entityIDs.length && // lock the field if any feature needs it
85845             _entityIDs.some(function (entityID) {
85846               var entity = context.graph().hasEntity(entityID);
85847               if (!entity) return false;
85848
85849               var original = context.graph().base().entities[_entityIDs[0]];
85850
85851               var hasOriginalName = original && entity.tags.name && entity.tags.name === original.tags.name; // if the name was already edited manually then allow further editing
85852
85853               if (!hasOriginalName) return false; // features linked to Wikidata are likely important and should be protected
85854
85855               if (entity.tags.wikidata) return true; // assume the name has already been confirmed if its source has been researched
85856
85857               if (entity.tags['name:etymology:wikidata']) return true;
85858               var preset = _mainPresetIndex.match(entity, context.graph());
85859               var isSuggestion = preset && preset.suggestion;
85860               var showsBrand = preset && preset.originalFields.filter(function (d) {
85861                 return d.id === 'brand';
85862               }).length; // protect standardized brand names
85863
85864               return isSuggestion && !showsBrand;
85865             });
85866
85867             field.locked(isLocked);
85868           } // update _multilingual, maintaining the existing order
85869
85870
85871           function calcMultilingual(tags) {
85872             var existingLangsOrdered = _multilingual.map(function (item) {
85873               return item.lang;
85874             });
85875
85876             var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
85877
85878             for (var k in tags) {
85879               var m = k.match(/^(.*):(.+)$/);
85880
85881               if (m && m[1] === field.key && m[2]) {
85882                 var item = {
85883                   lang: m[2],
85884                   value: tags[k]
85885                 };
85886
85887                 if (existingLangs.has(item.lang)) {
85888                   // update the value
85889                   _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
85890                   existingLangs["delete"](item.lang);
85891                 } else {
85892                   _multilingual.push(item);
85893                 }
85894               }
85895             }
85896
85897             _multilingual = _multilingual.filter(function (item) {
85898               return !item.lang || !existingLangs.has(item.lang);
85899             });
85900           }
85901
85902           function localized(selection) {
85903             _selection = selection;
85904             calcLocked();
85905             var isLocked = field.locked();
85906             var singularEntity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85907             var preset = singularEntity && _mainPresetIndex.match(singularEntity, context.graph());
85908             var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
85909
85910             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
85911             input = wrap.selectAll('.localized-main').data([0]); // enter/update
85912
85913             input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
85914
85915             if (preset && field.id === 'name') {
85916               var pTag = preset.id.split('/', 2);
85917               var pKey = pTag[0];
85918               var pValue = pTag[1];
85919
85920               if (!preset.suggestion) {
85921                 // Not a suggestion preset - Add a suggestions dropdown if it makes sense to.
85922                 // This code attempts to determine if the matched preset is the
85923                 // kind of preset that even can benefit from name suggestions..
85924                 // - true = shops, cafes, hotels, etc. (also generic and fallback presets)
85925                 // - false = churches, parks, hospitals, etc. (things not in the index)
85926                 var isFallback = preset.isFallback();
85927                 var goodSuggestions = allSuggestions.filter(function (s) {
85928                   if (isFallback) return true;
85929                   var sTag = s.id.split('/', 2);
85930                   var sKey = sTag[0];
85931                   var sValue = sTag[1];
85932                   return pKey === sKey && (!pValue || pValue === sValue);
85933                 }); // Show the suggestions.. If the user picks one, change the tags..
85934
85935                 if (allSuggestions.length && goodSuggestions.length) {
85936                   input.on('blur.localized', checkBrandOnBlur).call(brandCombo.fetcher(fetchBrandNames(preset, allSuggestions)).on('accept', acceptBrand).on('cancel', cancelBrand));
85937                 }
85938               }
85939             }
85940
85941             input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
85942             var translateButton = wrap.selectAll('.localized-add').data([0]);
85943             translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
85944             translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
85945
85946             if (_tags && !_multilingual.length) {
85947               calcMultilingual(_tags);
85948             }
85949
85950             localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
85951             localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
85952             localizedInputs.call(renderMultilingual);
85953             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.
85954             // (This can happen if the user actives the combo, arrows down, and then clicks off to blur)
85955             // So compare the current field value against the suggestions one last time.
85956
85957             function checkBrandOnBlur() {
85958               var latest = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85959               if (!latest) return; // deleting the entity blurred the field?
85960
85961               var preset = _mainPresetIndex.match(latest, context.graph());
85962               if (preset && preset.suggestion) return; // already accepted
85963
85964               var name = utilGetSetValue(input).trim();
85965               var matched = allSuggestions.filter(function (s) {
85966                 return name === s.name();
85967               });
85968
85969               if (matched.length === 1) {
85970                 acceptBrand({
85971                   suggestion: matched[0]
85972                 });
85973               } else {
85974                 cancelBrand();
85975               }
85976             }
85977
85978             function acceptBrand(d) {
85979               var entity = _entityIDs.length === 1 && context.hasEntity(_entityIDs[0]);
85980
85981               if (!d || !entity) {
85982                 cancelBrand();
85983                 return;
85984               }
85985
85986               var tags = entity.tags;
85987               var geometry = entity.geometry(context.graph());
85988               var removed = preset.unsetTags(tags, geometry);
85989
85990               for (var k in tags) {
85991                 tags[k] = removed[k]; // set removed tags to `undefined`
85992               }
85993
85994               tags = d.suggestion.setTags(tags, geometry);
85995               utilGetSetValue(input, tags.name);
85996               dispatch$1.call('change', this, tags);
85997             } // user hit escape
85998
85999
86000             function cancelBrand() {
86001               var name = utilGetSetValue(input);
86002               dispatch$1.call('change', this, {
86003                 name: name
86004               });
86005             }
86006
86007             function fetchBrandNames(preset, suggestions) {
86008               var pTag = preset.id.split('/', 2);
86009               var pKey = pTag[0];
86010               var pValue = pTag[1];
86011               return function (value, callback) {
86012                 var results = [];
86013
86014                 if (value && value.length > 2) {
86015                   for (var i = 0; i < suggestions.length; i++) {
86016                     var s = suggestions[i]; // don't suggest brands from incompatible countries
86017
86018                     if (_countryCode && s.countryCodes && s.countryCodes.indexOf(_countryCode) === -1) continue;
86019                     var sTag = s.id.split('/', 2);
86020                     var sKey = sTag[0];
86021                     var sValue = sTag[1];
86022                     var subtitle = s.subtitle();
86023                     var name = s.name();
86024                     if (subtitle) name += ' – ' + subtitle;
86025                     var dist = utilEditDistance(value, name.substring(0, value.length));
86026                     var matchesPreset = pKey === sKey && (!pValue || pValue === sValue);
86027
86028                     if (dist < 1 || matchesPreset && dist < 3) {
86029                       var obj = {
86030                         value: s.name(),
86031                         title: name,
86032                         display: s.nameLabel() + (subtitle ? ' – ' + s.subtitleLabel() : ''),
86033                         suggestion: s,
86034                         dist: dist + (matchesPreset ? 0 : 1) // penalize if not matched preset
86035
86036                       };
86037                       results.push(obj);
86038                     }
86039                   }
86040
86041                   results.sort(function (a, b) {
86042                     return a.dist - b.dist;
86043                   });
86044                 }
86045
86046                 results = results.slice(0, 10);
86047                 callback(results);
86048               };
86049             }
86050
86051             function addNew(d3_event) {
86052               d3_event.preventDefault();
86053               if (field.locked()) return;
86054               var defaultLang = _mainLocalizer.languageCode().toLowerCase();
86055
86056               var langExists = _multilingual.find(function (datum) {
86057                 return datum.lang === defaultLang;
86058               });
86059
86060               var isLangEn = defaultLang.indexOf('en') > -1;
86061
86062               if (isLangEn || langExists) {
86063                 defaultLang = '';
86064                 langExists = _multilingual.find(function (datum) {
86065                   return datum.lang === defaultLang;
86066                 });
86067               }
86068
86069               if (!langExists) {
86070                 // prepend the value so it appears at the top
86071                 _multilingual.unshift({
86072                   lang: defaultLang,
86073                   value: ''
86074                 });
86075
86076                 localizedInputs.call(renderMultilingual);
86077               }
86078             }
86079
86080             function change(onInput) {
86081               return function (d3_event) {
86082                 if (field.locked()) {
86083                   d3_event.preventDefault();
86084                   return;
86085                 }
86086
86087                 var val = utilGetSetValue(select(this));
86088                 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
86089
86090                 if (!val && Array.isArray(_tags[field.key])) return;
86091                 var t = {};
86092                 t[field.key] = val || undefined;
86093                 dispatch$1.call('change', this, t, onInput);
86094               };
86095             }
86096           }
86097
86098           function key(lang) {
86099             return field.key + ':' + lang;
86100           }
86101
86102           function changeLang(d3_event, d) {
86103             var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
86104
86105             var lang = utilGetSetValue(select(this)).toLowerCase();
86106
86107             var language = _languagesArray.find(function (d) {
86108               return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
86109             });
86110
86111             if (language) lang = language.code;
86112
86113             if (d.lang && d.lang !== lang) {
86114               tags[key(d.lang)] = undefined;
86115             }
86116
86117             var newKey = lang && context.cleanTagKey(key(lang));
86118             var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
86119
86120             if (newKey && value) {
86121               tags[newKey] = value;
86122             } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
86123               tags[newKey] = _wikiTitles[d.lang];
86124             }
86125
86126             d.lang = lang;
86127             dispatch$1.call('change', this, tags);
86128           }
86129
86130           function changeValue(d3_event, d) {
86131             if (!d.lang) return;
86132             var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
86133
86134             if (!value && Array.isArray(d.value)) return;
86135             var t = {};
86136             t[key(d.lang)] = value;
86137             d.value = value;
86138             dispatch$1.call('change', this, t);
86139           }
86140
86141           function fetchLanguages(value, cb) {
86142             var v = value.toLowerCase(); // show the user's language first
86143
86144             var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
86145
86146             if (_countryCode && _territoryLanguages[_countryCode]) {
86147               langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
86148             }
86149
86150             var langItems = [];
86151             langCodes.forEach(function (code) {
86152               var langItem = _languagesArray.find(function (item) {
86153                 return item.code === code;
86154               });
86155
86156               if (langItem) langItems.push(langItem);
86157             });
86158             langItems = utilArrayUniq(langItems.concat(_languagesArray));
86159             cb(langItems.filter(function (d) {
86160               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;
86161             }).map(function (d) {
86162               return {
86163                 value: d.label
86164               };
86165             }));
86166           }
86167
86168           function renderMultilingual(selection) {
86169             var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
86170               return d.lang;
86171             });
86172             entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
86173             var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
86174               var wrap = select(this);
86175               var domId = utilUniqueDomId(index);
86176               var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
86177               var text = label.append('span').attr('class', 'label-text');
86178               text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
86179               text.append('span').attr('class', 'label-textannotation');
86180               label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
86181                 if (field.locked()) return;
86182                 d3_event.preventDefault();
86183
86184                 if (!d.lang || !d.value) {
86185                   _multilingual.splice(index, 1);
86186
86187                   renderMultilingual(selection);
86188                 } else {
86189                   // remove from entity tags
86190                   var t = {};
86191                   t[key(d.lang)] = undefined;
86192                   dispatch$1.call('change', this, t);
86193                 }
86194               }).call(svgIcon('#iD-operation-delete'));
86195               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);
86196               wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
86197             });
86198             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 () {
86199               select(this).style('max-height', '').style('overflow', 'visible');
86200             });
86201             entries = entries.merge(entriesEnter);
86202             entries.order();
86203             entries.classed('present', function (d) {
86204               return d.lang && d.value;
86205             });
86206             utilGetSetValue(entries.select('.localized-lang'), function (d) {
86207               var langItem = _languagesArray.find(function (item) {
86208                 return item.code === d.lang;
86209               });
86210
86211               if (langItem) return langItem.label;
86212               return d.lang;
86213             });
86214             utilGetSetValue(entries.select('.localized-value'), function (d) {
86215               return typeof d.value === 'string' ? d.value : '';
86216             }).attr('title', function (d) {
86217               return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
86218             }).attr('placeholder', function (d) {
86219               return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
86220             }).classed('mixed', function (d) {
86221               return Array.isArray(d.value);
86222             });
86223           }
86224
86225           localized.tags = function (tags) {
86226             _tags = tags; // Fetch translations from wikipedia
86227
86228             if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
86229               _wikiTitles = {};
86230               var wm = tags.wikipedia.match(/([^:]+):(.+)/);
86231
86232               if (wm && wm[0] && wm[1]) {
86233                 wikipedia.translations(wm[1], wm[2], function (err, d) {
86234                   if (err || !d) return;
86235                   _wikiTitles = d;
86236                 });
86237               }
86238             }
86239
86240             var isMixed = Array.isArray(tags[field.key]);
86241             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);
86242             calcMultilingual(tags);
86243
86244             _selection.call(localized);
86245           };
86246
86247           localized.focus = function () {
86248             input.node().focus();
86249           };
86250
86251           localized.entityIDs = function (val) {
86252             if (!arguments.length) return _entityIDs;
86253             _entityIDs = val;
86254             _multilingual = [];
86255             loadCountryCode();
86256             return localized;
86257           };
86258
86259           function loadCountryCode() {
86260             var extent = combinedEntityExtent();
86261             var countryCode = extent && iso1A2Code(extent.center());
86262             _countryCode = countryCode && countryCode.toLowerCase();
86263           }
86264
86265           function combinedEntityExtent() {
86266             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
86267           }
86268
86269           return utilRebind(localized, dispatch$1, 'on');
86270         }
86271
86272         function uiFieldMaxspeed(field, context) {
86273           var dispatch$1 = dispatch('change');
86274           var unitInput = select(null);
86275           var input = select(null);
86276           var _entityIDs = [];
86277
86278           var _tags;
86279
86280           var _isImperial;
86281
86282           var speedCombo = uiCombobox(context, 'maxspeed');
86283           var unitCombo = uiCombobox(context, 'maxspeed-unit').data(['km/h', 'mph'].map(comboValues));
86284           var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
86285           var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
86286
86287           function maxspeed(selection) {
86288             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86289             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86290             input = wrap.selectAll('input.maxspeed-number').data([0]);
86291             input = input.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
86292             input.on('change', change).on('blur', change);
86293             var loc = combinedEntityExtent().center();
86294             _isImperial = roadSpeedUnit(loc) === 'mph';
86295             unitInput = wrap.selectAll('input.maxspeed-unit').data([0]);
86296             unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'maxspeed-unit').call(unitCombo).merge(unitInput);
86297             unitInput.on('blur', changeUnits).on('change', changeUnits);
86298
86299             function changeUnits() {
86300               _isImperial = utilGetSetValue(unitInput) === 'mph';
86301               utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
86302               setUnitSuggestions();
86303               change();
86304             }
86305           }
86306
86307           function setUnitSuggestions() {
86308             speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
86309             utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
86310           }
86311
86312           function comboValues(d) {
86313             return {
86314               value: d.toString(),
86315               title: d.toString()
86316             };
86317           }
86318
86319           function change() {
86320             var tag = {};
86321             var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
86322
86323             if (!value && Array.isArray(_tags[field.key])) return;
86324
86325             if (!value) {
86326               tag[field.key] = undefined;
86327             } else if (isNaN(value) || !_isImperial) {
86328               tag[field.key] = context.cleanTagValue(value);
86329             } else {
86330               tag[field.key] = context.cleanTagValue(value + ' mph');
86331             }
86332
86333             dispatch$1.call('change', this, tag);
86334           }
86335
86336           maxspeed.tags = function (tags) {
86337             _tags = tags;
86338             var value = tags[field.key];
86339             var isMixed = Array.isArray(value);
86340
86341             if (!isMixed) {
86342               if (value && value.indexOf('mph') >= 0) {
86343                 value = parseInt(value, 10).toString();
86344                 _isImperial = true;
86345               } else if (value) {
86346                 _isImperial = false;
86347               }
86348             }
86349
86350             setUnitSuggestions();
86351             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);
86352           };
86353
86354           maxspeed.focus = function () {
86355             input.node().focus();
86356           };
86357
86358           maxspeed.entityIDs = function (val) {
86359             _entityIDs = val;
86360           };
86361
86362           function combinedEntityExtent() {
86363             return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
86364           }
86365
86366           return utilRebind(maxspeed, dispatch$1, 'on');
86367         }
86368
86369         function uiFieldRadio(field, context) {
86370           var dispatch$1 = dispatch('change');
86371           var placeholder = select(null);
86372           var wrap = select(null);
86373           var labels = select(null);
86374           var radios = select(null);
86375           var radioData = (field.options || field.strings && field.strings.options && Object.keys(field.strings.options) || field.keys).slice(); // shallow copy
86376
86377           var typeField;
86378           var layerField;
86379           var _oldType = {};
86380           var _entityIDs = [];
86381
86382           function selectedKey() {
86383             var node = wrap.selectAll('.form-field-input-radio label.active input');
86384             return !node.empty() && node.datum();
86385           }
86386
86387           function radio(selection) {
86388             selection.classed('preset-radio', true);
86389             wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86390             var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
86391             enter.append('span').attr('class', 'placeholder');
86392             wrap = wrap.merge(enter);
86393             placeholder = wrap.selectAll('.placeholder');
86394             labels = wrap.selectAll('label').data(radioData);
86395             enter = labels.enter().append('label');
86396             enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
86397               return field.t('options.' + d, {
86398                 'default': d
86399               });
86400             }).attr('checked', false);
86401             enter.append('span').html(function (d) {
86402               return field.t.html('options.' + d, {
86403                 'default': d
86404               });
86405             });
86406             labels = labels.merge(enter);
86407             radios = labels.selectAll('input').on('change', changeRadio);
86408           }
86409
86410           function structureExtras(selection, tags) {
86411             var selected = selectedKey() || tags.layer !== undefined;
86412             var type = _mainPresetIndex.field(selected);
86413             var layer = _mainPresetIndex.field('layer');
86414             var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
86415             var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
86416             extrasWrap.exit().remove();
86417             extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
86418             var list = extrasWrap.selectAll('ul').data([0]);
86419             list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
86420
86421             if (type) {
86422               if (!typeField || typeField.id !== selected) {
86423                 typeField = uiField(context, type, _entityIDs, {
86424                   wrap: false
86425                 }).on('change', changeType);
86426               }
86427
86428               typeField.tags(tags);
86429             } else {
86430               typeField = null;
86431             }
86432
86433             var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
86434               return d.id;
86435             }); // Exit
86436
86437             typeItem.exit().remove(); // Enter
86438
86439             var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
86440             typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
86441             typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
86442
86443             typeItem = typeItem.merge(typeEnter);
86444
86445             if (typeField) {
86446               typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
86447             } // Layer
86448
86449
86450             if (layer && showLayer) {
86451               if (!layerField) {
86452                 layerField = uiField(context, layer, _entityIDs, {
86453                   wrap: false
86454                 }).on('change', changeLayer);
86455               }
86456
86457               layerField.tags(tags);
86458               field.keys = utilArrayUnion(field.keys, ['layer']);
86459             } else {
86460               layerField = null;
86461               field.keys = field.keys.filter(function (k) {
86462                 return k !== 'layer';
86463               });
86464             }
86465
86466             var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
86467
86468             layerItem.exit().remove(); // Enter
86469
86470             var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
86471             layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
86472             layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
86473
86474             layerItem = layerItem.merge(layerEnter);
86475
86476             if (layerField) {
86477               layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
86478             }
86479           }
86480
86481           function changeType(t, onInput) {
86482             var key = selectedKey();
86483             if (!key) return;
86484             var val = t[key];
86485
86486             if (val !== 'no') {
86487               _oldType[key] = val;
86488             }
86489
86490             if (field.type === 'structureRadio') {
86491               // remove layer if it should not be set
86492               if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
86493                 t.layer = undefined;
86494               } // add layer if it should be set
86495
86496
86497               if (t.layer === undefined) {
86498                 if (key === 'bridge' && val !== 'no') {
86499                   t.layer = '1';
86500                 }
86501
86502                 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
86503                   t.layer = '-1';
86504                 }
86505               }
86506             }
86507
86508             dispatch$1.call('change', this, t, onInput);
86509           }
86510
86511           function changeLayer(t, onInput) {
86512             if (t.layer === '0') {
86513               t.layer = undefined;
86514             }
86515
86516             dispatch$1.call('change', this, t, onInput);
86517           }
86518
86519           function changeRadio() {
86520             var t = {};
86521             var activeKey;
86522
86523             if (field.key) {
86524               t[field.key] = undefined;
86525             }
86526
86527             radios.each(function (d) {
86528               var active = select(this).property('checked');
86529               if (active) activeKey = d;
86530
86531               if (field.key) {
86532                 if (active) t[field.key] = d;
86533               } else {
86534                 var val = _oldType[activeKey] || 'yes';
86535                 t[d] = active ? val : undefined;
86536               }
86537             });
86538
86539             if (field.type === 'structureRadio') {
86540               if (activeKey === 'bridge') {
86541                 t.layer = '1';
86542               } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
86543                 t.layer = '-1';
86544               } else {
86545                 t.layer = undefined;
86546               }
86547             }
86548
86549             dispatch$1.call('change', this, t);
86550           }
86551
86552           radio.tags = function (tags) {
86553             radios.property('checked', function (d) {
86554               if (field.key) {
86555                 return tags[field.key] === d;
86556               }
86557
86558               return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
86559             });
86560
86561             function isMixed(d) {
86562               if (field.key) {
86563                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
86564               }
86565
86566               return Array.isArray(tags[d]);
86567             }
86568
86569             labels.classed('active', function (d) {
86570               if (field.key) {
86571                 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
86572               }
86573
86574               return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
86575             }).classed('mixed', isMixed).attr('title', function (d) {
86576               return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
86577             });
86578             var selection = radios.filter(function () {
86579               return this.checked;
86580             });
86581
86582             if (selection.empty()) {
86583               placeholder.html(_t.html('inspector.none'));
86584             } else {
86585               placeholder.html(selection.attr('value'));
86586               _oldType[selection.datum()] = tags[selection.datum()];
86587             }
86588
86589             if (field.type === 'structureRadio') {
86590               // For waterways without a tunnel tag, set 'culvert' as
86591               // the _oldType to default to if the user picks 'tunnel'
86592               if (!!tags.waterway && !_oldType.tunnel) {
86593                 _oldType.tunnel = 'culvert';
86594               }
86595
86596               wrap.call(structureExtras, tags);
86597             }
86598           };
86599
86600           radio.focus = function () {
86601             radios.node().focus();
86602           };
86603
86604           radio.entityIDs = function (val) {
86605             if (!arguments.length) return _entityIDs;
86606             _entityIDs = val;
86607             _oldType = {};
86608             return radio;
86609           };
86610
86611           radio.isAllowed = function () {
86612             return _entityIDs.length === 1;
86613           };
86614
86615           return utilRebind(radio, dispatch$1, 'on');
86616         }
86617
86618         function uiFieldRestrictions(field, context) {
86619           var dispatch$1 = dispatch('change');
86620           var breathe = behaviorBreathe();
86621           corePreferences('turn-restriction-via-way', null); // remove old key
86622
86623           var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
86624
86625           var storedDistance = corePreferences('turn-restriction-distance');
86626
86627           var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
86628
86629           var _maxDistance = storedDistance ? +storedDistance : 30;
86630
86631           var _initialized = false;
86632
86633           var _parent = select(null); // the entire field
86634
86635
86636           var _container = select(null); // just the map
86637
86638
86639           var _oldTurns;
86640
86641           var _graph;
86642
86643           var _vertexID;
86644
86645           var _intersection;
86646
86647           var _fromWayID;
86648
86649           var _lastXPos;
86650
86651           function restrictions(selection) {
86652             _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
86653
86654             if (_vertexID && (context.graph() !== _graph || !_intersection)) {
86655               _graph = context.graph();
86656               _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
86657             } // It's possible for there to be no actual intersection here.
86658             // for example, a vertex of two `highway=path`
86659             // In this case, hide the field.
86660
86661
86662             var isOK = _intersection && _intersection.vertices.length && // has vertices
86663             _intersection.vertices // has the vertex that the user selected
86664             .filter(function (vertex) {
86665               return vertex.id === _vertexID;
86666             }).length && _intersection.ways.length > 2 && // has more than 2 ways
86667             _intersection.ways // has more than 1 TO way
86668             .filter(function (way) {
86669               return way.__to;
86670             }).length > 1; // Also hide in the case where
86671
86672             select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
86673
86674             if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
86675               selection.call(restrictions.off);
86676               return;
86677             }
86678
86679             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
86680             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
86681             var container = wrap.selectAll('.restriction-container').data([0]); // enter
86682
86683             var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
86684             containerEnter.append('div').attr('class', 'restriction-help'); // update
86685
86686             _container = containerEnter.merge(container).call(renderViewer);
86687             var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
86688
86689             controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
86690           }
86691
86692           function renderControls(selection) {
86693             var distControl = selection.selectAll('.restriction-distance').data([0]);
86694             distControl.exit().remove();
86695             var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
86696             distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
86697             distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
86698             distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
86699
86700             selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
86701               var val = select(this).property('value');
86702               _maxDistance = +val;
86703               _intersection = null;
86704
86705               _container.selectAll('.layer-osm .layer-turns *').remove();
86706
86707               corePreferences('turn-restriction-distance', _maxDistance);
86708
86709               _parent.call(restrictions);
86710             });
86711             selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
86712             var viaControl = selection.selectAll('.restriction-via-way').data([0]);
86713             viaControl.exit().remove();
86714             var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
86715             viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
86716             viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
86717             viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
86718
86719             selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
86720               var val = select(this).property('value');
86721               _maxViaWay = +val;
86722
86723               _container.selectAll('.layer-osm .layer-turns *').remove();
86724
86725               corePreferences('turn-restriction-via-way0', _maxViaWay);
86726
86727               _parent.call(restrictions);
86728             });
86729             selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
86730           }
86731
86732           function renderViewer(selection) {
86733             if (!_intersection) return;
86734             var vgraph = _intersection.graph;
86735             var filter = utilFunctor(true);
86736             var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
86737             // Instead of asking the restriction-container for its dimensions,
86738             //  we can ask the .sidebar, which can have its dimensions cached.
86739             // width: calc as sidebar - padding
86740             // height: hardcoded (from `80_app.css`)
86741             // var d = utilGetDimensions(selection);
86742
86743             var sdims = utilGetDimensions(context.container().select('.sidebar'));
86744             var d = [sdims[0] - 50, 370];
86745             var c = geoVecScale(d, 0.5);
86746             var z = 22;
86747             projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
86748
86749             var extent = geoExtent();
86750
86751             for (var i = 0; i < _intersection.vertices.length; i++) {
86752               extent._extend(_intersection.vertices[i].extent());
86753             } // If this is a large intersection, adjust zoom to fit extent
86754
86755
86756             if (_intersection.vertices.length > 1) {
86757               var padding = 180; // in z22 pixels
86758
86759               var tl = projection([extent[0][0], extent[1][1]]);
86760               var br = projection([extent[1][0], extent[0][1]]);
86761               var hFactor = (br[0] - tl[0]) / (d[0] - padding);
86762               var vFactor = (br[1] - tl[1]) / (d[1] - padding);
86763               var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
86764               var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
86765               z = z - Math.max(hZoomDiff, vZoomDiff);
86766               projection.scale(geoZoomToScale(z));
86767             }
86768
86769             var padTop = 35; // reserve top space for hint text
86770
86771             var extentCenter = projection(extent.center());
86772             extentCenter[1] = extentCenter[1] - padTop;
86773             projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
86774             var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
86775             var drawVertices = svgVertices(projection, context);
86776             var drawLines = svgLines(projection, context);
86777             var drawTurns = svgTurns(projection, context);
86778             var firstTime = selection.selectAll('.surface').empty();
86779             selection.call(drawLayers);
86780             var surface = selection.selectAll('.surface').classed('tr', true);
86781
86782             if (firstTime) {
86783               _initialized = true;
86784               surface.call(breathe);
86785             } // This can happen if we've lowered the detail while a FROM way
86786             // is selected, and that way is no longer part of the intersection.
86787
86788
86789             if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
86790               _fromWayID = null;
86791               _oldTurns = null;
86792             }
86793
86794             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));
86795             surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
86796             surface.selectAll('.selected').classed('selected', false);
86797             surface.selectAll('.related').classed('related', false);
86798             var way;
86799
86800             if (_fromWayID) {
86801               way = vgraph.entity(_fromWayID);
86802               surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86803             }
86804
86805             document.addEventListener('resizeWindow', function () {
86806               utilSetDimensions(_container, null);
86807               redraw(1);
86808             }, false);
86809             updateHints(null);
86810
86811             function click(d3_event) {
86812               surface.call(breathe.off).call(breathe);
86813               var datum = d3_event.target.__data__;
86814               var entity = datum && datum.properties && datum.properties.entity;
86815
86816               if (entity) {
86817                 datum = entity;
86818               }
86819
86820               if (datum instanceof osmWay && (datum.__from || datum.__via)) {
86821                 _fromWayID = datum.id;
86822                 _oldTurns = null;
86823                 redraw();
86824               } else if (datum instanceof osmTurn) {
86825                 var actions, extraActions, turns, i;
86826                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86827
86828                 if (datum.restrictionID && !datum.direct) {
86829                   return;
86830                 } else if (datum.restrictionID && !datum.only) {
86831                   // NO -> ONLY
86832                   var seen = {};
86833                   var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
86834
86835                   datumOnly.only = true; // but change this property
86836
86837                   restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
86838                   // We will remember them in _oldTurns, and restore them if the user clicks again.
86839
86840                   turns = _intersection.turns(_fromWayID, 2);
86841                   extraActions = [];
86842                   _oldTurns = [];
86843
86844                   for (i = 0; i < turns.length; i++) {
86845                     var turn = turns[i];
86846                     if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
86847
86848                     if (turn.direct && turn.path[1] === datum.path[1]) {
86849                       seen[turns[i].restrictionID] = true;
86850                       turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
86851
86852                       _oldTurns.push(turn);
86853
86854                       extraActions.push(actionUnrestrictTurn(turn));
86855                     }
86856                   }
86857
86858                   actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
86859                 } else if (datum.restrictionID) {
86860                   // ONLY -> Allowed
86861                   // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
86862                   // This relies on the assumption that the intersection was already split up when we
86863                   // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
86864                   turns = _oldTurns || [];
86865                   extraActions = [];
86866
86867                   for (i = 0; i < turns.length; i++) {
86868                     if (turns[i].key !== datum.key) {
86869                       extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
86870                     }
86871                   }
86872
86873                   _oldTurns = null;
86874                   actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
86875                 } else {
86876                   // Allowed -> NO
86877                   actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
86878                 }
86879
86880                 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
86881                 // Refresh it and update the help..
86882
86883                 var s = surface.selectAll('.' + datum.key);
86884                 datum = s.empty() ? null : s.datum();
86885                 updateHints(datum);
86886               } else {
86887                 _fromWayID = null;
86888                 _oldTurns = null;
86889                 redraw();
86890               }
86891             }
86892
86893             function mouseover(d3_event) {
86894               var datum = d3_event.target.__data__;
86895               updateHints(datum);
86896             }
86897
86898             _lastXPos = _lastXPos || sdims[0];
86899
86900             function redraw(minChange) {
86901               var xPos = -1;
86902
86903               if (minChange) {
86904                 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
86905               }
86906
86907               if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
86908                 if (context.hasEntity(_vertexID)) {
86909                   _lastXPos = xPos;
86910
86911                   _container.call(renderViewer);
86912                 }
86913               }
86914             }
86915
86916             function highlightPathsFrom(wayID) {
86917               surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
86918               surface.selectAll('.' + wayID).classed('related', true);
86919
86920               if (wayID) {
86921                 var turns = _intersection.turns(wayID, _maxViaWay);
86922
86923                 for (var i = 0; i < turns.length; i++) {
86924                   var turn = turns[i];
86925                   var ids = [turn.to.way];
86926                   var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
86927
86928                   if (turn.only || turns.length === 1) {
86929                     if (turn.via.ways) {
86930                       ids = ids.concat(turn.via.ways);
86931                     }
86932                   } else if (turn.to.way === wayID) {
86933                     continue;
86934                   }
86935
86936                   surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
86937                 }
86938               }
86939             }
86940
86941             function updateHints(datum) {
86942               var help = _container.selectAll('.restriction-help').html('');
86943
86944               var placeholders = {};
86945               ['from', 'via', 'to'].forEach(function (k) {
86946                 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
86947               });
86948               var entity = datum && datum.properties && datum.properties.entity;
86949
86950               if (entity) {
86951                 datum = entity;
86952               }
86953
86954               if (_fromWayID) {
86955                 way = vgraph.entity(_fromWayID);
86956                 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
86957               } // Hovering a way
86958
86959
86960               if (datum instanceof osmWay && datum.__from) {
86961                 way = datum;
86962                 highlightPathsFrom(_fromWayID ? null : way.id);
86963                 surface.selectAll('.' + way.id).classed('related', true);
86964                 var clickSelect = !_fromWayID || _fromWayID !== way.id;
86965                 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
86966                 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
86967                   from: placeholders.from,
86968                   fromName: displayName(way.id, vgraph)
86969                 })); // Hovering a turn arrow
86970               } else if (datum instanceof osmTurn) {
86971                 var restrictionType = osmInferRestriction(vgraph, datum, projection);
86972                 var turnType = restrictionType.replace(/^(only|no)\_/, '');
86973                 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
86974                 var klass, turnText, nextText;
86975
86976                 if (datum.no) {
86977                   klass = 'restrict';
86978                   turnText = _t.html('restriction.help.turn.no_' + turnType, {
86979                     indirect: indirect
86980                   });
86981                   nextText = _t.html('restriction.help.turn.only_' + turnType, {
86982                     indirect: ''
86983                   });
86984                 } else if (datum.only) {
86985                   klass = 'only';
86986                   turnText = _t.html('restriction.help.turn.only_' + turnType, {
86987                     indirect: indirect
86988                   });
86989                   nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
86990                     indirect: ''
86991                   });
86992                 } else {
86993                   klass = 'allow';
86994                   turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
86995                     indirect: indirect
86996                   });
86997                   nextText = _t.html('restriction.help.turn.no_' + turnType, {
86998                     indirect: ''
86999                   });
87000                 }
87001
87002                 help.append('div') // "NO Right Turn (indirect)"
87003                 .attr('class', 'qualifier ' + klass).html(turnText);
87004                 help.append('div') // "FROM {fromName} TO {toName}"
87005                 .html(_t.html('restriction.help.from_name_to_name', {
87006                   from: placeholders.from,
87007                   fromName: displayName(datum.from.way, vgraph),
87008                   to: placeholders.to,
87009                   toName: displayName(datum.to.way, vgraph)
87010                 }));
87011
87012                 if (datum.via.ways && datum.via.ways.length) {
87013                   var names = [];
87014
87015                   for (var i = 0; i < datum.via.ways.length; i++) {
87016                     var prev = names[names.length - 1];
87017                     var curr = displayName(datum.via.ways[i], vgraph);
87018                     if (!prev || curr !== prev) // collapse identical names
87019                       names.push(curr);
87020                   }
87021
87022                   help.append('div') // "VIA {viaNames}"
87023                   .html(_t.html('restriction.help.via_names', {
87024                     via: placeholders.via,
87025                     viaNames: names.join(', ')
87026                   }));
87027                 }
87028
87029                 if (!indirect) {
87030                   help.append('div') // Click for "No Right Turn"
87031                   .html(_t.html('restriction.help.toggle', {
87032                     turn: nextText.trim()
87033                   }));
87034                 }
87035
87036                 highlightPathsFrom(null);
87037                 var alongIDs = datum.path.slice();
87038                 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
87039               } else {
87040                 highlightPathsFrom(null);
87041
87042                 if (_fromWayID) {
87043                   help.append('div') // "FROM {fromName}"
87044                   .html(_t.html('restriction.help.from_name', {
87045                     from: placeholders.from,
87046                     fromName: displayName(_fromWayID, vgraph)
87047                   }));
87048                 } else {
87049                   help.append('div') // "Click to select a FROM segment."
87050                   .html(_t.html('restriction.help.select_from', {
87051                     from: placeholders.from
87052                   }));
87053                 }
87054               }
87055             }
87056           }
87057
87058           function displayMaxDistance(maxDist) {
87059             var isImperial = !_mainLocalizer.usesMetric();
87060             var opts;
87061
87062             if (isImperial) {
87063               var distToFeet = {
87064                 // imprecise conversion for prettier display
87065                 20: 70,
87066                 25: 85,
87067                 30: 100,
87068                 35: 115,
87069                 40: 130,
87070                 45: 145,
87071                 50: 160
87072               }[maxDist];
87073               opts = {
87074                 distance: _t('units.feet', {
87075                   quantity: distToFeet
87076                 })
87077               };
87078             } else {
87079               opts = {
87080                 distance: _t('units.meters', {
87081                   quantity: maxDist
87082                 })
87083               };
87084             }
87085
87086             return _t.html('restriction.controls.distance_up_to', opts);
87087           }
87088
87089           function displayMaxVia(maxVia) {
87090             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');
87091           }
87092
87093           function displayName(entityID, graph) {
87094             var entity = graph.entity(entityID);
87095             var name = utilDisplayName(entity) || '';
87096             var matched = _mainPresetIndex.match(entity, graph);
87097             var type = matched && matched.name() || utilDisplayType(entity.id);
87098             return name || type;
87099           }
87100
87101           restrictions.entityIDs = function (val) {
87102             _intersection = null;
87103             _fromWayID = null;
87104             _oldTurns = null;
87105             _vertexID = val[0];
87106           };
87107
87108           restrictions.tags = function () {};
87109
87110           restrictions.focus = function () {};
87111
87112           restrictions.off = function (selection) {
87113             if (!_initialized) return;
87114             selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
87115             select(window).on('resize.restrictions', null);
87116           };
87117
87118           return utilRebind(restrictions, dispatch$1, 'on');
87119         }
87120         uiFieldRestrictions.supportsMultiselection = false;
87121
87122         function uiFieldTextarea(field, context) {
87123           var dispatch$1 = dispatch('change');
87124           var input = select(null);
87125
87126           var _tags;
87127
87128           function textarea(selection) {
87129             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87130             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
87131             input = wrap.selectAll('textarea').data([0]);
87132             input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
87133           }
87134
87135           function change(onInput) {
87136             return function () {
87137               var val = utilGetSetValue(input);
87138               if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
87139
87140               if (!val && Array.isArray(_tags[field.key])) return;
87141               var t = {};
87142               t[field.key] = val || undefined;
87143               dispatch$1.call('change', this, t, onInput);
87144             };
87145           }
87146
87147           textarea.tags = function (tags) {
87148             _tags = tags;
87149             var isMixed = Array.isArray(tags[field.key]);
87150             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);
87151           };
87152
87153           textarea.focus = function () {
87154             input.node().focus();
87155           };
87156
87157           return utilRebind(textarea, dispatch$1, 'on');
87158         }
87159
87160         function uiFieldWikidata(field, context) {
87161           var wikidata = services.wikidata;
87162           var dispatch$1 = dispatch('change');
87163
87164           var _selection = select(null);
87165
87166           var _searchInput = select(null);
87167
87168           var _qid = null;
87169           var _wikidataEntity = null;
87170           var _wikiURL = '';
87171           var _entityIDs = [];
87172
87173           var _wikipediaKey = field.keys && field.keys.find(function (key) {
87174             return key.includes('wikipedia');
87175           }),
87176               _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
87177
87178           var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
87179
87180           function wiki(selection) {
87181             _selection = selection;
87182             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87183             wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
87184             var list = wrap.selectAll('ul').data([0]);
87185             list = list.enter().append('ul').attr('class', 'rows').merge(list);
87186             var searchRow = list.selectAll('li.wikidata-search').data([0]);
87187             var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
87188             searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
87189               var node = select(this).node();
87190               node.setSelectionRange(0, node.value.length);
87191             }).on('blur', function () {
87192               setLabelForEntity();
87193             }).call(combobox.fetcher(fetchWikidataItems));
87194             combobox.on('accept', function (d) {
87195               if (d) {
87196                 _qid = d.id;
87197                 change();
87198               }
87199             }).on('cancel', function () {
87200               setLabelForEntity();
87201             });
87202             searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
87203               domain: 'wikidata.org'
87204             })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
87205               d3_event.preventDefault();
87206               if (_wikiURL) window.open(_wikiURL, '_blank');
87207             });
87208             searchRow = searchRow.merge(searchRowEnter);
87209             _searchInput = searchRow.select('input');
87210             var wikidataProperties = ['description', 'identifier'];
87211             var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
87212
87213             var enter = items.enter().append('li').attr('class', function (d) {
87214               return 'labeled-input preset-wikidata-' + d;
87215             });
87216             enter.append('span').attr('class', 'label').html(function (d) {
87217               return _t.html('wikidata.' + d);
87218             });
87219             enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
87220             enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
87221               d3_event.preventDefault();
87222               select(this.parentNode).select('input').node().select();
87223               document.execCommand('copy');
87224             });
87225           }
87226
87227           function fetchWikidataItems(q, callback) {
87228             if (!q && _hintKey) {
87229               // other tags may be good search terms
87230               for (var i in _entityIDs) {
87231                 var entity = context.hasEntity(_entityIDs[i]);
87232
87233                 if (entity.tags[_hintKey]) {
87234                   q = entity.tags[_hintKey];
87235                   break;
87236                 }
87237               }
87238             }
87239
87240             wikidata.itemsForSearchQuery(q, function (err, data) {
87241               if (err) return;
87242
87243               for (var i in data) {
87244                 data[i].value = data[i].label + ' (' + data[i].id + ')';
87245                 data[i].title = data[i].description;
87246               }
87247
87248               if (callback) callback(data);
87249             });
87250           }
87251
87252           function change() {
87253             var syncTags = {};
87254             syncTags[field.key] = _qid;
87255             dispatch$1.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
87256
87257             var initGraph = context.graph();
87258             var initEntityIDs = _entityIDs;
87259             wikidata.entityByQID(_qid, function (err, entity) {
87260               if (err) return; // If graph has changed, we can't apply this update.
87261
87262               if (context.graph() !== initGraph) return;
87263               if (!entity.sitelinks) return;
87264               var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
87265
87266               ['labels', 'descriptions'].forEach(function (key) {
87267                 if (!entity[key]) return;
87268                 var valueLangs = Object.keys(entity[key]);
87269                 if (valueLangs.length === 0) return;
87270                 var valueLang = valueLangs[0];
87271
87272                 if (langs.indexOf(valueLang) === -1) {
87273                   langs.push(valueLang);
87274                 }
87275               });
87276               var newWikipediaValue;
87277
87278               if (_wikipediaKey) {
87279                 var foundPreferred;
87280
87281                 for (var i in langs) {
87282                   var lang = langs[i];
87283                   var siteID = lang.replace('-', '_') + 'wiki';
87284
87285                   if (entity.sitelinks[siteID]) {
87286                     foundPreferred = true;
87287                     newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
87288
87289                     break;
87290                   }
87291                 }
87292
87293                 if (!foundPreferred) {
87294                   // No wikipedia sites available in the user's language or the fallback languages,
87295                   // default to any wikipedia sitelink
87296                   var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
87297                     return site.endsWith('wiki');
87298                   });
87299
87300                   if (wikiSiteKeys.length === 0) {
87301                     // if no wikipedia pages are linked to this wikidata entity, delete that tag
87302                     newWikipediaValue = null;
87303                   } else {
87304                     var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
87305                     var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
87306                     newWikipediaValue = wikiLang + ':' + wikiTitle;
87307                   }
87308                 }
87309               }
87310
87311               if (newWikipediaValue) {
87312                 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
87313               }
87314
87315               if (typeof newWikipediaValue === 'undefined') return;
87316               var actions = initEntityIDs.map(function (entityID) {
87317                 var entity = context.hasEntity(entityID);
87318                 if (!entity) return null;
87319                 var currTags = Object.assign({}, entity.tags); // shallow copy
87320
87321                 if (newWikipediaValue === null) {
87322                   if (!currTags[_wikipediaKey]) return null;
87323                   delete currTags[_wikipediaKey];
87324                 } else {
87325                   currTags[_wikipediaKey] = newWikipediaValue;
87326                 }
87327
87328                 return actionChangeTags(entityID, currTags);
87329               }).filter(Boolean);
87330               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
87331
87332               context.overwrite(function actionUpdateWikipediaTags(graph) {
87333                 actions.forEach(function (action) {
87334                   graph = action(graph);
87335                 });
87336                 return graph;
87337               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
87338               // changeTags() is not intended to be called asynchronously
87339             });
87340           }
87341
87342           function setLabelForEntity() {
87343             var label = '';
87344
87345             if (_wikidataEntity) {
87346               label = entityPropertyForDisplay(_wikidataEntity, 'labels');
87347
87348               if (label.length === 0) {
87349                 label = _wikidataEntity.id.toString();
87350               }
87351             }
87352
87353             utilGetSetValue(_searchInput, label);
87354           }
87355
87356           wiki.tags = function (tags) {
87357             var isMixed = Array.isArray(tags[field.key]);
87358
87359             _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
87360
87361             _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
87362
87363             if (!/^Q[0-9]*$/.test(_qid)) {
87364               // not a proper QID
87365               unrecognized();
87366               return;
87367             } // QID value in correct format
87368
87369
87370             _wikiURL = 'https://wikidata.org/wiki/' + _qid;
87371             wikidata.entityByQID(_qid, function (err, entity) {
87372               if (err) {
87373                 unrecognized();
87374                 return;
87375               }
87376
87377               _wikidataEntity = entity;
87378               setLabelForEntity();
87379               var description = entityPropertyForDisplay(entity, 'descriptions');
87380
87381               _selection.select('button.wiki-link').classed('disabled', false);
87382
87383               _selection.select('.preset-wikidata-description').style('display', function () {
87384                 return description.length > 0 ? 'flex' : 'none';
87385               }).select('input').attr('value', description);
87386
87387               _selection.select('.preset-wikidata-identifier').style('display', function () {
87388                 return entity.id ? 'flex' : 'none';
87389               }).select('input').attr('value', entity.id);
87390             }); // not a proper QID
87391
87392             function unrecognized() {
87393               _wikidataEntity = null;
87394               setLabelForEntity();
87395
87396               _selection.select('.preset-wikidata-description').style('display', 'none');
87397
87398               _selection.select('.preset-wikidata-identifier').style('display', 'none');
87399
87400               _selection.select('button.wiki-link').classed('disabled', true);
87401
87402               if (_qid && _qid !== '') {
87403                 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
87404               } else {
87405                 _wikiURL = '';
87406               }
87407             }
87408           };
87409
87410           function entityPropertyForDisplay(wikidataEntity, propKey) {
87411             if (!wikidataEntity[propKey]) return '';
87412             var propObj = wikidataEntity[propKey];
87413             var langKeys = Object.keys(propObj);
87414             if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
87415
87416             var langs = wikidata.languagesToQuery();
87417
87418             for (var i in langs) {
87419               var lang = langs[i];
87420               var valueObj = propObj[lang];
87421               if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
87422             } // default to any available value
87423
87424
87425             return propObj[langKeys[0]].value;
87426           }
87427
87428           wiki.entityIDs = function (val) {
87429             if (!arguments.length) return _entityIDs;
87430             _entityIDs = val;
87431             return wiki;
87432           };
87433
87434           wiki.focus = function () {
87435             _searchInput.node().focus();
87436           };
87437
87438           return utilRebind(wiki, dispatch$1, 'on');
87439         }
87440
87441         function uiFieldWikipedia(field, context) {
87442           var _arguments = arguments;
87443           var dispatch$1 = dispatch('change');
87444           var wikipedia = services.wikipedia;
87445           var wikidata = services.wikidata;
87446
87447           var _langInput = select(null);
87448
87449           var _titleInput = select(null);
87450
87451           var _wikiURL = '';
87452
87453           var _entityIDs;
87454
87455           var _tags;
87456
87457           var _dataWikipedia = [];
87458           _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
87459             _dataWikipedia = d;
87460             if (_tags) updateForTags(_tags);
87461           })["catch"](function () {
87462             /* ignore */
87463           });
87464           var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
87465             var v = value.toLowerCase();
87466             callback(_dataWikipedia.filter(function (d) {
87467               return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
87468             }).map(function (d) {
87469               return {
87470                 value: d[1]
87471               };
87472             }));
87473           });
87474           var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
87475             if (!value) {
87476               value = '';
87477
87478               for (var i in _entityIDs) {
87479                 var entity = context.hasEntity(_entityIDs[i]);
87480
87481                 if (entity.tags.name) {
87482                   value = entity.tags.name;
87483                   break;
87484                 }
87485               }
87486             }
87487
87488             var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
87489             searchfn(language()[2], value, function (query, data) {
87490               callback(data.map(function (d) {
87491                 return {
87492                   value: d
87493                 };
87494               }));
87495             });
87496           });
87497
87498           function wiki(selection) {
87499             var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
87500             wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
87501             var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
87502             langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
87503             _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
87504             _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);
87505
87506             _langInput.on('blur', changeLang).on('change', changeLang);
87507
87508             var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
87509             titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
87510             _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
87511             _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
87512
87513             _titleInput.on('blur', function () {
87514               change(true);
87515             }).on('change', function () {
87516               change(false);
87517             });
87518
87519             var link = titleContainer.selectAll('.wiki-link').data([0]);
87520             link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
87521               domain: 'wikipedia.org'
87522             })).call(svgIcon('#iD-icon-out-link')).merge(link);
87523             link.on('click', function (d3_event) {
87524               d3_event.preventDefault();
87525               if (_wikiURL) window.open(_wikiURL, '_blank');
87526             });
87527           }
87528
87529           function defaultLanguageInfo(skipEnglishFallback) {
87530             var langCode = _mainLocalizer.languageCode().toLowerCase();
87531
87532             for (var i in _dataWikipedia) {
87533               var d = _dataWikipedia[i]; // default to the language of iD's current locale
87534
87535               if (d[2] === langCode) return d;
87536             } // fallback to English
87537
87538
87539             return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
87540           }
87541
87542           function language(skipEnglishFallback) {
87543             var value = utilGetSetValue(_langInput).toLowerCase();
87544
87545             for (var i in _dataWikipedia) {
87546               var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
87547
87548               if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
87549             } // fallback to English
87550
87551
87552             return defaultLanguageInfo(skipEnglishFallback);
87553           }
87554
87555           function changeLang() {
87556             utilGetSetValue(_langInput, language()[1]);
87557             change(true);
87558           }
87559
87560           function change(skipWikidata) {
87561             var value = utilGetSetValue(_titleInput);
87562             var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
87563
87564             var langInfo = m && _dataWikipedia.find(function (d) {
87565               return m[1] === d[2];
87566             });
87567
87568             var syncTags = {};
87569
87570             if (langInfo) {
87571               var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
87572
87573               value = decodeURIComponent(m[2]).replace(/_/g, ' ');
87574
87575               if (m[3]) {
87576                 var anchor; // try {
87577                 // leave this out for now - #6232
87578                 // Best-effort `anchordecode:` implementation
87579                 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
87580                 // } catch (e) {
87581
87582                 anchor = decodeURIComponent(m[3]); // }
87583
87584                 value += '#' + anchor.replace(/_/g, ' ');
87585               }
87586
87587               value = value.slice(0, 1).toUpperCase() + value.slice(1);
87588               utilGetSetValue(_langInput, nativeLangName);
87589               utilGetSetValue(_titleInput, value);
87590             }
87591
87592             if (value) {
87593               syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
87594             } else {
87595               syncTags.wikipedia = undefined;
87596             }
87597
87598             dispatch$1.call('change', this, syncTags);
87599             if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
87600
87601             var initGraph = context.graph();
87602             var initEntityIDs = _entityIDs;
87603             wikidata.itemsByTitle(language()[2], value, function (err, data) {
87604               if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
87605
87606               if (context.graph() !== initGraph) return;
87607               var qids = Object.keys(data);
87608               var value = qids && qids.find(function (id) {
87609                 return id.match(/^Q\d+$/);
87610               });
87611               var actions = initEntityIDs.map(function (entityID) {
87612                 var entity = context.entity(entityID).tags;
87613                 var currTags = Object.assign({}, entity); // shallow copy
87614
87615                 if (currTags.wikidata !== value) {
87616                   currTags.wikidata = value;
87617                   return actionChangeTags(entityID, currTags);
87618                 }
87619
87620                 return null;
87621               }).filter(Boolean);
87622               if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
87623
87624               context.overwrite(function actionUpdateWikidataTags(graph) {
87625                 actions.forEach(function (action) {
87626                   graph = action(graph);
87627                 });
87628                 return graph;
87629               }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
87630               // changeTags() is not intended to be called asynchronously
87631             });
87632           }
87633
87634           wiki.tags = function (tags) {
87635             _tags = tags;
87636             updateForTags(tags);
87637           };
87638
87639           function updateForTags(tags) {
87640             var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
87641             // optional suffix of `#anchor`
87642
87643             var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
87644             var tagLang = m && m[1];
87645             var tagArticleTitle = m && m[2];
87646             var anchor = m && m[3];
87647
87648             var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
87649               return tagLang === d[2];
87650             }); // value in correct format
87651
87652
87653             if (tagLangInfo) {
87654               var nativeLangName = tagLangInfo[1];
87655               utilGetSetValue(_langInput, nativeLangName);
87656               utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
87657
87658               if (anchor) {
87659                 try {
87660                   // Best-effort `anchorencode:` implementation
87661                   anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
87662                 } catch (e) {
87663                   anchor = anchor.replace(/ /g, '_');
87664                 }
87665               }
87666
87667               _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
87668             } else {
87669               utilGetSetValue(_titleInput, value);
87670
87671               if (value && value !== '') {
87672                 utilGetSetValue(_langInput, '');
87673                 var defaultLangInfo = defaultLanguageInfo();
87674                 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
87675               } else {
87676                 var shownOrDefaultLangInfo = language(true
87677                 /* skipEnglishFallback */
87678                 );
87679                 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
87680                 _wikiURL = '';
87681               }
87682             }
87683           }
87684
87685           wiki.entityIDs = function (val) {
87686             if (!_arguments.length) return _entityIDs;
87687             _entityIDs = val;
87688             return wiki;
87689           };
87690
87691           wiki.focus = function () {
87692             _titleInput.node().focus();
87693           };
87694
87695           return utilRebind(wiki, dispatch$1, 'on');
87696         }
87697         uiFieldWikipedia.supportsMultiselection = false;
87698
87699         var uiFields = {
87700           access: uiFieldAccess,
87701           address: uiFieldAddress,
87702           check: uiFieldCheck,
87703           combo: uiFieldCombo,
87704           cycleway: uiFieldCycleway,
87705           defaultCheck: uiFieldCheck,
87706           email: uiFieldText,
87707           identifier: uiFieldText,
87708           lanes: uiFieldLanes,
87709           localized: uiFieldLocalized,
87710           maxspeed: uiFieldMaxspeed,
87711           manyCombo: uiFieldCombo,
87712           multiCombo: uiFieldCombo,
87713           networkCombo: uiFieldCombo,
87714           number: uiFieldText,
87715           onewayCheck: uiFieldCheck,
87716           radio: uiFieldRadio,
87717           restrictions: uiFieldRestrictions,
87718           semiCombo: uiFieldCombo,
87719           structureRadio: uiFieldRadio,
87720           tel: uiFieldText,
87721           text: uiFieldText,
87722           textarea: uiFieldTextarea,
87723           typeCombo: uiFieldCombo,
87724           url: uiFieldText,
87725           wikidata: uiFieldWikidata,
87726           wikipedia: uiFieldWikipedia
87727         };
87728
87729         function uiField(context, presetField, entityIDs, options) {
87730           options = Object.assign({
87731             show: true,
87732             wrap: true,
87733             remove: true,
87734             revert: true,
87735             info: true
87736           }, options);
87737           var dispatch$1 = dispatch('change', 'revert');
87738           var field = Object.assign({}, presetField); // shallow copy
87739
87740           field.domId = utilUniqueDomId('form-field-' + field.safeid);
87741           var _show = options.show;
87742           var _state = '';
87743           var _tags = {};
87744           var _locked = false;
87745
87746           var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
87747             label: field.label
87748           })).placement('bottom');
87749
87750           field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
87751
87752           if (_show && !field.impl) {
87753             createField();
87754           } // Creates the field.. This is done lazily,
87755           // once we know that the field will be shown.
87756
87757
87758           function createField() {
87759             field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
87760               dispatch$1.call('change', field, t, onInput);
87761             });
87762
87763             if (entityIDs) {
87764               field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
87765
87766               if (field.impl.entityIDs) {
87767                 field.impl.entityIDs(entityIDs);
87768               }
87769             }
87770           }
87771
87772           function isModified() {
87773             if (!entityIDs || !entityIDs.length) return false;
87774             return entityIDs.some(function (entityID) {
87775               var original = context.graph().base().entities[entityID];
87776               var latest = context.graph().entity(entityID);
87777               return field.keys.some(function (key) {
87778                 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
87779               });
87780             });
87781           }
87782
87783           function tagsContainFieldKey() {
87784             return field.keys.some(function (key) {
87785               if (field.type === 'multiCombo') {
87786                 for (var tagKey in _tags) {
87787                   if (tagKey.indexOf(key) === 0) {
87788                     return true;
87789                   }
87790                 }
87791
87792                 return false;
87793               }
87794
87795               return _tags[key] !== undefined;
87796             });
87797           }
87798
87799           function revert(d3_event, d) {
87800             d3_event.stopPropagation();
87801             d3_event.preventDefault();
87802             if (!entityIDs || _locked) return;
87803             dispatch$1.call('revert', d, d.keys);
87804           }
87805
87806           function remove(d3_event, d) {
87807             d3_event.stopPropagation();
87808             d3_event.preventDefault();
87809             if (_locked) return;
87810             var t = {};
87811             d.keys.forEach(function (key) {
87812               t[key] = undefined;
87813             });
87814             dispatch$1.call('change', d, t);
87815           }
87816
87817           field.render = function (selection) {
87818             var container = selection.selectAll('.form-field').data([field]); // Enter
87819
87820             var enter = container.enter().append('div').attr('class', function (d) {
87821               return 'form-field form-field-' + d.safeid;
87822             }).classed('nowrap', !options.wrap);
87823
87824             if (options.wrap) {
87825               var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
87826                 return d.domId;
87827               });
87828               var textEnter = labelEnter.append('span').attr('class', 'label-text');
87829               textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
87830                 return d.label();
87831               });
87832               textEnter.append('span').attr('class', 'label-textannotation');
87833
87834               if (options.remove) {
87835                 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
87836               }
87837
87838               if (options.revert) {
87839                 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
87840               }
87841             } // Update
87842
87843
87844             container = container.merge(enter);
87845             container.select('.field-label > .remove-icon') // propagate bound data
87846             .on('click', remove);
87847             container.select('.field-label > .modified-icon') // propagate bound data
87848             .on('click', revert);
87849             container.each(function (d) {
87850               var selection = select(this);
87851
87852               if (!d.impl) {
87853                 createField();
87854               }
87855
87856               var reference, help; // instantiate field help
87857
87858               if (options.wrap && field.type === 'restrictions') {
87859                 help = uiFieldHelp(context, 'restrictions');
87860               } // instantiate tag reference
87861
87862
87863               if (options.wrap && options.info) {
87864                 var referenceKey = d.key || '';
87865
87866                 if (d.type === 'multiCombo') {
87867                   // lookup key without the trailing ':'
87868                   referenceKey = referenceKey.replace(/:$/, '');
87869                 }
87870
87871                 reference = uiTagReference(d.reference || {
87872                   key: referenceKey
87873                 });
87874
87875                 if (_state === 'hover') {
87876                   reference.showing(false);
87877                 }
87878               }
87879
87880               selection.call(d.impl); // add field help components
87881
87882               if (help) {
87883                 selection.call(help.body).select('.field-label').call(help.button);
87884               } // add tag reference components
87885
87886
87887               if (reference) {
87888                 selection.call(reference.body).select('.field-label').call(reference.button);
87889               }
87890
87891               d.impl.tags(_tags);
87892             });
87893             container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
87894
87895             var annotation = container.selectAll('.field-label .label-textannotation');
87896             var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
87897             icon.exit().remove();
87898             icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
87899             container.call(_locked ? _lockedTip : _lockedTip.destroy);
87900           };
87901
87902           field.state = function (val) {
87903             if (!arguments.length) return _state;
87904             _state = val;
87905             return field;
87906           };
87907
87908           field.tags = function (val) {
87909             if (!arguments.length) return _tags;
87910             _tags = val;
87911
87912             if (tagsContainFieldKey() && !_show) {
87913               // always show a field if it has a value to display
87914               _show = true;
87915
87916               if (!field.impl) {
87917                 createField();
87918               }
87919             }
87920
87921             return field;
87922           };
87923
87924           field.locked = function (val) {
87925             if (!arguments.length) return _locked;
87926             _locked = val;
87927             return field;
87928           };
87929
87930           field.show = function () {
87931             _show = true;
87932
87933             if (!field.impl) {
87934               createField();
87935             }
87936
87937             if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
87938               var t = {};
87939               t[field.key] = field["default"];
87940               dispatch$1.call('change', this, t);
87941             }
87942           }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
87943
87944
87945           field.isShown = function () {
87946             return _show;
87947           }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
87948           // A non-allowed field is hidden from the user altogether
87949
87950
87951           field.isAllowed = function () {
87952             if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
87953             if (field.geometry && !entityIDs.every(function (entityID) {
87954               return field.matchGeometry(context.graph().geometry(entityID));
87955             })) return false;
87956
87957             if (field.countryCodes || field.notCountryCodes) {
87958               var extent = combinedEntityExtent();
87959               if (!extent) return true;
87960               var center = extent.center();
87961               var countryCode = iso1A2Code(center);
87962               if (!countryCode) return false;
87963               countryCode = countryCode.toLowerCase();
87964
87965               if (field.countryCodes && field.countryCodes.indexOf(countryCode) === -1) {
87966                 return false;
87967               }
87968
87969               if (field.notCountryCodes && field.notCountryCodes.indexOf(countryCode) !== -1) {
87970                 return false;
87971               }
87972             }
87973
87974             var prerequisiteTag = field.prerequisiteTag;
87975
87976             if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
87977             prerequisiteTag) {
87978               if (!entityIDs.every(function (entityID) {
87979                 var entity = context.graph().entity(entityID);
87980
87981                 if (prerequisiteTag.key) {
87982                   var value = entity.tags[prerequisiteTag.key];
87983                   if (!value) return false;
87984
87985                   if (prerequisiteTag.valueNot) {
87986                     return prerequisiteTag.valueNot !== value;
87987                   }
87988
87989                   if (prerequisiteTag.value) {
87990                     return prerequisiteTag.value === value;
87991                   }
87992                 } else if (prerequisiteTag.keyNot) {
87993                   if (entity.tags[prerequisiteTag.keyNot]) return false;
87994                 }
87995
87996                 return true;
87997               })) return false;
87998             }
87999
88000             return true;
88001           };
88002
88003           field.focus = function () {
88004             if (field.impl) {
88005               field.impl.focus();
88006             }
88007           };
88008
88009           function combinedEntityExtent() {
88010             return entityIDs && entityIDs.length && entityIDs.reduce(function (extent, entityID) {
88011               var entity = context.graph().entity(entityID);
88012               return extent.extend(entity.extent(context.graph()));
88013             }, geoExtent());
88014           }
88015
88016           return utilRebind(field, dispatch$1, 'on');
88017         }
88018
88019         function uiFormFields(context) {
88020           var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
88021           var _fieldsArr = [];
88022           var _lastPlaceholder = '';
88023           var _state = '';
88024           var _klass = '';
88025
88026           function formFields(selection) {
88027             var allowedFields = _fieldsArr.filter(function (field) {
88028               return field.isAllowed();
88029             });
88030
88031             var shown = allowedFields.filter(function (field) {
88032               return field.isShown();
88033             });
88034             var notShown = allowedFields.filter(function (field) {
88035               return !field.isShown();
88036             });
88037             var container = selection.selectAll('.form-fields-container').data([0]);
88038             container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
88039             var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
88040               return d.id + (d.entityIDs ? d.entityIDs.join() : '');
88041             });
88042             fields.exit().remove(); // Enter
88043
88044             var enter = fields.enter().append('div').attr('class', function (d) {
88045               return 'wrap-form-field wrap-form-field-' + d.safeid;
88046             }); // Update
88047
88048             fields = fields.merge(enter);
88049             fields.order().each(function (d) {
88050               select(this).call(d.render);
88051             });
88052             var titles = [];
88053             var moreFields = notShown.map(function (field) {
88054               var title = field.title();
88055               titles.push(title);
88056               var terms = field.terms();
88057               if (field.key) terms.push(field.key);
88058               if (field.keys) terms = terms.concat(field.keys);
88059               return {
88060                 display: field.label(),
88061                 value: title,
88062                 title: title,
88063                 field: field,
88064                 terms: terms
88065               };
88066             });
88067             var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
88068             var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
88069             more.exit().remove();
88070             var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
88071             moreEnter.append('span').html(_t.html('inspector.add_fields'));
88072             more = moreEnter.merge(more);
88073             var input = more.selectAll('.value').data([0]);
88074             input.exit().remove();
88075             input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
88076             input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
88077               if (!d) return; // user entered something that was not matched
88078
88079               var field = d.field;
88080               field.show();
88081               selection.call(formFields); // rerender
88082
88083               field.focus();
88084             })); // avoid updating placeholder excessively (triggers style recalc)
88085
88086             if (_lastPlaceholder !== placeholder) {
88087               input.attr('placeholder', placeholder);
88088               _lastPlaceholder = placeholder;
88089             }
88090           }
88091
88092           formFields.fieldsArr = function (val) {
88093             if (!arguments.length) return _fieldsArr;
88094             _fieldsArr = val || [];
88095             return formFields;
88096           };
88097
88098           formFields.state = function (val) {
88099             if (!arguments.length) return _state;
88100             _state = val;
88101             return formFields;
88102           };
88103
88104           formFields.klass = function (val) {
88105             if (!arguments.length) return _klass;
88106             _klass = val;
88107             return formFields;
88108           };
88109
88110           return formFields;
88111         }
88112
88113         function uiSectionPresetFields(context) {
88114           var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
88115           var dispatch$1 = dispatch('change', 'revert');
88116           var formFields = uiFormFields(context);
88117
88118           var _state;
88119
88120           var _fieldsArr;
88121
88122           var _presets = [];
88123
88124           var _tags;
88125
88126           var _entityIDs;
88127
88128           function renderDisclosureContent(selection) {
88129             if (!_fieldsArr) {
88130               var graph = context.graph();
88131               var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
88132                 geoms[graph.entity(entityID).geometry(graph)] = true;
88133                 return geoms;
88134               }, {}));
88135               var presetsManager = _mainPresetIndex;
88136               var allFields = [];
88137               var allMoreFields = [];
88138               var sharedTotalFields;
88139
88140               _presets.forEach(function (preset) {
88141                 var fields = preset.fields();
88142                 var moreFields = preset.moreFields();
88143                 allFields = utilArrayUnion(allFields, fields);
88144                 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
88145
88146                 if (!sharedTotalFields) {
88147                   sharedTotalFields = utilArrayUnion(fields, moreFields);
88148                 } else {
88149                   sharedTotalFields = sharedTotalFields.filter(function (field) {
88150                     return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
88151                   });
88152                 }
88153               });
88154
88155               var sharedFields = allFields.filter(function (field) {
88156                 return sharedTotalFields.indexOf(field) !== -1;
88157               });
88158               var sharedMoreFields = allMoreFields.filter(function (field) {
88159                 return sharedTotalFields.indexOf(field) !== -1;
88160               });
88161               _fieldsArr = [];
88162               sharedFields.forEach(function (field) {
88163                 if (field.matchAllGeometry(geometries)) {
88164                   _fieldsArr.push(uiField(context, field, _entityIDs));
88165                 }
88166               });
88167               var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
88168
88169               if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
88170                 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
88171               }
88172
88173               var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
88174               additionalFields.sort(function (field1, field2) {
88175                 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
88176               });
88177               additionalFields.forEach(function (field) {
88178                 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
88179                   _fieldsArr.push(uiField(context, field, _entityIDs, {
88180                     show: false
88181                   }));
88182                 }
88183               });
88184
88185               _fieldsArr.forEach(function (field) {
88186                 field.on('change', function (t, onInput) {
88187                   dispatch$1.call('change', field, _entityIDs, t, onInput);
88188                 }).on('revert', function (keys) {
88189                   dispatch$1.call('revert', field, keys);
88190                 });
88191               });
88192             }
88193
88194             _fieldsArr.forEach(function (field) {
88195               field.state(_state).tags(_tags);
88196             });
88197
88198             selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
88199             selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
88200               // if user presses enter, and combobox is not active, accept edits..
88201               if (d3_event.keyCode === 13 && // ↩ Return
88202               context.container().select('.combobox').empty()) {
88203                 context.enter(modeBrowse(context));
88204               }
88205             });
88206           }
88207
88208           section.presets = function (val) {
88209             if (!arguments.length) return _presets;
88210
88211             if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
88212               _presets = val;
88213               _fieldsArr = null;
88214             }
88215
88216             return section;
88217           };
88218
88219           section.state = function (val) {
88220             if (!arguments.length) return _state;
88221             _state = val;
88222             return section;
88223           };
88224
88225           section.tags = function (val) {
88226             if (!arguments.length) return _tags;
88227             _tags = val; // Don't reset _fieldsArr here.
88228
88229             return section;
88230           };
88231
88232           section.entityIDs = function (val) {
88233             if (!arguments.length) return _entityIDs;
88234
88235             if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
88236               _entityIDs = val;
88237               _fieldsArr = null;
88238             }
88239
88240             return section;
88241           };
88242
88243           return utilRebind(section, dispatch$1, 'on');
88244         }
88245
88246         function uiSectionRawMemberEditor(context) {
88247           var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
88248             if (!_entityIDs || _entityIDs.length !== 1) return false;
88249             var entity = context.hasEntity(_entityIDs[0]);
88250             return entity && entity.type === 'relation';
88251           }).label(function () {
88252             var entity = context.hasEntity(_entityIDs[0]);
88253             if (!entity) return '';
88254             var gt = entity.members.length > _maxMembers ? '>' : '';
88255             var count = gt + entity.members.slice(0, _maxMembers).length;
88256             return _t('inspector.title_count', {
88257               title: _t.html('inspector.members'),
88258               count: count
88259             });
88260           }).disclosureContent(renderDisclosureContent);
88261           var taginfo = services.taginfo;
88262
88263           var _entityIDs;
88264
88265           var _maxMembers = 1000;
88266
88267           function downloadMember(d3_event, d) {
88268             d3_event.preventDefault(); // display the loading indicator
88269
88270             select(this.parentNode).classed('tag-reference-loading', true);
88271             context.loadEntity(d.id, function () {
88272               section.reRender();
88273             });
88274           }
88275
88276           function zoomToMember(d3_event, d) {
88277             d3_event.preventDefault();
88278             var entity = context.entity(d.id);
88279             context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
88280
88281             utilHighlightEntities([d.id], true, context);
88282           }
88283
88284           function selectMember(d3_event, d) {
88285             d3_event.preventDefault(); // remove the hover-highlight styling
88286
88287             utilHighlightEntities([d.id], false, context);
88288             var entity = context.entity(d.id);
88289             var mapExtent = context.map().extent();
88290
88291             if (!entity.intersects(mapExtent, context.graph())) {
88292               // zoom to the entity if its extent is not visible now
88293               context.map().zoomToEase(entity);
88294             }
88295
88296             context.enter(modeSelect(context, [d.id]));
88297           }
88298
88299           function changeRole(d3_event, d) {
88300             var oldRole = d.role;
88301             var newRole = context.cleanRelationRole(select(this).property('value'));
88302
88303             if (oldRole !== newRole) {
88304               var member = {
88305                 id: d.id,
88306                 type: d.type,
88307                 role: newRole
88308               };
88309               context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
88310                 n: 1
88311               }));
88312               context.validator().validate();
88313             }
88314           }
88315
88316           function deleteMember(d3_event, d) {
88317             // remove the hover-highlight styling
88318             utilHighlightEntities([d.id], false, context);
88319             context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
88320               n: 1
88321             }));
88322
88323             if (!context.hasEntity(d.relation.id)) {
88324               // Removing the last member will also delete the relation.
88325               // If this happens we need to exit the selection mode
88326               context.enter(modeBrowse(context));
88327             } else {
88328               // Changing the mode also runs `validate`, but otherwise we need to
88329               // rerun it manually
88330               context.validator().validate();
88331             }
88332           }
88333
88334           function renderDisclosureContent(selection) {
88335             var entityID = _entityIDs[0];
88336             var memberships = [];
88337             var entity = context.entity(entityID);
88338             entity.members.slice(0, _maxMembers).forEach(function (member, index) {
88339               memberships.push({
88340                 index: index,
88341                 id: member.id,
88342                 type: member.type,
88343                 role: member.role,
88344                 relation: entity,
88345                 member: context.hasEntity(member.id),
88346                 domId: utilUniqueDomId(entityID + '-member-' + index)
88347               });
88348             });
88349             var list = selection.selectAll('.member-list').data([0]);
88350             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
88351             var items = list.selectAll('li').data(memberships, function (d) {
88352               return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
88353             });
88354             items.exit().each(unbind).remove();
88355             var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
88356               return !d.member;
88357             });
88358             itemsEnter.each(function (d) {
88359               var item = select(this);
88360               var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
88361
88362               if (d.member) {
88363                 // highlight the member feature in the map while hovering on the list item
88364                 item.on('mouseover', function () {
88365                   utilHighlightEntities([d.id], true, context);
88366                 }).on('mouseout', function () {
88367                   utilHighlightEntities([d.id], false, context);
88368                 });
88369                 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
88370                 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
88371                   var matched = _mainPresetIndex.match(d.member, context.graph());
88372                   return matched && matched.name() || utilDisplayType(d.member.id);
88373                 });
88374                 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
88375                   return utilDisplayName(d.member);
88376                 });
88377                 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
88378                 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
88379               } else {
88380                 var labelText = label.append('span').attr('class', 'label-text');
88381                 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
88382                   id: d.id
88383                 }));
88384                 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
88385                   id: d.id
88386                 }));
88387                 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
88388               }
88389             });
88390             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88391             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
88392               return d.domId;
88393             }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
88394
88395             if (taginfo) {
88396               wrapEnter.each(bindTypeahead);
88397             } // update
88398
88399
88400             items = items.merge(itemsEnter).order();
88401             items.select('input.member-role').property('value', function (d) {
88402               return d.role;
88403             }).on('blur', changeRole).on('change', changeRole);
88404             items.select('button.member-delete').on('click', deleteMember);
88405             var dragOrigin, targetIndex;
88406             items.call(d3_drag().on('start', function (d3_event) {
88407               dragOrigin = {
88408                 x: d3_event.x,
88409                 y: d3_event.y
88410               };
88411               targetIndex = null;
88412             }).on('drag', function (d3_event) {
88413               var x = d3_event.x - dragOrigin.x,
88414                   y = d3_event.y - dragOrigin.y;
88415               if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
88416               Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
88417               var index = items.nodes().indexOf(this);
88418               select(this).classed('dragging', true);
88419               targetIndex = null;
88420               selection.selectAll('li.member-row').style('transform', function (d2, index2) {
88421                 var node = select(this).node();
88422
88423                 if (index === index2) {
88424                   return 'translate(' + x + 'px, ' + y + 'px)';
88425                 } else if (index2 > index && d3_event.y > node.offsetTop) {
88426                   if (targetIndex === null || index2 > targetIndex) {
88427                     targetIndex = index2;
88428                   }
88429
88430                   return 'translateY(-100%)';
88431                 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
88432                   if (targetIndex === null || index2 < targetIndex) {
88433                     targetIndex = index2;
88434                   }
88435
88436                   return 'translateY(100%)';
88437                 }
88438
88439                 return null;
88440               });
88441             }).on('end', function (d3_event, d) {
88442               if (!select(this).classed('dragging')) return;
88443               var index = items.nodes().indexOf(this);
88444               select(this).classed('dragging', false);
88445               selection.selectAll('li.member-row').style('transform', null);
88446
88447               if (targetIndex !== null) {
88448                 // dragged to a new position, reorder
88449                 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
88450                 context.validator().validate();
88451               }
88452             }));
88453
88454             function bindTypeahead(d) {
88455               var row = select(this);
88456               var role = row.selectAll('input.member-role');
88457               var origValue = role.property('value');
88458
88459               function sort(value, data) {
88460                 var sameletter = [];
88461                 var other = [];
88462
88463                 for (var i = 0; i < data.length; i++) {
88464                   if (data[i].value.substring(0, value.length) === value) {
88465                     sameletter.push(data[i]);
88466                   } else {
88467                     other.push(data[i]);
88468                   }
88469                 }
88470
88471                 return sameletter.concat(other);
88472               }
88473
88474               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88475                 // The `geometry` param is used in the `taginfo.js` interface for
88476                 // filtering results, as a key into the `tag_members_fractions`
88477                 // object.  If we don't know the geometry because the member is
88478                 // not yet downloaded, it's ok to guess based on type.
88479                 var geometry;
88480
88481                 if (d.member) {
88482                   geometry = context.graph().geometry(d.member.id);
88483                 } else if (d.type === 'relation') {
88484                   geometry = 'relation';
88485                 } else if (d.type === 'way') {
88486                   geometry = 'line';
88487                 } else {
88488                   geometry = 'point';
88489                 }
88490
88491                 var rtype = entity.tags.type;
88492                 taginfo.roles({
88493                   debounce: true,
88494                   rtype: rtype || '',
88495                   geometry: geometry,
88496                   query: role
88497                 }, function (err, data) {
88498                   if (!err) callback(sort(role, data));
88499                 });
88500               }).on('cancel', function () {
88501                 role.property('value', origValue);
88502               }));
88503             }
88504
88505             function unbind() {
88506               var row = select(this);
88507               row.selectAll('input.member-role').call(uiCombobox.off, context);
88508             }
88509           }
88510
88511           section.entityIDs = function (val) {
88512             if (!arguments.length) return _entityIDs;
88513             _entityIDs = val;
88514             return section;
88515           };
88516
88517           return section;
88518         }
88519
88520         function actionDeleteMembers(relationId, memberIndexes) {
88521           return function (graph) {
88522             // Remove the members in descending order so removals won't shift what members
88523             // are at the remaining indexes
88524             memberIndexes.sort(function (a, b) {
88525               return b - a;
88526             });
88527
88528             for (var i in memberIndexes) {
88529               graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
88530             }
88531
88532             return graph;
88533           };
88534         }
88535
88536         function uiSectionRawMembershipEditor(context) {
88537           var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
88538             return _entityIDs && _entityIDs.length;
88539           }).label(function () {
88540             var parents = getSharedParentRelations();
88541             var gt = parents.length > _maxMemberships ? '>' : '';
88542             var count = gt + parents.slice(0, _maxMemberships).length;
88543             return _t('inspector.title_count', {
88544               title: _t.html('inspector.relations'),
88545               count: count
88546             });
88547           }).disclosureContent(renderDisclosureContent);
88548           var taginfo = services.taginfo;
88549           var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
88550             if (d.relation) utilHighlightEntities([d.relation.id], true, context);
88551           }).itemsMouseLeave(function (d3_event, d) {
88552             if (d.relation) utilHighlightEntities([d.relation.id], false, context);
88553           });
88554           var _inChange = false;
88555           var _entityIDs = [];
88556
88557           var _showBlank;
88558
88559           var _maxMemberships = 1000;
88560
88561           function getSharedParentRelations() {
88562             var parents = [];
88563
88564             for (var i = 0; i < _entityIDs.length; i++) {
88565               var entity = context.graph().hasEntity(_entityIDs[i]);
88566               if (!entity) continue;
88567
88568               if (i === 0) {
88569                 parents = context.graph().parentRelations(entity);
88570               } else {
88571                 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
88572               }
88573
88574               if (!parents.length) break;
88575             }
88576
88577             return parents;
88578           }
88579
88580           function getMemberships() {
88581             var memberships = [];
88582             var relations = getSharedParentRelations().slice(0, _maxMemberships);
88583             var isMultiselect = _entityIDs.length > 1;
88584             var i, relation, membership, index, member, indexedMember;
88585
88586             for (i = 0; i < relations.length; i++) {
88587               relation = relations[i];
88588               membership = {
88589                 relation: relation,
88590                 members: [],
88591                 hash: osmEntity.key(relation)
88592               };
88593
88594               for (index = 0; index < relation.members.length; index++) {
88595                 member = relation.members[index];
88596
88597                 if (_entityIDs.indexOf(member.id) !== -1) {
88598                   indexedMember = Object.assign({}, member, {
88599                     index: index
88600                   });
88601                   membership.members.push(indexedMember);
88602                   membership.hash += ',' + index.toString();
88603
88604                   if (!isMultiselect) {
88605                     // For single selections, list one entry per membership per relation.
88606                     // For multiselections, list one entry per relation.
88607                     memberships.push(membership);
88608                     membership = {
88609                       relation: relation,
88610                       members: [],
88611                       hash: osmEntity.key(relation)
88612                     };
88613                   }
88614                 }
88615               }
88616
88617               if (membership.members.length) memberships.push(membership);
88618             }
88619
88620             memberships.forEach(function (membership) {
88621               membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
88622               var roles = [];
88623               membership.members.forEach(function (member) {
88624                 if (roles.indexOf(member.role) === -1) roles.push(member.role);
88625               });
88626               membership.role = roles.length === 1 ? roles[0] : roles;
88627             });
88628             return memberships;
88629           }
88630
88631           function selectRelation(d3_event, d) {
88632             d3_event.preventDefault(); // remove the hover-highlight styling
88633
88634             utilHighlightEntities([d.relation.id], false, context);
88635             context.enter(modeSelect(context, [d.relation.id]));
88636           }
88637
88638           function zoomToRelation(d3_event, d) {
88639             d3_event.preventDefault();
88640             var entity = context.entity(d.relation.id);
88641             context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
88642
88643             utilHighlightEntities([d.relation.id], true, context);
88644           }
88645
88646           function changeRole(d3_event, d) {
88647             if (d === 0) return; // called on newrow (shouldn't happen)
88648
88649             if (_inChange) return; // avoid accidental recursive call #5731
88650
88651             var newRole = context.cleanRelationRole(select(this).property('value'));
88652             if (!newRole.trim() && typeof d.role !== 'string') return;
88653             var membersToUpdate = d.members.filter(function (member) {
88654               return member.role !== newRole;
88655             });
88656
88657             if (membersToUpdate.length) {
88658               _inChange = true;
88659               context.perform(function actionChangeMemberRoles(graph) {
88660                 membersToUpdate.forEach(function (member) {
88661                   var newMember = Object.assign({}, member, {
88662                     role: newRole
88663                   });
88664                   delete newMember.index;
88665                   graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
88666                 });
88667                 return graph;
88668               }, _t('operations.change_role.annotation', {
88669                 n: membersToUpdate.length
88670               }));
88671               context.validator().validate();
88672             }
88673
88674             _inChange = false;
88675           }
88676
88677           function addMembership(d, role) {
88678             this.blur(); // avoid keeping focus on the button
88679
88680             _showBlank = false;
88681
88682             function actionAddMembers(relationId, ids, role) {
88683               return function (graph) {
88684                 for (var i in ids) {
88685                   var member = {
88686                     id: ids[i],
88687                     type: graph.entity(ids[i]).type,
88688                     role: role
88689                   };
88690                   graph = actionAddMember(relationId, member)(graph);
88691                 }
88692
88693                 return graph;
88694               };
88695             }
88696
88697             if (d.relation) {
88698               context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
88699                 n: _entityIDs.length
88700               }));
88701               context.validator().validate();
88702             } else {
88703               var relation = osmRelation();
88704               context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
88705
88706               context.enter(modeSelect(context, [relation.id]).newFeature(true));
88707             }
88708           }
88709
88710           function deleteMembership(d3_event, d) {
88711             this.blur(); // avoid keeping focus on the button
88712
88713             if (d === 0) return; // called on newrow (shouldn't happen)
88714             // remove the hover-highlight styling
88715
88716             utilHighlightEntities([d.relation.id], false, context);
88717             var indexes = d.members.map(function (member) {
88718               return member.index;
88719             });
88720             context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
88721               n: _entityIDs.length
88722             }));
88723             context.validator().validate();
88724           }
88725
88726           function fetchNearbyRelations(q, callback) {
88727             var newRelation = {
88728               relation: null,
88729               value: _t('inspector.new_relation'),
88730               display: _t.html('inspector.new_relation')
88731             };
88732             var entityID = _entityIDs[0];
88733             var result = [];
88734             var graph = context.graph();
88735
88736             function baseDisplayLabel(entity) {
88737               var matched = _mainPresetIndex.match(entity, graph);
88738               var presetName = matched && matched.name() || _t('inspector.relation');
88739               var entityName = utilDisplayName(entity) || '';
88740               return presetName + ' ' + entityName;
88741             }
88742
88743             var explicitRelation = q && context.hasEntity(q.toLowerCase());
88744
88745             if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
88746               // loaded relation is specified explicitly, only show that
88747               result.push({
88748                 relation: explicitRelation,
88749                 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
88750               });
88751             } else {
88752               context.history().intersects(context.map().extent()).forEach(function (entity) {
88753                 if (entity.type !== 'relation' || entity.id === entityID) return;
88754                 var value = baseDisplayLabel(entity);
88755                 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
88756                 result.push({
88757                   relation: entity,
88758                   value: value
88759                 });
88760               });
88761               result.sort(function (a, b) {
88762                 return osmRelation.creationOrder(a.relation, b.relation);
88763               }); // Dedupe identical names by appending relation id - see #2891
88764
88765               var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
88766                 return v.length > 1;
88767               });
88768               dupeGroups.forEach(function (group) {
88769                 group.forEach(function (obj) {
88770                   obj.value += ' ' + obj.relation.id;
88771                 });
88772               });
88773             }
88774
88775             result.forEach(function (obj) {
88776               obj.title = obj.value;
88777             });
88778             result.unshift(newRelation);
88779             callback(result);
88780           }
88781
88782           function renderDisclosureContent(selection) {
88783             var memberships = getMemberships();
88784             var list = selection.selectAll('.member-list').data([0]);
88785             list = list.enter().append('ul').attr('class', 'member-list').merge(list);
88786             var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
88787               return d.hash;
88788             });
88789             items.exit().each(unbind).remove(); // Enter
88790
88791             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
88792
88793             itemsEnter.on('mouseover', function (d3_event, d) {
88794               utilHighlightEntities([d.relation.id], true, context);
88795             }).on('mouseout', function (d3_event, d) {
88796               utilHighlightEntities([d.relation.id], false, context);
88797             });
88798             var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
88799               return d.domId;
88800             });
88801             var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
88802             labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
88803               var matched = _mainPresetIndex.match(d.relation, context.graph());
88804               return matched && matched.name() || _t('inspector.relation');
88805             });
88806             labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
88807               return utilDisplayName(d.relation);
88808             });
88809             labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
88810             labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
88811             var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88812             wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
88813               return d.domId;
88814             }).property('type', 'text').property('value', function (d) {
88815               return typeof d.role === 'string' ? d.role : '';
88816             }).attr('title', function (d) {
88817               return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
88818             }).attr('placeholder', function (d) {
88819               return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
88820             }).classed('mixed', function (d) {
88821               return Array.isArray(d.role);
88822             }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
88823
88824             if (taginfo) {
88825               wrapEnter.each(bindTypeahead);
88826             }
88827
88828             var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
88829
88830             newMembership.exit().remove(); // Enter
88831
88832             var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
88833             var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
88834             newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
88835             newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
88836               list.selectAll('.member-row-new').remove();
88837             });
88838             var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
88839             newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
88840
88841             newMembership = newMembership.merge(newMembershipEnter);
88842             newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
88843             .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
88844
88845             var addRow = selection.selectAll('.add-row').data([0]); // enter
88846
88847             var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
88848             var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
88849             addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
88850             addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
88851             addRowEnter.append('div').attr('class', 'space-value'); // preserve space
88852
88853             addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
88854             // update
88855
88856             addRow = addRow.merge(addRowEnter);
88857             addRow.select('.add-relation').on('click', function () {
88858               _showBlank = true;
88859               section.reRender();
88860               list.selectAll('.member-entity-input').node().focus();
88861             });
88862
88863             function acceptEntity(d) {
88864               if (!d) {
88865                 cancelEntity();
88866                 return;
88867               } // remove hover-higlighting
88868
88869
88870               if (d.relation) utilHighlightEntities([d.relation.id], false, context);
88871               var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
88872               addMembership(d, role);
88873             }
88874
88875             function cancelEntity() {
88876               var input = newMembership.selectAll('.member-entity-input');
88877               input.property('value', ''); // remove hover-higlighting
88878
88879               context.surface().selectAll('.highlighted').classed('highlighted', false);
88880             }
88881
88882             function bindTypeahead(d) {
88883               var row = select(this);
88884               var role = row.selectAll('input.member-role');
88885               var origValue = role.property('value');
88886
88887               function sort(value, data) {
88888                 var sameletter = [];
88889                 var other = [];
88890
88891                 for (var i = 0; i < data.length; i++) {
88892                   if (data[i].value.substring(0, value.length) === value) {
88893                     sameletter.push(data[i]);
88894                   } else {
88895                     other.push(data[i]);
88896                   }
88897                 }
88898
88899                 return sameletter.concat(other);
88900               }
88901
88902               role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
88903                 var rtype = d.relation.tags.type;
88904                 taginfo.roles({
88905                   debounce: true,
88906                   rtype: rtype || '',
88907                   geometry: context.graph().geometry(_entityIDs[0]),
88908                   query: role
88909                 }, function (err, data) {
88910                   if (!err) callback(sort(role, data));
88911                 });
88912               }).on('cancel', function () {
88913                 role.property('value', origValue);
88914               }));
88915             }
88916
88917             function unbind() {
88918               var row = select(this);
88919               row.selectAll('input.member-role').call(uiCombobox.off, context);
88920             }
88921           }
88922
88923           section.entityIDs = function (val) {
88924             if (!arguments.length) return _entityIDs;
88925             _entityIDs = val;
88926             _showBlank = false;
88927             return section;
88928           };
88929
88930           return section;
88931         }
88932
88933         function uiSectionSelectionList(context) {
88934           var _selectedIDs = [];
88935           var section = uiSection('selected-features', context).shouldDisplay(function () {
88936             return _selectedIDs.length > 1;
88937           }).label(function () {
88938             return _t('inspector.title_count', {
88939               title: _t.html('inspector.features'),
88940               count: _selectedIDs.length
88941             });
88942           }).disclosureContent(renderDisclosureContent);
88943           context.history().on('change.selectionList', function (difference) {
88944             if (difference) {
88945               section.reRender();
88946             }
88947           });
88948
88949           section.entityIDs = function (val) {
88950             if (!arguments.length) return _selectedIDs;
88951             _selectedIDs = val;
88952             return section;
88953           };
88954
88955           function selectEntity(d3_event, entity) {
88956             context.enter(modeSelect(context, [entity.id]));
88957           }
88958
88959           function deselectEntity(d3_event, entity) {
88960             var selectedIDs = _selectedIDs.slice();
88961
88962             var index = selectedIDs.indexOf(entity.id);
88963
88964             if (index > -1) {
88965               selectedIDs.splice(index, 1);
88966               context.enter(modeSelect(context, selectedIDs));
88967             }
88968           }
88969
88970           function renderDisclosureContent(selection) {
88971             var list = selection.selectAll('.feature-list').data([0]);
88972             list = list.enter().append('ul').attr('class', 'feature-list').merge(list);
88973
88974             var entities = _selectedIDs.map(function (id) {
88975               return context.hasEntity(id);
88976             }).filter(Boolean);
88977
88978             var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
88979             items.exit().remove(); // Enter
88980
88981             var enter = items.enter().append('li').attr('class', 'feature-list-item').each(function (d) {
88982               select(this).on('mouseover', function () {
88983                 utilHighlightEntities([d.id], true, context);
88984               }).on('mouseout', function () {
88985                 utilHighlightEntities([d.id], false, context);
88986               });
88987             });
88988             var label = enter.append('button').attr('class', 'label').on('click', selectEntity);
88989             label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
88990             label.append('span').attr('class', 'entity-type');
88991             label.append('span').attr('class', 'entity-name');
88992             enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close')); // Update
88993
88994             items = items.merge(enter);
88995             items.selectAll('.entity-geom-icon use').attr('href', function () {
88996               var entity = this.parentNode.parentNode.__data__;
88997               return '#iD-icon-' + entity.geometry(context.graph());
88998             });
88999             items.selectAll('.entity-type').html(function (entity) {
89000               return _mainPresetIndex.match(entity, context.graph()).name();
89001             });
89002             items.selectAll('.entity-name').html(function (d) {
89003               // fetch latest entity
89004               var entity = context.entity(d.id);
89005               return utilDisplayName(entity);
89006             });
89007           }
89008
89009           return section;
89010         }
89011
89012         function uiEntityEditor(context) {
89013           var dispatch$1 = dispatch('choose');
89014           var _state = 'select';
89015           var _coalesceChanges = false;
89016           var _modified = false;
89017
89018           var _base;
89019
89020           var _entityIDs;
89021
89022           var _activePresets = [];
89023
89024           var _newFeature;
89025
89026           var _sections;
89027
89028           function entityEditor(selection) {
89029             var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
89030
89031             var header = selection.selectAll('.header').data([0]); // Enter
89032
89033             var headerEnter = header.enter().append('div').attr('class', 'header fillL');
89034             headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
89035             headerEnter.append('button').attr('class', 'close').on('click', function () {
89036               context.enter(modeBrowse(context));
89037             }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
89038             headerEnter.append('h3'); // Update
89039
89040             header = header.merge(headerEnter);
89041             header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
89042             header.selectAll('.preset-reset').on('click', function () {
89043               dispatch$1.call('choose', this, _activePresets);
89044             }); // Body
89045
89046             var body = selection.selectAll('.inspector-body').data([0]); // Enter
89047
89048             var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
89049
89050             body = body.merge(bodyEnter);
89051
89052             if (!_sections) {
89053               _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
89054                 dispatch$1.call('choose', this, presets);
89055               }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
89056             }
89057
89058             _sections.forEach(function (section) {
89059               if (section.entityIDs) {
89060                 section.entityIDs(_entityIDs);
89061               }
89062
89063               if (section.presets) {
89064                 section.presets(_activePresets);
89065               }
89066
89067               if (section.tags) {
89068                 section.tags(combinedTags);
89069               }
89070
89071               if (section.state) {
89072                 section.state(_state);
89073               }
89074
89075               body.call(section.render);
89076             });
89077
89078             context.history().on('change.entity-editor', historyChanged);
89079
89080             function historyChanged(difference) {
89081               if (selection.selectAll('.entity-editor').empty()) return;
89082               if (_state === 'hide') return;
89083               var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
89084               if (!significant) return;
89085               _entityIDs = _entityIDs.filter(context.hasEntity);
89086               if (!_entityIDs.length) return;
89087               var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
89088               loadActivePresets();
89089               var graph = context.graph();
89090               entityEditor.modified(_base !== graph);
89091               entityEditor(selection);
89092
89093               if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
89094                 // flash the button to indicate the preset changed
89095                 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
89096               }
89097             }
89098           } // Tag changes that fire on input can all get coalesced into a single
89099           // history operation when the user leaves the field.  #2342
89100           // Use explicit entityIDs in case the selection changes before the event is fired.
89101
89102
89103           function changeTags(entityIDs, changed, onInput) {
89104             var actions = [];
89105
89106             for (var i in entityIDs) {
89107               var entityID = entityIDs[i];
89108               var entity = context.entity(entityID);
89109               var tags = Object.assign({}, entity.tags); // shallow copy
89110
89111               for (var k in changed) {
89112                 if (!k) continue;
89113                 var v = changed[k];
89114
89115                 if (v !== undefined || tags.hasOwnProperty(k)) {
89116                   tags[k] = v;
89117                 }
89118               }
89119
89120               if (!onInput) {
89121                 tags = utilCleanTags(tags);
89122               }
89123
89124               if (!fastDeepEqual(entity.tags, tags)) {
89125                 actions.push(actionChangeTags(entityID, tags));
89126               }
89127             }
89128
89129             if (actions.length) {
89130               var combinedAction = function combinedAction(graph) {
89131                 actions.forEach(function (action) {
89132                   graph = action(graph);
89133                 });
89134                 return graph;
89135               };
89136
89137               var annotation = _t('operations.change_tags.annotation');
89138
89139               if (_coalesceChanges) {
89140                 context.overwrite(combinedAction, annotation);
89141               } else {
89142                 context.perform(combinedAction, annotation);
89143                 _coalesceChanges = !!onInput;
89144               }
89145             } // if leaving field (blur event), rerun validation
89146
89147
89148             if (!onInput) {
89149               context.validator().validate();
89150             }
89151           }
89152
89153           function revertTags(keys) {
89154             var actions = [];
89155
89156             for (var i in _entityIDs) {
89157               var entityID = _entityIDs[i];
89158               var original = context.graph().base().entities[entityID];
89159               var changed = {};
89160
89161               for (var j in keys) {
89162                 var key = keys[j];
89163                 changed[key] = original ? original.tags[key] : undefined;
89164               }
89165
89166               var entity = context.entity(entityID);
89167               var tags = Object.assign({}, entity.tags); // shallow copy
89168
89169               for (var k in changed) {
89170                 if (!k) continue;
89171                 var v = changed[k];
89172
89173                 if (v !== undefined || tags.hasOwnProperty(k)) {
89174                   tags[k] = v;
89175                 }
89176               }
89177
89178               tags = utilCleanTags(tags);
89179
89180               if (!fastDeepEqual(entity.tags, tags)) {
89181                 actions.push(actionChangeTags(entityID, tags));
89182               }
89183             }
89184
89185             if (actions.length) {
89186               var combinedAction = function combinedAction(graph) {
89187                 actions.forEach(function (action) {
89188                   graph = action(graph);
89189                 });
89190                 return graph;
89191               };
89192
89193               var annotation = _t('operations.change_tags.annotation');
89194
89195               if (_coalesceChanges) {
89196                 context.overwrite(combinedAction, annotation);
89197               } else {
89198                 context.perform(combinedAction, annotation);
89199                 _coalesceChanges = false;
89200               }
89201             }
89202
89203             context.validator().validate();
89204           }
89205
89206           entityEditor.modified = function (val) {
89207             if (!arguments.length) return _modified;
89208             _modified = val;
89209             return entityEditor;
89210           };
89211
89212           entityEditor.state = function (val) {
89213             if (!arguments.length) return _state;
89214             _state = val;
89215             return entityEditor;
89216           };
89217
89218           entityEditor.entityIDs = function (val) {
89219             if (!arguments.length) return _entityIDs; // always reload these even if the entityIDs are unchanged, since we
89220             // could be reselecting after something like dragging a node
89221
89222             _base = context.graph();
89223             _coalesceChanges = false;
89224             if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
89225
89226             _entityIDs = val;
89227             loadActivePresets(true);
89228             return entityEditor.modified(false);
89229           };
89230
89231           entityEditor.newFeature = function (val) {
89232             if (!arguments.length) return _newFeature;
89233             _newFeature = val;
89234             return entityEditor;
89235           };
89236
89237           function loadActivePresets(isForNewSelection) {
89238             var graph = context.graph();
89239             var counts = {};
89240
89241             for (var i in _entityIDs) {
89242               var entity = graph.hasEntity(_entityIDs[i]);
89243               if (!entity) return;
89244               var match = _mainPresetIndex.match(entity, graph);
89245               if (!counts[match.id]) counts[match.id] = 0;
89246               counts[match.id] += 1;
89247             }
89248
89249             var matches = Object.keys(counts).sort(function (p1, p2) {
89250               return counts[p2] - counts[p1];
89251             }).map(function (pID) {
89252               return _mainPresetIndex.item(pID);
89253             });
89254
89255             if (!isForNewSelection) {
89256               // A "weak" preset doesn't set any tags. (e.g. "Address")
89257               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")
89258
89259               if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
89260             }
89261
89262             entityEditor.presets(matches);
89263           }
89264
89265           entityEditor.presets = function (val) {
89266             if (!arguments.length) return _activePresets; // don't reload the same preset
89267
89268             if (!utilArrayIdentical(val, _activePresets)) {
89269               _activePresets = val;
89270             }
89271
89272             return entityEditor;
89273           };
89274
89275           return utilRebind(entityEditor, dispatch$1, 'on');
89276         }
89277
89278         function uiPresetList(context) {
89279           var dispatch$1 = dispatch('cancel', 'choose');
89280
89281           var _entityIDs;
89282
89283           var _currentPresets;
89284
89285           var _autofocus = false;
89286
89287           function presetList(selection) {
89288             if (!_entityIDs) return;
89289             var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
89290             selection.html('');
89291             var messagewrap = selection.append('div').attr('class', 'header fillL');
89292             var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
89293             messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
89294               dispatch$1.call('cancel', this);
89295             }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
89296
89297             function initialKeydown(d3_event) {
89298               // hack to let delete shortcut work when search is autofocused
89299               if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
89300                 d3_event.preventDefault();
89301                 d3_event.stopPropagation();
89302                 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
89303               } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
89304                 d3_event.preventDefault();
89305                 d3_event.stopPropagation();
89306                 context.undo();
89307               } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
89308                 // don't check for delete/undo hack on future keydown events
89309                 select(this).on('keydown', keydown);
89310                 keydown.call(this, d3_event);
89311               }
89312             }
89313
89314             function keydown(d3_event) {
89315               // down arrow
89316               if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
89317               search.node().selectionStart === search.property('value').length) {
89318                 d3_event.preventDefault();
89319                 d3_event.stopPropagation(); // move focus to the first item in the preset list
89320
89321                 var buttons = list.selectAll('.preset-list-button');
89322                 if (!buttons.empty()) buttons.nodes()[0].focus();
89323               }
89324             }
89325
89326             function keypress(d3_event) {
89327               // enter
89328               var value = search.property('value');
89329
89330               if (d3_event.keyCode === 13 && // ↩ Return
89331               value.length) {
89332                 list.selectAll('.preset-list-item:first-child').each(function (d) {
89333                   d.choose.call(this);
89334                 });
89335               }
89336             }
89337
89338             function inputevent() {
89339               var value = search.property('value');
89340               list.classed('filtered', value.length);
89341               var extent = combinedEntityExtent();
89342               var results, messageText;
89343
89344               if (value.length && extent) {
89345                 var center = extent.center();
89346                 var countryCode = iso1A2Code(center);
89347                 results = presets.search(value, entityGeometries()[0], countryCode && countryCode.toLowerCase());
89348                 messageText = _t('inspector.results', {
89349                   n: results.collection.length,
89350                   search: value
89351                 });
89352               } else {
89353                 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro());
89354                 messageText = _t('inspector.choose');
89355               }
89356
89357               list.call(drawList, results);
89358               message.html(messageText);
89359             }
89360
89361             var searchWrap = selection.append('div').attr('class', 'search-header');
89362             searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
89363             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);
89364
89365             if (_autofocus) {
89366               search.node().focus(); // Safari 14 doesn't always like to focus immediately,
89367               // so try again on the next pass
89368
89369               setTimeout(function () {
89370                 search.node().focus();
89371               }, 0);
89372             }
89373
89374             var listWrap = selection.append('div').attr('class', 'inspector-body');
89375             var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro()));
89376             context.features().on('change.preset-list', updateForFeatureHiddenState);
89377           }
89378
89379           function drawList(list, presets) {
89380             presets = presets.matchAllGeometry(entityGeometries());
89381             var collection = presets.collection.reduce(function (collection, preset) {
89382               if (!preset) return collection;
89383
89384               if (preset.members) {
89385                 if (preset.members.collection.filter(function (preset) {
89386                   return preset.addable();
89387                 }).length > 1) {
89388                   collection.push(CategoryItem(preset));
89389                 }
89390               } else if (preset.addable()) {
89391                 collection.push(PresetItem(preset));
89392               }
89393
89394               return collection;
89395             }, []);
89396             var items = list.selectAll('.preset-list-item').data(collection, function (d) {
89397               return d.preset.id;
89398             });
89399             items.order();
89400             items.exit().remove();
89401             items.enter().append('div').attr('class', function (item) {
89402               return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
89403             }).classed('current', function (item) {
89404               return _currentPresets.indexOf(item.preset) !== -1;
89405             }).each(function (item) {
89406               select(this).call(item);
89407             }).style('opacity', 0).transition().style('opacity', 1);
89408             updateForFeatureHiddenState();
89409           }
89410
89411           function itemKeydown(d3_event) {
89412             // the actively focused item
89413             var item = select(this.closest('.preset-list-item'));
89414             var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
89415
89416             if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
89417               d3_event.preventDefault();
89418               d3_event.stopPropagation(); // the next item in the list at the same level
89419
89420               var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
89421
89422               if (nextItem.empty()) {
89423                 // if there is a parent item
89424                 if (!parentItem.empty()) {
89425                   // the item is the last item of a sublist,
89426                   // select the next item at the parent level
89427                   nextItem = select(parentItem.node().nextElementSibling);
89428                 } // if the focused item is expanded
89429
89430               } else if (select(this).classed('expanded')) {
89431                 // select the first subitem instead
89432                 nextItem = item.select('.subgrid .preset-list-item:first-child');
89433               }
89434
89435               if (!nextItem.empty()) {
89436                 // focus on the next item
89437                 nextItem.select('.preset-list-button').node().focus();
89438               } // arrow up, move focus to the previous, higher item
89439
89440             } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
89441               d3_event.preventDefault();
89442               d3_event.stopPropagation(); // the previous item in the list at the same level
89443
89444               var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
89445
89446               if (previousItem.empty()) {
89447                 // if there is a parent item
89448                 if (!parentItem.empty()) {
89449                   // the item is the first subitem of a sublist select the parent item
89450                   previousItem = parentItem;
89451                 } // if the previous item is expanded
89452
89453               } else if (previousItem.select('.preset-list-button').classed('expanded')) {
89454                 // select the last subitem of the sublist of the previous item
89455                 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
89456               }
89457
89458               if (!previousItem.empty()) {
89459                 // focus on the previous item
89460                 previousItem.select('.preset-list-button').node().focus();
89461               } else {
89462                 // the focus is at the top of the list, move focus back to the search field
89463                 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
89464                 search.node().focus();
89465               } // arrow left, move focus to the parent item if there is one
89466
89467             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
89468               d3_event.preventDefault();
89469               d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
89470
89471               if (!parentItem.empty()) {
89472                 parentItem.select('.preset-list-button').node().focus();
89473               } // arrow right, choose this item
89474
89475             } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
89476               d3_event.preventDefault();
89477               d3_event.stopPropagation();
89478               item.datum().choose.call(select(this).node());
89479             }
89480           }
89481
89482           function CategoryItem(preset) {
89483             var box,
89484                 sublist,
89485                 shown = false;
89486
89487             function item(selection) {
89488               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
89489
89490               function click() {
89491                 var isExpanded = select(this).classed('expanded');
89492                 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
89493                 select(this).classed('expanded', !isExpanded);
89494                 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
89495                 item.choose();
89496               }
89497
89498               var geometries = entityGeometries();
89499               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) {
89500                 // right arrow, expand the focused item
89501                 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
89502                   d3_event.preventDefault();
89503                   d3_event.stopPropagation(); // if the item isn't expanded
89504
89505                   if (!select(this).classed('expanded')) {
89506                     // toggle expansion (expand the item)
89507                     click.call(this, d3_event);
89508                   } // left arrow, collapse the focused item
89509
89510                 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
89511                   d3_event.preventDefault();
89512                   d3_event.stopPropagation(); // if the item is expanded
89513
89514                   if (select(this).classed('expanded')) {
89515                     // toggle expansion (collapse the item)
89516                     click.call(this, d3_event);
89517                   }
89518                 } else {
89519                   itemKeydown.call(this, d3_event);
89520                 }
89521               });
89522               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
89523               label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
89524                 return preset.nameLabel() + '&hellip;';
89525               });
89526               box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
89527               box.append('div').attr('class', 'arrow');
89528               sublist = box.append('div').attr('class', 'preset-list fillL3');
89529             }
89530
89531             item.choose = function () {
89532               if (!box || !sublist) return;
89533
89534               if (shown) {
89535                 shown = false;
89536                 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
89537               } else {
89538                 shown = true;
89539                 var members = preset.members.matchAllGeometry(entityGeometries());
89540                 sublist.call(drawList, members);
89541                 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
89542               }
89543             };
89544
89545             item.preset = preset;
89546             return item;
89547           }
89548
89549           function PresetItem(preset) {
89550             function item(selection) {
89551               var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
89552               var geometries = entityGeometries();
89553               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);
89554               var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
89555               var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
89556               label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
89557                 return d;
89558               });
89559               wrap.call(item.reference.button);
89560               selection.call(item.reference.body);
89561             }
89562
89563             item.choose = function () {
89564               if (select(this).classed('disabled')) return;
89565
89566               if (!context.inIntro()) {
89567                 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
89568               }
89569
89570               context.perform(function (graph) {
89571                 for (var i in _entityIDs) {
89572                   var entityID = _entityIDs[i];
89573                   var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
89574                   graph = actionChangePreset(entityID, oldPreset, preset)(graph);
89575                 }
89576
89577                 return graph;
89578               }, _t('operations.change_tags.annotation'));
89579               context.validator().validate(); // rerun validation
89580
89581               dispatch$1.call('choose', this, preset);
89582             };
89583
89584             item.help = function (d3_event) {
89585               d3_event.stopPropagation();
89586               item.reference.toggle();
89587             };
89588
89589             item.preset = preset;
89590             item.reference = uiTagReference(preset.reference());
89591             return item;
89592           }
89593
89594           function updateForFeatureHiddenState() {
89595             if (!_entityIDs.every(context.hasEntity)) return;
89596             var geometries = entityGeometries();
89597             var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
89598
89599             button.call(uiTooltip().destroyAny);
89600             button.each(function (item, index) {
89601               var hiddenPresetFeaturesId;
89602
89603               for (var i in geometries) {
89604                 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
89605                 if (hiddenPresetFeaturesId) break;
89606               }
89607
89608               var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
89609               select(this).classed('disabled', isHiddenPreset);
89610
89611               if (isHiddenPreset) {
89612                 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
89613                 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
89614                   features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
89615                 })).placement(index < 2 ? 'bottom' : 'top'));
89616               }
89617             });
89618           }
89619
89620           presetList.autofocus = function (val) {
89621             if (!arguments.length) return _autofocus;
89622             _autofocus = val;
89623             return presetList;
89624           };
89625
89626           presetList.entityIDs = function (val) {
89627             if (!arguments.length) return _entityIDs;
89628             _entityIDs = val;
89629
89630             if (_entityIDs && _entityIDs.length) {
89631               var presets = _entityIDs.map(function (entityID) {
89632                 return _mainPresetIndex.match(context.entity(entityID), context.graph());
89633               });
89634
89635               presetList.presets(presets);
89636             }
89637
89638             return presetList;
89639           };
89640
89641           presetList.presets = function (val) {
89642             if (!arguments.length) return _currentPresets;
89643             _currentPresets = val;
89644             return presetList;
89645           };
89646
89647           function entityGeometries() {
89648             var counts = {};
89649
89650             for (var i in _entityIDs) {
89651               var entityID = _entityIDs[i];
89652               var entity = context.entity(entityID);
89653               var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
89654
89655               if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
89656                 geometry = 'point';
89657               }
89658
89659               if (!counts[geometry]) counts[geometry] = 0;
89660               counts[geometry] += 1;
89661             }
89662
89663             return Object.keys(counts).sort(function (geom1, geom2) {
89664               return counts[geom2] - counts[geom1];
89665             });
89666           }
89667
89668           function combinedEntityExtent() {
89669             return _entityIDs.reduce(function (extent, entityID) {
89670               var entity = context.graph().entity(entityID);
89671               return extent.extend(entity.extent(context.graph()));
89672             }, geoExtent());
89673           }
89674
89675           return utilRebind(presetList, dispatch$1, 'on');
89676         }
89677
89678         function uiInspector(context) {
89679           var presetList = uiPresetList(context);
89680           var entityEditor = uiEntityEditor(context);
89681           var wrap = select(null),
89682               presetPane = select(null),
89683               editorPane = select(null);
89684           var _state = 'select';
89685
89686           var _entityIDs;
89687
89688           var _newFeature = false;
89689
89690           function inspector(selection) {
89691             presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
89692               inspector.setPreset();
89693             });
89694             entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
89695             wrap = selection.selectAll('.panewrap').data([0]);
89696             var enter = wrap.enter().append('div').attr('class', 'panewrap');
89697             enter.append('div').attr('class', 'preset-list-pane pane');
89698             enter.append('div').attr('class', 'entity-editor-pane pane');
89699             wrap = wrap.merge(enter);
89700             presetPane = wrap.selectAll('.preset-list-pane');
89701             editorPane = wrap.selectAll('.entity-editor-pane');
89702
89703             function shouldDefaultToPresetList() {
89704               // always show the inspector on hover
89705               if (_state !== 'select') return false; // can only change preset on single selection
89706
89707               if (_entityIDs.length !== 1) return false;
89708               var entityID = _entityIDs[0];
89709               var entity = context.hasEntity(entityID);
89710               if (!entity) return false; // default to inspector if there are already tags
89711
89712               if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
89713
89714               if (_newFeature) return true; // all existing features except vertices should default to inspector
89715
89716               if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
89717
89718               if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
89719
89720               if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
89721
89722               if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
89723
89724               return true;
89725             }
89726
89727             if (shouldDefaultToPresetList()) {
89728               wrap.style('right', '-100%');
89729               editorPane.classed('hide', true);
89730               presetPane.classed('hide', false).call(presetList);
89731             } else {
89732               wrap.style('right', '0%');
89733               presetPane.classed('hide', true);
89734               editorPane.classed('hide', false).call(entityEditor);
89735             }
89736
89737             var footer = selection.selectAll('.footer').data([0]);
89738             footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
89739             footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
89740           }
89741
89742           inspector.showList = function (presets) {
89743             presetPane.classed('hide', false);
89744             wrap.transition().styleTween('right', function () {
89745               return interpolate('0%', '-100%');
89746             }).on('end', function () {
89747               editorPane.classed('hide', true);
89748             });
89749
89750             if (presets) {
89751               presetList.presets(presets);
89752             }
89753
89754             presetPane.call(presetList.autofocus(true));
89755           };
89756
89757           inspector.setPreset = function (preset) {
89758             // upon setting multipolygon, go to the area preset list instead of the editor
89759             if (preset && preset.id === 'type/multipolygon') {
89760               presetPane.call(presetList.autofocus(true));
89761             } else {
89762               editorPane.classed('hide', false);
89763               wrap.transition().styleTween('right', function () {
89764                 return interpolate('-100%', '0%');
89765               }).on('end', function () {
89766                 presetPane.classed('hide', true);
89767               });
89768
89769               if (preset) {
89770                 entityEditor.presets([preset]);
89771               }
89772
89773               editorPane.call(entityEditor);
89774             }
89775           };
89776
89777           inspector.state = function (val) {
89778             if (!arguments.length) return _state;
89779             _state = val;
89780             entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
89781
89782             context.container().selectAll('.field-help-body').remove();
89783             return inspector;
89784           };
89785
89786           inspector.entityIDs = function (val) {
89787             if (!arguments.length) return _entityIDs;
89788             _entityIDs = val;
89789             return inspector;
89790           };
89791
89792           inspector.newFeature = function (val) {
89793             if (!arguments.length) return _newFeature;
89794             _newFeature = val;
89795             return inspector;
89796           };
89797
89798           return inspector;
89799         }
89800
89801         function uiSidebar(context) {
89802           var inspector = uiInspector(context);
89803           var dataEditor = uiDataEditor(context);
89804           var noteEditor = uiNoteEditor(context);
89805           var improveOsmEditor = uiImproveOsmEditor(context);
89806           var keepRightEditor = uiKeepRightEditor(context);
89807           var osmoseEditor = uiOsmoseEditor(context);
89808
89809           var _current;
89810
89811           var _wasData = false;
89812           var _wasNote = false;
89813           var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
89814
89815           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
89816
89817           function sidebar(selection) {
89818             var container = context.container();
89819             var minWidth = 240;
89820             var sidebarWidth;
89821             var containerWidth;
89822             var dragOffset; // Set the initial width constraints
89823
89824             selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
89825             var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
89826             var downPointerId, lastClientX, containerLocGetter;
89827
89828             function pointerdown(d3_event) {
89829               if (downPointerId) return;
89830               if ('button' in d3_event && d3_event.button !== 0) return;
89831               downPointerId = d3_event.pointerId || 'mouse';
89832               lastClientX = d3_event.clientX;
89833               containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
89834
89835               dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
89836               sidebarWidth = selection.node().getBoundingClientRect().width;
89837               containerWidth = container.node().getBoundingClientRect().width;
89838               var widthPct = sidebarWidth / containerWidth * 100;
89839               selection.style('width', widthPct + '%') // lock in current width
89840               .style('max-width', '85%'); // but allow larger widths
89841
89842               resizer.classed('dragging', true);
89843               select(window).on('touchmove.sidebar-resizer', function (d3_event) {
89844                 // disable page scrolling while resizing on touch input
89845                 d3_event.preventDefault();
89846               }, {
89847                 passive: false
89848               }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
89849             }
89850
89851             function pointermove(d3_event) {
89852               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
89853               d3_event.preventDefault();
89854               var dx = d3_event.clientX - lastClientX;
89855               lastClientX = d3_event.clientX;
89856               var isRTL = _mainLocalizer.textDirection() === 'rtl';
89857               var scaleX = isRTL ? 0 : 1;
89858               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
89859               var x = containerLocGetter(d3_event)[0] - dragOffset;
89860               sidebarWidth = isRTL ? containerWidth - x : x;
89861               var isCollapsed = selection.classed('collapsed');
89862               var shouldCollapse = sidebarWidth < minWidth;
89863               selection.classed('collapsed', shouldCollapse);
89864
89865               if (shouldCollapse) {
89866                 if (!isCollapsed) {
89867                   selection.style(xMarginProperty, '-400px').style('width', '400px');
89868                   context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
89869                 }
89870               } else {
89871                 var widthPct = sidebarWidth / containerWidth * 100;
89872                 selection.style(xMarginProperty, null).style('width', widthPct + '%');
89873
89874                 if (isCollapsed) {
89875                   context.ui().onResize([-sidebarWidth * scaleX, 0]);
89876                 } else {
89877                   context.ui().onResize([-dx * scaleX, 0]);
89878                 }
89879               }
89880             }
89881
89882             function pointerup(d3_event) {
89883               if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
89884               downPointerId = null;
89885               resizer.classed('dragging', false);
89886               select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
89887             }
89888
89889             var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
89890             var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
89891
89892             var hoverModeSelect = function hoverModeSelect(targets) {
89893               context.container().selectAll('.feature-list-item button').classed('hover', false);
89894
89895               if (context.selectedIDs().length > 1 && targets && targets.length) {
89896                 var elements = context.container().selectAll('.feature-list-item button').filter(function (node) {
89897                   return targets.indexOf(node) !== -1;
89898                 });
89899
89900                 if (!elements.empty()) {
89901                   elements.classed('hover', true);
89902                 }
89903               }
89904             };
89905
89906             sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
89907
89908             function hover(targets) {
89909               var datum = targets && targets.length && targets[0];
89910
89911               if (datum && datum.__featurehash__) {
89912                 // hovering on data
89913                 _wasData = true;
89914                 sidebar.show(dataEditor.datum(datum));
89915                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89916               } else if (datum instanceof osmNote) {
89917                 if (context.mode().id === 'drag-note') return;
89918                 _wasNote = true;
89919                 var osm = services.osm;
89920
89921                 if (osm) {
89922                   datum = osm.getNote(datum.id); // marker may contain stale data - get latest
89923                 }
89924
89925                 sidebar.show(noteEditor.note(datum));
89926                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89927               } else if (datum instanceof QAItem) {
89928                 _wasQaItem = true;
89929                 var errService = services[datum.service];
89930
89931                 if (errService) {
89932                   // marker may contain stale data - get latest
89933                   datum = errService.getError(datum.id);
89934                 } // Currently only three possible services
89935
89936
89937                 var errEditor;
89938
89939                 if (datum.service === 'keepRight') {
89940                   errEditor = keepRightEditor;
89941                 } else if (datum.service === 'osmose') {
89942                   errEditor = osmoseEditor;
89943                 } else {
89944                   errEditor = improveOsmEditor;
89945                 }
89946
89947                 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
89948                   return d.id === datum.id;
89949                 });
89950                 sidebar.show(errEditor.error(datum));
89951                 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
89952               } else if (!_current && datum instanceof osmEntity) {
89953                 featureListWrap.classed('inspector-hidden', true);
89954                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
89955
89956                 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
89957                   inspector.state('hover').entityIDs([datum.id]).newFeature(false);
89958                   inspectorWrap.call(inspector);
89959                 }
89960               } else if (!_current) {
89961                 featureListWrap.classed('inspector-hidden', false);
89962                 inspectorWrap.classed('inspector-hidden', true);
89963                 inspector.state('hide');
89964               } else if (_wasData || _wasNote || _wasQaItem) {
89965                 _wasNote = false;
89966                 _wasData = false;
89967                 _wasQaItem = false;
89968                 context.container().selectAll('.note').classed('hover', false);
89969                 context.container().selectAll('.qaItem').classed('hover', false);
89970                 sidebar.hide();
89971               }
89972             }
89973
89974             sidebar.hover = throttle(hover, 200);
89975
89976             sidebar.intersects = function (extent) {
89977               var rect = selection.node().getBoundingClientRect();
89978               return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
89979             };
89980
89981             sidebar.select = function (ids, newFeature) {
89982               sidebar.hide();
89983
89984               if (ids && ids.length) {
89985                 var entity = ids.length === 1 && context.entity(ids[0]);
89986
89987                 if (entity && newFeature && selection.classed('collapsed')) {
89988                   // uncollapse the sidebar
89989                   var extent = entity.extent(context.graph());
89990                   sidebar.expand(sidebar.intersects(extent));
89991                 }
89992
89993                 featureListWrap.classed('inspector-hidden', true);
89994                 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
89995                 // themselves may have changed
89996
89997                 inspector.state('select').entityIDs(ids).newFeature(newFeature);
89998                 inspectorWrap.call(inspector);
89999               } else {
90000                 inspector.state('hide');
90001               }
90002             };
90003
90004             sidebar.showPresetList = function () {
90005               inspector.showList();
90006             };
90007
90008             sidebar.show = function (component, element) {
90009               featureListWrap.classed('inspector-hidden', true);
90010               inspectorWrap.classed('inspector-hidden', true);
90011               if (_current) _current.remove();
90012               _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
90013             };
90014
90015             sidebar.hide = function () {
90016               featureListWrap.classed('inspector-hidden', false);
90017               inspectorWrap.classed('inspector-hidden', true);
90018               if (_current) _current.remove();
90019               _current = null;
90020             };
90021
90022             sidebar.expand = function (moveMap) {
90023               if (selection.classed('collapsed')) {
90024                 sidebar.toggle(moveMap);
90025               }
90026             };
90027
90028             sidebar.collapse = function (moveMap) {
90029               if (!selection.classed('collapsed')) {
90030                 sidebar.toggle(moveMap);
90031               }
90032             };
90033
90034             sidebar.toggle = function (moveMap) {
90035               // Don't allow sidebar to toggle when the user is in the walkthrough.
90036               if (context.inIntro()) return;
90037               var isCollapsed = selection.classed('collapsed');
90038               var isCollapsing = !isCollapsed;
90039               var isRTL = _mainLocalizer.textDirection() === 'rtl';
90040               var scaleX = isRTL ? 0 : 1;
90041               var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
90042               sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
90043
90044               selection.style('width', sidebarWidth + 'px');
90045               var startMargin, endMargin, lastMargin;
90046
90047               if (isCollapsing) {
90048                 startMargin = lastMargin = 0;
90049                 endMargin = -sidebarWidth;
90050               } else {
90051                 startMargin = lastMargin = -sidebarWidth;
90052                 endMargin = 0;
90053               }
90054
90055               if (!isCollapsing) {
90056                 // unhide the sidebar's content before it transitions onscreen
90057                 selection.classed('collapsed', isCollapsing);
90058               }
90059
90060               selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
90061                 var i = d3_interpolateNumber(startMargin, endMargin);
90062                 return function (t) {
90063                   var dx = lastMargin - Math.round(i(t));
90064                   lastMargin = lastMargin - dx;
90065                   context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
90066                 };
90067               }).on('end', function () {
90068                 if (isCollapsing) {
90069                   // hide the sidebar's content after it transitions offscreen
90070                   selection.classed('collapsed', isCollapsing);
90071                 } // switch back from px to %
90072
90073
90074                 if (!isCollapsing) {
90075                   var containerWidth = container.node().getBoundingClientRect().width;
90076                   var widthPct = sidebarWidth / containerWidth * 100;
90077                   selection.style(xMarginProperty, null).style('width', widthPct + '%');
90078                 }
90079               });
90080             }; // toggle the sidebar collapse when double-clicking the resizer
90081
90082
90083             resizer.on('dblclick', function (d3_event) {
90084               d3_event.preventDefault();
90085
90086               if (d3_event.sourceEvent) {
90087                 d3_event.sourceEvent.preventDefault();
90088               }
90089
90090               sidebar.toggle();
90091             }); // ensure hover sidebar is closed when zooming out beyond editable zoom
90092
90093             context.map().on('crossEditableZoom.sidebar', function (within) {
90094               if (!within && !selection.select('.inspector-hover').empty()) {
90095                 hover([]);
90096               }
90097             });
90098           }
90099
90100           sidebar.showPresetList = function () {};
90101
90102           sidebar.hover = function () {};
90103
90104           sidebar.hover.cancel = function () {};
90105
90106           sidebar.intersects = function () {};
90107
90108           sidebar.select = function () {};
90109
90110           sidebar.show = function () {};
90111
90112           sidebar.hide = function () {};
90113
90114           sidebar.expand = function () {};
90115
90116           sidebar.collapse = function () {};
90117
90118           sidebar.toggle = function () {};
90119
90120           return sidebar;
90121         }
90122
90123         function uiSourceSwitch(context) {
90124           var keys;
90125
90126           function click(d3_event) {
90127             d3_event.preventDefault();
90128             var osm = context.connection();
90129             if (!osm) return;
90130             if (context.inIntro()) return;
90131             if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
90132             var isLive = select(this).classed('live');
90133             isLive = !isLive;
90134             context.enter(modeBrowse(context));
90135             context.history().clearSaved(); // remove saved history
90136
90137             context.flush(); // remove stored data
90138
90139             select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
90140             osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
90141           }
90142
90143           var sourceSwitch = function sourceSwitch(selection) {
90144             selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
90145           };
90146
90147           sourceSwitch.keys = function (_) {
90148             if (!arguments.length) return keys;
90149             keys = _;
90150             return sourceSwitch;
90151           };
90152
90153           return sourceSwitch;
90154         }
90155
90156         function uiSpinner(context) {
90157           var osm = context.connection();
90158           return function (selection) {
90159             var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
90160
90161             if (osm) {
90162               osm.on('loading.spinner', function () {
90163                 img.transition().style('opacity', 1);
90164               }).on('loaded.spinner', function () {
90165                 img.transition().style('opacity', 0);
90166               });
90167             }
90168           };
90169         }
90170
90171         function uiSplash(context) {
90172           return function (selection) {
90173             // Exception - if there are restorable changes, skip this splash screen.
90174             // This is because we currently only support one `uiModal` at a time
90175             //  and we need to show them `uiRestore`` instead of this one.
90176             if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
90177
90178             var updateMessage = '';
90179             var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
90180             var showSplash = !corePreferences('sawSplash');
90181
90182             if (sawPrivacyVersion !== context.privacyVersion) {
90183               updateMessage = _t('splash.privacy_update');
90184               showSplash = true;
90185             }
90186
90187             if (!showSplash) return;
90188             corePreferences('sawSplash', true);
90189             corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
90190
90191             _mainFileFetcher.get('intro_graph');
90192             var modalSelection = uiModal(selection);
90193             modalSelection.select('.modal').attr('class', 'modal-splash modal');
90194             var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
90195             introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
90196             var modalSection = introModal.append('div').attr('class', 'modal-section');
90197             modalSection.append('p').html(_t.html('splash.text', {
90198               version: context.version,
90199               website: '<a target="_blank" href="http://ideditor.blog/">ideditor.blog</a>',
90200               github: '<a target="_blank" href="https://github.com/openstreetmap/iD">github.com</a>'
90201             }));
90202             modalSection.append('p').html(_t.html('splash.privacy', {
90203               updateMessage: updateMessage,
90204               privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
90205             }));
90206             var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
90207             var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
90208               context.container().call(uiIntro(context));
90209               modalSelection.close();
90210             });
90211             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
90212             walkthrough.append('div').html(_t.html('splash.walkthrough'));
90213             var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
90214             startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
90215             startEditing.append('div').html(_t.html('splash.start'));
90216             modalSelection.select('button.close').attr('class', 'hide');
90217           };
90218         }
90219
90220         function uiStatus(context) {
90221           var osm = context.connection();
90222           return function (selection) {
90223             if (!osm) return;
90224
90225             function update(err, apiStatus) {
90226               selection.html('');
90227
90228               if (err) {
90229                 if (apiStatus === 'connectionSwitched') {
90230                   // if the connection was just switched, we can't rely on
90231                   // the status (we're getting the status of the previous api)
90232                   return;
90233                 } else if (apiStatus === 'rateLimited') {
90234                   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) {
90235                     d3_event.preventDefault();
90236                     osm.authenticate();
90237                   });
90238                 } else {
90239                   // don't allow retrying too rapidly
90240                   var throttledRetry = throttle(function () {
90241                     // try loading the visible tiles
90242                     context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
90243
90244                     osm.reloadApiStatus();
90245                   }, 2000); // eslint-disable-next-line no-warning-comments
90246                   // TODO: nice messages for different error types
90247
90248
90249                   selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
90250                   .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
90251                     d3_event.preventDefault();
90252                     throttledRetry();
90253                   });
90254                 }
90255               } else if (apiStatus === 'readonly') {
90256                 selection.html(_t.html('osm_api_status.message.readonly'));
90257               } else if (apiStatus === 'offline') {
90258                 selection.html(_t.html('osm_api_status.message.offline'));
90259               }
90260
90261               selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
90262             }
90263
90264             osm.on('apiStatusChange.uiStatus', update); // reload the status periodically regardless of other factors
90265
90266             window.setInterval(function () {
90267               osm.reloadApiStatus();
90268             }, 90000); // load the initial status in case no OSM data was loaded yet
90269
90270             osm.reloadApiStatus();
90271           };
90272         }
90273
90274         function modeDrawArea(context, wayID, startGraph, button) {
90275           var mode = {
90276             button: button,
90277             id: 'draw-area'
90278           };
90279           var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
90280             context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
90281           });
90282           mode.wayID = wayID;
90283
90284           mode.enter = function () {
90285             context.install(behavior);
90286           };
90287
90288           mode.exit = function () {
90289             context.uninstall(behavior);
90290           };
90291
90292           mode.selectedIDs = function () {
90293             return [wayID];
90294           };
90295
90296           mode.activeID = function () {
90297             return behavior && behavior.activeID() || [];
90298           };
90299
90300           return mode;
90301         }
90302
90303         function modeAddArea(context, mode) {
90304           mode.id = 'add-area';
90305           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
90306           var defaultTags = {
90307             area: 'yes'
90308           };
90309           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
90310
90311           function actionClose(wayId) {
90312             return function (graph) {
90313               return graph.replace(graph.entity(wayId).close());
90314             };
90315           }
90316
90317           function start(loc) {
90318             var startGraph = context.graph();
90319             var node = osmNode({
90320               loc: loc
90321             });
90322             var way = osmWay({
90323               tags: defaultTags
90324             });
90325             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
90326             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90327           }
90328
90329           function startFromWay(loc, edge) {
90330             var startGraph = context.graph();
90331             var node = osmNode({
90332               loc: loc
90333             });
90334             var way = osmWay({
90335               tags: defaultTags
90336             });
90337             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
90338               loc: loc,
90339               edge: edge
90340             }, node));
90341             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90342           }
90343
90344           function startFromNode(node) {
90345             var startGraph = context.graph();
90346             var way = osmWay({
90347               tags: defaultTags
90348             });
90349             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
90350             context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
90351           }
90352
90353           mode.enter = function () {
90354             context.install(behavior);
90355           };
90356
90357           mode.exit = function () {
90358             context.uninstall(behavior);
90359           };
90360
90361           return mode;
90362         }
90363
90364         function modeAddLine(context, mode) {
90365           mode.id = 'add-line';
90366           var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
90367           var defaultTags = {};
90368           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
90369
90370           function start(loc) {
90371             var startGraph = context.graph();
90372             var node = osmNode({
90373               loc: loc
90374             });
90375             var way = osmWay({
90376               tags: defaultTags
90377             });
90378             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
90379             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90380           }
90381
90382           function startFromWay(loc, edge) {
90383             var startGraph = context.graph();
90384             var node = osmNode({
90385               loc: loc
90386             });
90387             var way = osmWay({
90388               tags: defaultTags
90389             });
90390             context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
90391               loc: loc,
90392               edge: edge
90393             }, node));
90394             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90395           }
90396
90397           function startFromNode(node) {
90398             var startGraph = context.graph();
90399             var way = osmWay({
90400               tags: defaultTags
90401             });
90402             context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
90403             context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
90404           }
90405
90406           mode.enter = function () {
90407             context.install(behavior);
90408           };
90409
90410           mode.exit = function () {
90411             context.uninstall(behavior);
90412           };
90413
90414           return mode;
90415         }
90416
90417         function modeAddPoint(context, mode) {
90418           mode.id = 'add-point';
90419           var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
90420           var defaultTags = {};
90421           if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
90422
90423           function add(loc) {
90424             var node = osmNode({
90425               loc: loc,
90426               tags: defaultTags
90427             });
90428             context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
90429             enterSelectMode(node);
90430           }
90431
90432           function addWay(loc, edge) {
90433             var node = osmNode({
90434               tags: defaultTags
90435             });
90436             context.perform(actionAddMidpoint({
90437               loc: loc,
90438               edge: edge
90439             }, node), _t('operations.add.annotation.vertex'));
90440             enterSelectMode(node);
90441           }
90442
90443           function enterSelectMode(node) {
90444             context.enter(modeSelect(context, [node.id]).newFeature(true));
90445           }
90446
90447           function addNode(node) {
90448             if (Object.keys(defaultTags).length === 0) {
90449               enterSelectMode(node);
90450               return;
90451             }
90452
90453             var tags = Object.assign({}, node.tags); // shallow copy
90454
90455             for (var key in defaultTags) {
90456               tags[key] = defaultTags[key];
90457             }
90458
90459             context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
90460             enterSelectMode(node);
90461           }
90462
90463           function cancel() {
90464             context.enter(modeBrowse(context));
90465           }
90466
90467           mode.enter = function () {
90468             context.install(behavior);
90469           };
90470
90471           mode.exit = function () {
90472             context.uninstall(behavior);
90473           };
90474
90475           return mode;
90476         }
90477
90478         function modeAddNote(context) {
90479           var mode = {
90480             id: 'add-note',
90481             button: 'note',
90482             description: _t.html('modes.add_note.description'),
90483             key: _t('modes.add_note.key')
90484           };
90485           var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
90486
90487           function add(loc) {
90488             var osm = services.osm;
90489             if (!osm) return;
90490             var note = osmNote({
90491               loc: loc,
90492               status: 'open',
90493               comments: []
90494             });
90495             osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
90496
90497             context.map().pan([0, 0]);
90498             context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
90499           }
90500
90501           function cancel() {
90502             context.enter(modeBrowse(context));
90503           }
90504
90505           mode.enter = function () {
90506             context.install(behavior);
90507           };
90508
90509           mode.exit = function () {
90510             context.uninstall(behavior);
90511           };
90512
90513           return mode;
90514         }
90515
90516         function uiConflicts(context) {
90517           var dispatch$1 = dispatch('cancel', 'save');
90518           var keybinding = utilKeybinding('conflicts');
90519
90520           var _origChanges;
90521
90522           var _conflictList;
90523
90524           var _shownConflictIndex;
90525
90526           function keybindingOn() {
90527             select(document).call(keybinding.on('⎋', cancel, true));
90528           }
90529
90530           function keybindingOff() {
90531             select(document).call(keybinding.unbind);
90532           }
90533
90534           function tryAgain() {
90535             keybindingOff();
90536             dispatch$1.call('save');
90537           }
90538
90539           function cancel() {
90540             keybindingOff();
90541             dispatch$1.call('cancel');
90542           }
90543
90544           function conflicts(selection) {
90545             keybindingOn();
90546             var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
90547             headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
90548             headerEnter.append('h3').html(_t.html('save.conflict.header'));
90549             var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
90550             var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
90551
90552             var detected = utilDetect();
90553             var changeset = new osmChangeset();
90554             delete changeset.id; // Export without changeset_id
90555
90556             var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
90557             var blob = new Blob([data], {
90558               type: 'text/xml;charset=utf-8;'
90559             });
90560             var fileName = 'changes.osc';
90561             var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
90562
90563             if (detected.download) {
90564               // All except IE11 and Edge
90565               linkEnter // download the data as a file
90566               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90567             } else {
90568               // IE11 and Edge
90569               linkEnter // open data uri in a new tab
90570               .attr('target', '_blank').on('click.download', function () {
90571                 navigator.msSaveBlob(blob, fileName);
90572               });
90573             }
90574
90575             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
90576             bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
90577             bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
90578             var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
90579             buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
90580             buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
90581           }
90582
90583           function showConflict(selection, index) {
90584             index = utilWrap(index, _conflictList.length);
90585             _shownConflictIndex = index;
90586             var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
90587
90588             if (index === _conflictList.length - 1) {
90589               window.setTimeout(function () {
90590                 parent.select('.conflicts-button').attr('disabled', null);
90591                 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
90592               }, 250);
90593             }
90594
90595             var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
90596             conflict.exit().remove();
90597             var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
90598             conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
90599               num: index + 1,
90600               total: _conflictList.length
90601             }));
90602             conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
90603               return d.name;
90604             }).on('click', function (d3_event, d) {
90605               d3_event.preventDefault();
90606               zoomToEntity(d.id);
90607             });
90608             var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
90609             details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
90610               return d.details || [];
90611             }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
90612               return d;
90613             });
90614             details.append('div').attr('class', 'conflict-choices').call(addChoices);
90615             details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
90616               return _t.html('save.conflict.' + d);
90617             }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
90618               return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
90619             }).on('click', function (d3_event, d) {
90620               d3_event.preventDefault();
90621               var container = parent.selectAll('.conflict-container');
90622               var sign = d === 'previous' ? -1 : 1;
90623               container.selectAll('.conflict').remove();
90624               container.call(showConflict, index + sign);
90625             });
90626           }
90627
90628           function addChoices(selection) {
90629             var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
90630               return d.choices || [];
90631             }); // enter
90632
90633             var choicesEnter = choices.enter().append('li').attr('class', 'layer');
90634             var labelEnter = choicesEnter.append('label');
90635             labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
90636               return d.id;
90637             }).on('change', function (d3_event, d) {
90638               var ul = this.parentNode.parentNode.parentNode;
90639               ul.__data__.chosen = d.id;
90640               choose(d3_event, ul, d);
90641             });
90642             labelEnter.append('span').html(function (d) {
90643               return d.text;
90644             }); // update
90645
90646             choicesEnter.merge(choices).each(function (d) {
90647               var ul = this.parentNode;
90648
90649               if (ul.__data__.chosen === d.id) {
90650                 choose(null, ul, d);
90651               }
90652             });
90653           }
90654
90655           function choose(d3_event, ul, datum) {
90656             if (d3_event) d3_event.preventDefault();
90657             select(ul).selectAll('li').classed('active', function (d) {
90658               return d === datum;
90659             }).selectAll('input').property('checked', function (d) {
90660               return d === datum;
90661             });
90662             var extent = geoExtent();
90663             var entity;
90664             entity = context.graph().hasEntity(datum.id);
90665             if (entity) extent._extend(entity.extent(context.graph()));
90666             datum.action();
90667             entity = context.graph().hasEntity(datum.id);
90668             if (entity) extent._extend(entity.extent(context.graph()));
90669             zoomToEntity(datum.id, extent);
90670           }
90671
90672           function zoomToEntity(id, extent) {
90673             context.surface().selectAll('.hover').classed('hover', false);
90674             var entity = context.graph().hasEntity(id);
90675
90676             if (entity) {
90677               if (extent) {
90678                 context.map().trimmedExtent(extent);
90679               } else {
90680                 context.map().zoomToEase(entity);
90681               }
90682
90683               context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90684             }
90685           } // The conflict list should be an array of objects like:
90686           // {
90687           //     id: id,
90688           //     name: entityName(local),
90689           //     details: merge.conflicts(),
90690           //     chosen: 1,
90691           //     choices: [
90692           //         choice(id, keepMine, forceLocal),
90693           //         choice(id, keepTheirs, forceRemote)
90694           //     ]
90695           // }
90696
90697
90698           conflicts.conflictList = function (_) {
90699             if (!arguments.length) return _conflictList;
90700             _conflictList = _;
90701             return conflicts;
90702           };
90703
90704           conflicts.origChanges = function (_) {
90705             if (!arguments.length) return _origChanges;
90706             _origChanges = _;
90707             return conflicts;
90708           };
90709
90710           conflicts.shownEntityIds = function () {
90711             if (_conflictList && typeof _shownConflictIndex === 'number') {
90712               return [_conflictList[_shownConflictIndex].id];
90713             }
90714
90715             return [];
90716           };
90717
90718           return utilRebind(conflicts, dispatch$1, 'on');
90719         }
90720
90721         function uiConfirm(selection) {
90722           var modalSelection = uiModal(selection);
90723           modalSelection.select('.modal').classed('modal-alert', true);
90724           var section = modalSelection.select('.content');
90725           section.append('div').attr('class', 'modal-section header');
90726           section.append('div').attr('class', 'modal-section message-text');
90727           var buttons = section.append('div').attr('class', 'modal-section buttons cf');
90728
90729           modalSelection.okButton = function () {
90730             buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
90731               modalSelection.remove();
90732             }).html(_t.html('confirm.okay')).node().focus();
90733             return modalSelection;
90734           };
90735
90736           return modalSelection;
90737         }
90738
90739         function uiChangesetEditor(context) {
90740           var dispatch$1 = dispatch('change');
90741           var formFields = uiFormFields(context);
90742           var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
90743
90744           var _fieldsArr;
90745
90746           var _tags;
90747
90748           var _changesetID;
90749
90750           function changesetEditor(selection) {
90751             render(selection);
90752           }
90753
90754           function render(selection) {
90755             var initial = false;
90756
90757             if (!_fieldsArr) {
90758               initial = true;
90759               var presets = _mainPresetIndex;
90760               _fieldsArr = [uiField(context, presets.field('comment'), null, {
90761                 show: true,
90762                 revert: false
90763               }), uiField(context, presets.field('source'), null, {
90764                 show: false,
90765                 revert: false
90766               }), uiField(context, presets.field('hashtags'), null, {
90767                 show: false,
90768                 revert: false
90769               })];
90770
90771               _fieldsArr.forEach(function (field) {
90772                 field.on('change', function (t, onInput) {
90773                   dispatch$1.call('change', field, undefined, t, onInput);
90774                 });
90775               });
90776             }
90777
90778             _fieldsArr.forEach(function (field) {
90779               field.tags(_tags);
90780             });
90781
90782             selection.call(formFields.fieldsArr(_fieldsArr));
90783
90784             if (initial) {
90785               var commentField = selection.select('.form-field-comment textarea');
90786               var commentNode = commentField.node();
90787
90788               if (commentNode) {
90789                 commentNode.focus();
90790                 commentNode.select();
90791               } // trigger a 'blur' event so that comment field can be cleaned
90792               // and checked for hashtags, even if retrieved from localstorage
90793
90794
90795               utilTriggerEvent(commentField, 'blur');
90796               var osm = context.connection();
90797
90798               if (osm) {
90799                 osm.userChangesets(function (err, changesets) {
90800                   if (err) return;
90801                   var comments = changesets.map(function (changeset) {
90802                     var comment = changeset.tags.comment;
90803                     return comment ? {
90804                       title: comment,
90805                       value: comment
90806                     } : null;
90807                   }).filter(Boolean);
90808                   commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
90809                 });
90810               }
90811             } // Add warning if comment mentions Google
90812
90813
90814             var hasGoogle = _tags.comment.match(/google/i);
90815
90816             var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
90817             commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
90818             var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
90819             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'));
90820             commentEnter.transition().duration(200).style('opacity', 1);
90821           }
90822
90823           changesetEditor.tags = function (_) {
90824             if (!arguments.length) return _tags;
90825             _tags = _; // Don't reset _fieldsArr here.
90826
90827             return changesetEditor;
90828           };
90829
90830           changesetEditor.changesetID = function (_) {
90831             if (!arguments.length) return _changesetID;
90832             if (_changesetID === _) return changesetEditor;
90833             _changesetID = _;
90834             _fieldsArr = null;
90835             return changesetEditor;
90836           };
90837
90838           return utilRebind(changesetEditor, dispatch$1, 'on');
90839         }
90840
90841         function uiSectionChanges(context) {
90842           var detected = utilDetect();
90843           var _discardTags = {};
90844           _mainFileFetcher.get('discarded').then(function (d) {
90845             _discardTags = d;
90846           })["catch"](function () {
90847             /* ignore */
90848           });
90849           var section = uiSection('changes-list', context).label(function () {
90850             var history = context.history();
90851             var summary = history.difference().summary();
90852             return _t('inspector.title_count', {
90853               title: _t.html('commit.changes'),
90854               count: summary.length
90855             });
90856           }).disclosureContent(renderDisclosureContent);
90857
90858           function renderDisclosureContent(selection) {
90859             var history = context.history();
90860             var summary = history.difference().summary();
90861             var container = selection.selectAll('.commit-section').data([0]);
90862             var containerEnter = container.enter().append('div').attr('class', 'commit-section');
90863             containerEnter.append('ul').attr('class', 'changeset-list');
90864             container = containerEnter.merge(container);
90865             var items = container.select('ul').selectAll('li').data(summary);
90866             var itemsEnter = items.enter().append('li').attr('class', 'change-item');
90867             var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
90868             buttons.each(function (d) {
90869               select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
90870             });
90871             buttons.append('span').attr('class', 'change-type').html(function (d) {
90872               return _t.html('commit.' + d.changeType) + ' ';
90873             });
90874             buttons.append('strong').attr('class', 'entity-type').html(function (d) {
90875               var matched = _mainPresetIndex.match(d.entity, d.graph);
90876               return matched && matched.name() || utilDisplayType(d.entity.id);
90877             });
90878             buttons.append('span').attr('class', 'entity-name').html(function (d) {
90879               var name = utilDisplayName(d.entity) || '',
90880                   string = '';
90881
90882               if (name !== '') {
90883                 string += ':';
90884               }
90885
90886               return string += ' ' + name;
90887             });
90888             items = itemsEnter.merge(items); // Download changeset link
90889
90890             var changeset = new osmChangeset().update({
90891               id: undefined
90892             });
90893             var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
90894             delete changeset.id; // Export without chnageset_id
90895
90896             var data = JXON.stringify(changeset.osmChangeJXON(changes));
90897             var blob = new Blob([data], {
90898               type: 'text/xml;charset=utf-8;'
90899             });
90900             var fileName = 'changes.osc';
90901             var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
90902
90903             if (detected.download) {
90904               // All except IE11 and Edge
90905               linkEnter // download the data as a file
90906               .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
90907             } else {
90908               // IE11 and Edge
90909               linkEnter // open data uri in a new tab
90910               .attr('target', '_blank').on('click.download', function () {
90911                 navigator.msSaveBlob(blob, fileName);
90912               });
90913             }
90914
90915             linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
90916
90917             function mouseover(d) {
90918               if (d.entity) {
90919                 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
90920               }
90921             }
90922
90923             function mouseout() {
90924               context.surface().selectAll('.hover').classed('hover', false);
90925             }
90926
90927             function click(d3_event, change) {
90928               if (change.changeType !== 'deleted') {
90929                 var entity = change.entity;
90930                 context.map().zoomToEase(entity);
90931                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
90932               }
90933             }
90934           }
90935
90936           return section;
90937         }
90938
90939         function uiCommitWarnings(context) {
90940           function commitWarnings(selection) {
90941             var issuesBySeverity = context.validator().getIssuesBySeverity({
90942               what: 'edited',
90943               where: 'all',
90944               includeDisabledRules: true
90945             });
90946
90947             for (var severity in issuesBySeverity) {
90948               var issues = issuesBySeverity[severity];
90949               var section = severity + '-section';
90950               var issueItem = severity + '-item';
90951               var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
90952               container.exit().remove();
90953               var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
90954               containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
90955               containerEnter.append('ul').attr('class', 'changeset-list');
90956               container = containerEnter.merge(container);
90957               var items = container.select('ul').selectAll('li').data(issues, function (d) {
90958                 return d.id;
90959               });
90960               items.exit().remove();
90961               var itemsEnter = items.enter().append('li').attr('class', issueItem);
90962               var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
90963                 if (d.entityIds) {
90964                   context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
90965                 }
90966               }).on('mouseout', function () {
90967                 context.surface().selectAll('.hover').classed('hover', false);
90968               }).on('click', function (d3_event, d) {
90969                 context.validator().focusIssue(d);
90970               });
90971               buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
90972               buttons.append('strong').attr('class', 'issue-message');
90973               buttons.filter(function (d) {
90974                 return d.tooltip;
90975               }).call(uiTooltip().title(function (d) {
90976                 return d.tooltip;
90977               }).placement('top'));
90978               items = itemsEnter.merge(items);
90979               items.selectAll('.issue-message').html(function (d) {
90980                 return d.message(context);
90981               });
90982             }
90983           }
90984
90985           return commitWarnings;
90986         }
90987
90988         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
90989         // from https://stackoverflow.com/a/25575009
90990
90991         var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
90992         function uiCommit(context) {
90993           var dispatch$1 = dispatch('cancel');
90994
90995           var _userDetails;
90996
90997           var _selection;
90998
90999           var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
91000           var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
91001           var commitChanges = uiSectionChanges(context);
91002           var commitWarnings = uiCommitWarnings(context);
91003
91004           function commit(selection) {
91005             _selection = selection; // Initialize changeset if one does not exist yet.
91006
91007             if (!context.changeset) initChangeset();
91008             loadDerivedChangesetTags();
91009             selection.call(render);
91010           }
91011
91012           function initChangeset() {
91013             // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
91014             var commentDate = +corePreferences('commentDate') || 0;
91015             var currDate = Date.now();
91016             var cutoff = 2 * 86400 * 1000; // 2 days
91017
91018             if (commentDate > currDate || currDate - commentDate > cutoff) {
91019               corePreferences('comment', null);
91020               corePreferences('hashtags', null);
91021               corePreferences('source', null);
91022             } // load in explicitly-set values, if any
91023
91024
91025             if (context.defaultChangesetComment()) {
91026               corePreferences('comment', context.defaultChangesetComment());
91027               corePreferences('commentDate', Date.now());
91028             }
91029
91030             if (context.defaultChangesetSource()) {
91031               corePreferences('source', context.defaultChangesetSource());
91032               corePreferences('commentDate', Date.now());
91033             }
91034
91035             if (context.defaultChangesetHashtags()) {
91036               corePreferences('hashtags', context.defaultChangesetHashtags());
91037               corePreferences('commentDate', Date.now());
91038             }
91039
91040             var detected = utilDetect();
91041             var tags = {
91042               comment: corePreferences('comment') || '',
91043               created_by: context.cleanTagValue('iD ' + context.version),
91044               host: context.cleanTagValue(detected.host),
91045               locale: context.cleanTagValue(_mainLocalizer.localeCode())
91046             }; // call findHashtags initially - this will remove stored
91047             // hashtags if any hashtags are found in the comment - #4304
91048
91049             findHashtags(tags, true);
91050             var hashtags = corePreferences('hashtags');
91051
91052             if (hashtags) {
91053               tags.hashtags = hashtags;
91054             }
91055
91056             var source = corePreferences('source');
91057
91058             if (source) {
91059               tags.source = source;
91060             }
91061
91062             var photoOverlaysUsed = context.history().photoOverlaysUsed();
91063
91064             if (photoOverlaysUsed.length) {
91065               var sources = (tags.source || '').split(';'); // include this tag for any photo layer
91066
91067               if (sources.indexOf('streetlevel imagery') === -1) {
91068                 sources.push('streetlevel imagery');
91069               } // add the photo overlays used during editing as sources
91070
91071
91072               photoOverlaysUsed.forEach(function (photoOverlay) {
91073                 if (sources.indexOf(photoOverlay) === -1) {
91074                   sources.push(photoOverlay);
91075                 }
91076               });
91077               tags.source = context.cleanTagValue(sources.join(';'));
91078             }
91079
91080             context.changeset = new osmChangeset({
91081               tags: tags
91082             });
91083           } // Calculates read-only metadata tags based on the user's editing session and applies
91084           // them to the changeset.
91085
91086
91087           function loadDerivedChangesetTags() {
91088             var osm = context.connection();
91089             if (!osm) return;
91090             var tags = Object.assign({}, context.changeset.tags); // shallow copy
91091             // assign tags for imagery used
91092
91093             var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
91094             tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
91095
91096             var osmClosed = osm.getClosedIDs();
91097             var itemType;
91098
91099             if (osmClosed.length) {
91100               tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
91101             }
91102
91103             if (services.keepRight) {
91104               var krClosed = services.keepRight.getClosedIDs();
91105
91106               if (krClosed.length) {
91107                 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
91108               }
91109             }
91110
91111             if (services.improveOSM) {
91112               var iOsmClosed = services.improveOSM.getClosedCounts();
91113
91114               for (itemType in iOsmClosed) {
91115                 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
91116               }
91117             }
91118
91119             if (services.osmose) {
91120               var osmoseClosed = services.osmose.getClosedCounts();
91121
91122               for (itemType in osmoseClosed) {
91123                 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
91124               }
91125             } // remove existing issue counts
91126
91127
91128             for (var key in tags) {
91129               if (key.match(/(^warnings:)|(^resolved:)/)) {
91130                 delete tags[key];
91131               }
91132             }
91133
91134             function addIssueCounts(issues, prefix) {
91135               var issuesByType = utilArrayGroupBy(issues, 'type');
91136
91137               for (var issueType in issuesByType) {
91138                 var issuesOfType = issuesByType[issueType];
91139
91140                 if (issuesOfType[0].subtype) {
91141                   var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
91142
91143                   for (var issueSubtype in issuesBySubtype) {
91144                     var issuesOfSubtype = issuesBySubtype[issueSubtype];
91145                     tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
91146                   }
91147                 } else {
91148                   tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
91149                 }
91150               }
91151             } // add counts of warnings generated by the user's edits
91152
91153
91154             var warnings = context.validator().getIssuesBySeverity({
91155               what: 'edited',
91156               where: 'all',
91157               includeIgnored: true,
91158               includeDisabledRules: true
91159             }).warning;
91160             addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
91161
91162             var resolvedIssues = context.validator().getResolvedIssues();
91163             addIssueCounts(resolvedIssues, 'resolved');
91164             context.changeset = context.changeset.update({
91165               tags: tags
91166             });
91167           }
91168
91169           function render(selection) {
91170             var osm = context.connection();
91171             if (!osm) return;
91172             var header = selection.selectAll('.header').data([0]);
91173             var headerTitle = header.enter().append('div').attr('class', 'header fillL');
91174             headerTitle.append('div').append('h3').html(_t.html('commit.title'));
91175             headerTitle.append('button').attr('class', 'close').on('click', function () {
91176               dispatch$1.call('cancel', this);
91177             }).call(svgIcon('#iD-icon-close'));
91178             var body = selection.selectAll('.body').data([0]);
91179             body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
91180
91181             var changesetSection = body.selectAll('.changeset-editor').data([0]);
91182             changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
91183             changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
91184
91185             body.call(commitWarnings); // Upload Explanation
91186
91187             var saveSection = body.selectAll('.save-section').data([0]);
91188             saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
91189             var prose = saveSection.selectAll('.commit-info').data([0]);
91190
91191             if (prose.enter().size()) {
91192               // first time, make sure to update user details in prose
91193               _userDetails = null;
91194             }
91195
91196             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()
91197             // if needed, because it can trigger a style recalculation
91198
91199             osm.userDetails(function (err, user) {
91200               if (err) return;
91201               if (_userDetails === user) return; // no change
91202
91203               _userDetails = user;
91204               var userLink = select(document.createElement('div'));
91205
91206               if (user.image_url) {
91207                 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
91208               }
91209
91210               userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
91211               prose.html(_t.html('commit.upload_explanation_with_user', {
91212                 user: userLink.html()
91213               }));
91214             }); // Request Review
91215
91216             var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
91217
91218             var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
91219             var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
91220             var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
91221             labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
91222             labelEnter.append('span').html(_t.html('commit.request_review')); // Update
91223
91224             requestReview = requestReview.merge(requestReviewEnter);
91225             var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
91226
91227             var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
91228
91229             var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
91230             buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
91231             var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
91232             uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
91233             var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
91234
91235             buttonSection = buttonSection.merge(buttonEnter);
91236             buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
91237               dispatch$1.call('cancel', this);
91238             });
91239             buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
91240               if (!select(this).classed('disabled')) {
91241                 this.blur(); // avoid keeping focus on the button - #4641
91242
91243                 for (var key in context.changeset.tags) {
91244                   // remove any empty keys before upload
91245                   if (!key) delete context.changeset.tags[key];
91246                 }
91247
91248                 context.uploader().save(context.changeset);
91249               }
91250             }); // remove any existing tooltip
91251
91252             uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
91253
91254             if (uploadBlockerTooltipText) {
91255               buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
91256             } // Raw Tag Editor
91257
91258
91259             var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
91260             tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
91261             tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
91262             .render);
91263             var changesSection = body.selectAll('.commit-changes-section').data([0]);
91264             changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
91265
91266             changesSection.call(commitChanges.render);
91267
91268             function toggleRequestReview() {
91269               var rr = requestReviewInput.property('checked');
91270               updateChangeset({
91271                 review_requested: rr ? 'yes' : undefined
91272               });
91273               tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
91274               .render);
91275             }
91276           }
91277
91278           function getUploadBlockerMessage() {
91279             var errors = context.validator().getIssuesBySeverity({
91280               what: 'edited',
91281               where: 'all'
91282             }).error;
91283
91284             if (errors.length) {
91285               return _t('commit.outstanding_errors_message', {
91286                 count: errors.length
91287               });
91288             } else {
91289               var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
91290
91291               if (!hasChangesetComment) {
91292                 return _t('commit.comment_needed_message');
91293               }
91294             }
91295
91296             return null;
91297           }
91298
91299           function changeTags(_, changed, onInput) {
91300             if (changed.hasOwnProperty('comment')) {
91301               if (changed.comment === undefined) {
91302                 changed.comment = '';
91303               }
91304
91305               if (!onInput) {
91306                 corePreferences('comment', changed.comment);
91307                 corePreferences('commentDate', Date.now());
91308               }
91309             }
91310
91311             if (changed.hasOwnProperty('source')) {
91312               if (changed.source === undefined) {
91313                 corePreferences('source', null);
91314               } else if (!onInput) {
91315                 corePreferences('source', changed.source);
91316                 corePreferences('commentDate', Date.now());
91317               }
91318             } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
91319
91320
91321             updateChangeset(changed, onInput);
91322
91323             if (_selection) {
91324               _selection.call(render);
91325             }
91326           }
91327
91328           function findHashtags(tags, commentOnly) {
91329             var detectedHashtags = commentHashtags();
91330
91331             if (detectedHashtags.length) {
91332               // always remove stored hashtags if there are hashtags in the comment - #4304
91333               corePreferences('hashtags', null);
91334             }
91335
91336             if (!detectedHashtags.length || !commentOnly) {
91337               detectedHashtags = detectedHashtags.concat(hashtagHashtags());
91338             }
91339
91340             var allLowerCase = new Set();
91341             return detectedHashtags.filter(function (hashtag) {
91342               // Compare tags as lowercase strings, but keep original case tags
91343               var lowerCase = hashtag.toLowerCase();
91344
91345               if (!allLowerCase.has(lowerCase)) {
91346                 allLowerCase.add(lowerCase);
91347                 return true;
91348               }
91349
91350               return false;
91351             }); // Extract hashtags from `comment`
91352
91353             function commentHashtags() {
91354               var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
91355               .match(hashtagRegex);
91356               return matches || [];
91357             } // Extract and clean hashtags from `hashtags`
91358
91359
91360             function hashtagHashtags() {
91361               var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
91362                 if (s[0] !== '#') {
91363                   s = '#' + s;
91364                 } // prepend '#'
91365
91366
91367                 var matched = s.match(hashtagRegex);
91368                 return matched && matched[0];
91369               }).filter(Boolean); // exclude falsy
91370
91371               return matches || [];
91372             }
91373           }
91374
91375           function isReviewRequested(tags) {
91376             var rr = tags.review_requested;
91377             if (rr === undefined) return false;
91378             rr = rr.trim().toLowerCase();
91379             return !(rr === '' || rr === 'no');
91380           }
91381
91382           function updateChangeset(changed, onInput) {
91383             var tags = Object.assign({}, context.changeset.tags); // shallow copy
91384
91385             Object.keys(changed).forEach(function (k) {
91386               var v = changed[k];
91387               k = context.cleanTagKey(k);
91388               if (readOnlyTags.indexOf(k) !== -1) return;
91389
91390               if (v === undefined) {
91391                 delete tags[k];
91392               } else if (onInput) {
91393                 tags[k] = v;
91394               } else {
91395                 tags[k] = context.cleanTagValue(v);
91396               }
91397             });
91398
91399             if (!onInput) {
91400               // when changing the comment, override hashtags with any found in comment.
91401               var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
91402               var arr = findHashtags(tags, commentOnly);
91403
91404               if (arr.length) {
91405                 tags.hashtags = context.cleanTagValue(arr.join(';'));
91406                 corePreferences('hashtags', tags.hashtags);
91407               } else {
91408                 delete tags.hashtags;
91409                 corePreferences('hashtags', null);
91410               }
91411             } // always update userdetails, just in case user reauthenticates as someone else
91412
91413
91414             if (_userDetails && _userDetails.changesets_count !== undefined) {
91415               var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
91416
91417               tags.changesets_count = String(changesetsCount); // first 100 edits - new user
91418
91419               if (changesetsCount <= 100) {
91420                 var s;
91421                 s = corePreferences('walkthrough_completed');
91422
91423                 if (s) {
91424                   tags['ideditor:walkthrough_completed'] = s;
91425                 }
91426
91427                 s = corePreferences('walkthrough_progress');
91428
91429                 if (s) {
91430                   tags['ideditor:walkthrough_progress'] = s;
91431                 }
91432
91433                 s = corePreferences('walkthrough_started');
91434
91435                 if (s) {
91436                   tags['ideditor:walkthrough_started'] = s;
91437                 }
91438               }
91439             } else {
91440               delete tags.changesets_count;
91441             }
91442
91443             if (!fastDeepEqual(context.changeset.tags, tags)) {
91444               context.changeset = context.changeset.update({
91445                 tags: tags
91446               });
91447             }
91448           }
91449
91450           commit.reset = function () {
91451             context.changeset = null;
91452           };
91453
91454           return utilRebind(commit, dispatch$1, 'on');
91455         }
91456
91457         var globalIsFinite = global_1.isFinite;
91458
91459         // `Number.isFinite` method
91460         // https://tc39.github.io/ecma262/#sec-number.isfinite
91461         var numberIsFinite = Number.isFinite || function isFinite(it) {
91462           return typeof it == 'number' && globalIsFinite(it);
91463         };
91464
91465         // `Number.isFinite` method
91466         // https://tc39.github.io/ecma262/#sec-number.isfinite
91467         _export({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
91468
91469         var RADIUS = 6378137;
91470         var FLATTENING = 1 / 298.257223563;
91471         var POLAR_RADIUS$1 = 6356752.3142;
91472         var wgs84 = {
91473           RADIUS: RADIUS,
91474           FLATTENING: FLATTENING,
91475           POLAR_RADIUS: POLAR_RADIUS$1
91476         };
91477
91478         var geometry_1 = geometry;
91479         var ring = ringArea;
91480
91481         function geometry(_) {
91482           var area = 0,
91483               i;
91484
91485           switch (_.type) {
91486             case 'Polygon':
91487               return polygonArea(_.coordinates);
91488
91489             case 'MultiPolygon':
91490               for (i = 0; i < _.coordinates.length; i++) {
91491                 area += polygonArea(_.coordinates[i]);
91492               }
91493
91494               return area;
91495
91496             case 'Point':
91497             case 'MultiPoint':
91498             case 'LineString':
91499             case 'MultiLineString':
91500               return 0;
91501
91502             case 'GeometryCollection':
91503               for (i = 0; i < _.geometries.length; i++) {
91504                 area += geometry(_.geometries[i]);
91505               }
91506
91507               return area;
91508           }
91509         }
91510
91511         function polygonArea(coords) {
91512           var area = 0;
91513
91514           if (coords && coords.length > 0) {
91515             area += Math.abs(ringArea(coords[0]));
91516
91517             for (var i = 1; i < coords.length; i++) {
91518               area -= Math.abs(ringArea(coords[i]));
91519             }
91520           }
91521
91522           return area;
91523         }
91524         /**
91525          * Calculate the approximate area of the polygon were it projected onto
91526          *     the earth.  Note that this area will be positive if ring is oriented
91527          *     clockwise, otherwise it will be negative.
91528          *
91529          * Reference:
91530          * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
91531          *     Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
91532          *     Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
91533          *
91534          * Returns:
91535          * {float} The approximate signed geodesic area of the polygon in square
91536          *     meters.
91537          */
91538
91539
91540         function ringArea(coords) {
91541           var p1,
91542               p2,
91543               p3,
91544               lowerIndex,
91545               middleIndex,
91546               upperIndex,
91547               i,
91548               area = 0,
91549               coordsLength = coords.length;
91550
91551           if (coordsLength > 2) {
91552             for (i = 0; i < coordsLength; i++) {
91553               if (i === coordsLength - 2) {
91554                 // i = N-2
91555                 lowerIndex = coordsLength - 2;
91556                 middleIndex = coordsLength - 1;
91557                 upperIndex = 0;
91558               } else if (i === coordsLength - 1) {
91559                 // i = N-1
91560                 lowerIndex = coordsLength - 1;
91561                 middleIndex = 0;
91562                 upperIndex = 1;
91563               } else {
91564                 // i = 0 to N-3
91565                 lowerIndex = i;
91566                 middleIndex = i + 1;
91567                 upperIndex = i + 2;
91568               }
91569
91570               p1 = coords[lowerIndex];
91571               p2 = coords[middleIndex];
91572               p3 = coords[upperIndex];
91573               area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
91574             }
91575
91576             area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
91577           }
91578
91579           return area;
91580         }
91581
91582         function rad(_) {
91583           return _ * Math.PI / 180;
91584         }
91585
91586         var geojsonArea = {
91587           geometry: geometry_1,
91588           ring: ring
91589         };
91590
91591         function toRadians(angleInDegrees) {
91592           return angleInDegrees * Math.PI / 180;
91593         }
91594
91595         function toDegrees(angleInRadians) {
91596           return angleInRadians * 180 / Math.PI;
91597         }
91598
91599         function offset(c1, distance, bearing) {
91600           var lat1 = toRadians(c1[1]);
91601           var lon1 = toRadians(c1[0]);
91602           var dByR = distance / 6378137; // distance divided by 6378137 (radius of the earth) wgs84
91603
91604           var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
91605           var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
91606           return [toDegrees(lon), toDegrees(lat)];
91607         }
91608
91609         function validateCenter(center) {
91610           var validCenterLengths = [2, 3];
91611
91612           if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
91613             throw new Error("ERROR! Center has to be an array of length two or three");
91614           }
91615
91616           var _center = _slicedToArray(center, 2),
91617               lng = _center[0],
91618               lat = _center[1];
91619
91620           if (typeof lng !== "number" || typeof lat !== "number") {
91621             throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
91622           }
91623
91624           if (lng > 180 || lng < -180) {
91625             throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
91626           }
91627
91628           if (lat > 90 || lat < -90) {
91629             throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
91630           }
91631         }
91632
91633         function validateRadius(radius) {
91634           if (typeof radius !== "number") {
91635             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
91636           }
91637
91638           if (radius <= 0) {
91639             throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
91640           }
91641         }
91642
91643         function validateNumberOfSegments(numberOfSegments) {
91644           if (typeof numberOfSegments !== "number" && numberOfSegments !== undefined) {
91645             throw new Error("ERROR! Number of segments has to be a number but was: ".concat(_typeof(numberOfSegments)));
91646           }
91647
91648           if (numberOfSegments < 3) {
91649             throw new Error("ERROR! Number of segments has to be at least 3 but was: ".concat(numberOfSegments));
91650           }
91651         }
91652
91653         function validateInput(_ref) {
91654           var center = _ref.center,
91655               radius = _ref.radius,
91656               numberOfSegments = _ref.numberOfSegments;
91657           validateCenter(center);
91658           validateRadius(radius);
91659           validateNumberOfSegments(numberOfSegments);
91660         }
91661
91662         var circleToPolygon = function circleToPolygon(center, radius, numberOfSegments) {
91663           var n = numberOfSegments ? numberOfSegments : 32; // validateInput() throws error on invalid input and do nothing on valid input
91664
91665           validateInput({
91666             center: center,
91667             radius: radius,
91668             numberOfSegments: numberOfSegments
91669           });
91670           var coordinates = [];
91671
91672           for (var i = 0; i < n; ++i) {
91673             coordinates.push(offset(center, radius, 2 * Math.PI * -i / n));
91674           }
91675
91676           coordinates.push(coordinates[0]);
91677           return {
91678             type: "Polygon",
91679             coordinates: [coordinates]
91680           };
91681         };
91682
91683         // `Number.EPSILON` constant
91684         // https://tc39.github.io/ecma262/#sec-number.epsilon
91685         _export({ target: 'Number', stat: true }, {
91686           EPSILON: Math.pow(2, -52)
91687         });
91688
91689         /**
91690          * splaytree v3.0.1
91691          * Fast Splay tree for Node and browser
91692          *
91693          * @author Alexander Milevski <info@w8r.name>
91694          * @license MIT
91695          * @preserve
91696          */
91697         var Node$1 = function Node(key, data) {
91698           _classCallCheck(this, Node);
91699
91700           this.next = null;
91701           this.key = key;
91702           this.data = data;
91703           this.left = null;
91704           this.right = null;
91705         };
91706         /* follows "An implementation of top-down splaying"
91707          * by D. Sleator <sleator@cs.cmu.edu> March 1992
91708          */
91709
91710
91711         function DEFAULT_COMPARE$1(a, b) {
91712           return a > b ? 1 : a < b ? -1 : 0;
91713         }
91714         /**
91715          * Simple top down splay, not requiring i to be in the tree t.
91716          */
91717
91718
91719         function splay(i, t, comparator) {
91720           var N = new Node$1(null, null);
91721           var l = N;
91722           var r = N;
91723
91724           while (true) {
91725             var cmp = comparator(i, t.key); //if (i < t.key) {
91726
91727             if (cmp < 0) {
91728               if (t.left === null) break; //if (i < t.left.key) {
91729
91730               if (comparator(i, t.left.key) < 0) {
91731                 var y = t.left;
91732                 /* rotate right */
91733
91734                 t.left = y.right;
91735                 y.right = t;
91736                 t = y;
91737                 if (t.left === null) break;
91738               }
91739
91740               r.left = t;
91741               /* link right */
91742
91743               r = t;
91744               t = t.left; //} else if (i > t.key) {
91745             } else if (cmp > 0) {
91746               if (t.right === null) break; //if (i > t.right.key) {
91747
91748               if (comparator(i, t.right.key) > 0) {
91749                 var _y = t.right;
91750                 /* rotate left */
91751
91752                 t.right = _y.left;
91753                 _y.left = t;
91754                 t = _y;
91755                 if (t.right === null) break;
91756               }
91757
91758               l.right = t;
91759               /* link left */
91760
91761               l = t;
91762               t = t.right;
91763             } else break;
91764           }
91765           /* assemble */
91766
91767
91768           l.right = t.left;
91769           r.left = t.right;
91770           t.left = N.right;
91771           t.right = N.left;
91772           return t;
91773         }
91774
91775         function _insert(i, data, t, comparator) {
91776           var node = new Node$1(i, data);
91777
91778           if (t === null) {
91779             node.left = node.right = null;
91780             return node;
91781           }
91782
91783           t = splay(i, t, comparator);
91784           var cmp = comparator(i, t.key);
91785
91786           if (cmp < 0) {
91787             node.left = t.left;
91788             node.right = t;
91789             t.left = null;
91790           } else if (cmp >= 0) {
91791             node.right = t.right;
91792             node.left = t;
91793             t.right = null;
91794           }
91795
91796           return node;
91797         }
91798
91799         function _split(key, v, comparator) {
91800           var left = null;
91801           var right = null;
91802
91803           if (v) {
91804             v = splay(key, v, comparator);
91805             var cmp = comparator(v.key, key);
91806
91807             if (cmp === 0) {
91808               left = v.left;
91809               right = v.right;
91810             } else if (cmp < 0) {
91811               right = v.right;
91812               v.right = null;
91813               left = v;
91814             } else {
91815               left = v.left;
91816               v.left = null;
91817               right = v;
91818             }
91819           }
91820
91821           return {
91822             left: left,
91823             right: right
91824           };
91825         }
91826
91827         function merge$4(left, right, comparator) {
91828           if (right === null) return left;
91829           if (left === null) return right;
91830           right = splay(left.key, right, comparator);
91831           right.left = left;
91832           return right;
91833         }
91834         /**
91835          * Prints level of the tree
91836          */
91837
91838
91839         function printRow(root, prefix, isTail, out, printNode) {
91840           if (root) {
91841             out("".concat(prefix).concat(isTail ? '└── ' : '├── ').concat(printNode(root), "\n"));
91842             var indent = prefix + (isTail ? '    ' : '│   ');
91843             if (root.left) printRow(root.left, indent, false, out, printNode);
91844             if (root.right) printRow(root.right, indent, true, out, printNode);
91845           }
91846         }
91847
91848         var Tree = /*#__PURE__*/function () {
91849           function Tree() {
91850             var comparator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_COMPARE$1;
91851
91852             _classCallCheck(this, Tree);
91853
91854             this._root = null;
91855             this._size = 0;
91856             this._comparator = comparator;
91857           }
91858           /**
91859            * Inserts a key, allows duplicates
91860            */
91861
91862
91863           _createClass(Tree, [{
91864             key: "insert",
91865             value: function insert(key, data) {
91866               this._size++;
91867               return this._root = _insert(key, data, this._root, this._comparator);
91868             }
91869             /**
91870              * Adds a key, if it is not present in the tree
91871              */
91872
91873           }, {
91874             key: "add",
91875             value: function add(key, data) {
91876               var node = new Node$1(key, data);
91877
91878               if (this._root === null) {
91879                 node.left = node.right = null;
91880                 this._size++;
91881                 this._root = node;
91882               }
91883
91884               var comparator = this._comparator;
91885               var t = splay(key, this._root, comparator);
91886               var cmp = comparator(key, t.key);
91887               if (cmp === 0) this._root = t;else {
91888                 if (cmp < 0) {
91889                   node.left = t.left;
91890                   node.right = t;
91891                   t.left = null;
91892                 } else if (cmp > 0) {
91893                   node.right = t.right;
91894                   node.left = t;
91895                   t.right = null;
91896                 }
91897
91898                 this._size++;
91899                 this._root = node;
91900               }
91901               return this._root;
91902             }
91903             /**
91904              * @param  {Key} key
91905              * @return {Node|null}
91906              */
91907
91908           }, {
91909             key: "remove",
91910             value: function remove(key) {
91911               this._root = this._remove(key, this._root, this._comparator);
91912             }
91913             /**
91914              * Deletes i from the tree if it's there
91915              */
91916
91917           }, {
91918             key: "_remove",
91919             value: function _remove(i, t, comparator) {
91920               var x;
91921               if (t === null) return null;
91922               t = splay(i, t, comparator);
91923               var cmp = comparator(i, t.key);
91924
91925               if (cmp === 0) {
91926                 /* found it */
91927                 if (t.left === null) {
91928                   x = t.right;
91929                 } else {
91930                   x = splay(i, t.left, comparator);
91931                   x.right = t.right;
91932                 }
91933
91934                 this._size--;
91935                 return x;
91936               }
91937
91938               return t;
91939               /* It wasn't there */
91940             }
91941             /**
91942              * Removes and returns the node with smallest key
91943              */
91944
91945           }, {
91946             key: "pop",
91947             value: function pop() {
91948               var node = this._root;
91949
91950               if (node) {
91951                 while (node.left) {
91952                   node = node.left;
91953                 }
91954
91955                 this._root = splay(node.key, this._root, this._comparator);
91956                 this._root = this._remove(node.key, this._root, this._comparator);
91957                 return {
91958                   key: node.key,
91959                   data: node.data
91960                 };
91961               }
91962
91963               return null;
91964             }
91965             /**
91966              * Find without splaying
91967              */
91968
91969           }, {
91970             key: "findStatic",
91971             value: function findStatic(key) {
91972               var current = this._root;
91973               var compare = this._comparator;
91974
91975               while (current) {
91976                 var cmp = compare(key, current.key);
91977                 if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
91978               }
91979
91980               return null;
91981             }
91982           }, {
91983             key: "find",
91984             value: function find(key) {
91985               if (this._root) {
91986                 this._root = splay(key, this._root, this._comparator);
91987                 if (this._comparator(key, this._root.key) !== 0) return null;
91988               }
91989
91990               return this._root;
91991             }
91992           }, {
91993             key: "contains",
91994             value: function contains(key) {
91995               var current = this._root;
91996               var compare = this._comparator;
91997
91998               while (current) {
91999                 var cmp = compare(key, current.key);
92000                 if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
92001               }
92002
92003               return false;
92004             }
92005           }, {
92006             key: "forEach",
92007             value: function forEach(visitor, ctx) {
92008               var current = this._root;
92009               var Q = [];
92010               /* Initialize stack s */
92011
92012               var done = false;
92013
92014               while (!done) {
92015                 if (current !== null) {
92016                   Q.push(current);
92017                   current = current.left;
92018                 } else {
92019                   if (Q.length !== 0) {
92020                     current = Q.pop();
92021                     visitor.call(ctx, current);
92022                     current = current.right;
92023                   } else done = true;
92024                 }
92025               }
92026
92027               return this;
92028             }
92029             /**
92030              * Walk key range from `low` to `high`. Stops if `fn` returns a value.
92031              */
92032
92033           }, {
92034             key: "range",
92035             value: function range(low, high, fn, ctx) {
92036               var Q = [];
92037               var compare = this._comparator;
92038               var node = this._root;
92039               var cmp;
92040
92041               while (Q.length !== 0 || node) {
92042                 if (node) {
92043                   Q.push(node);
92044                   node = node.left;
92045                 } else {
92046                   node = Q.pop();
92047                   cmp = compare(node.key, high);
92048
92049                   if (cmp > 0) {
92050                     break;
92051                   } else if (compare(node.key, low) >= 0) {
92052                     if (fn.call(ctx, node)) return this; // stop if smth is returned
92053                   }
92054
92055                   node = node.right;
92056                 }
92057               }
92058
92059               return this;
92060             }
92061             /**
92062              * Returns array of keys
92063              */
92064
92065           }, {
92066             key: "keys",
92067             value: function keys() {
92068               var keys = [];
92069               this.forEach(function (_ref) {
92070                 var key = _ref.key;
92071                 return keys.push(key);
92072               });
92073               return keys;
92074             }
92075             /**
92076              * Returns array of all the data in the nodes
92077              */
92078
92079           }, {
92080             key: "values",
92081             value: function values() {
92082               var values = [];
92083               this.forEach(function (_ref2) {
92084                 var data = _ref2.data;
92085                 return values.push(data);
92086               });
92087               return values;
92088             }
92089           }, {
92090             key: "min",
92091             value: function min() {
92092               if (this._root) return this.minNode(this._root).key;
92093               return null;
92094             }
92095           }, {
92096             key: "max",
92097             value: function max() {
92098               if (this._root) return this.maxNode(this._root).key;
92099               return null;
92100             }
92101           }, {
92102             key: "minNode",
92103             value: function minNode() {
92104               var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
92105               if (t) while (t.left) {
92106                 t = t.left;
92107               }
92108               return t;
92109             }
92110           }, {
92111             key: "maxNode",
92112             value: function maxNode() {
92113               var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._root;
92114               if (t) while (t.right) {
92115                 t = t.right;
92116               }
92117               return t;
92118             }
92119             /**
92120              * Returns node at given index
92121              */
92122
92123           }, {
92124             key: "at",
92125             value: function at(index) {
92126               var current = this._root;
92127               var done = false;
92128               var i = 0;
92129               var Q = [];
92130
92131               while (!done) {
92132                 if (current) {
92133                   Q.push(current);
92134                   current = current.left;
92135                 } else {
92136                   if (Q.length > 0) {
92137                     current = Q.pop();
92138                     if (i === index) return current;
92139                     i++;
92140                     current = current.right;
92141                   } else done = true;
92142                 }
92143               }
92144
92145               return null;
92146             }
92147           }, {
92148             key: "next",
92149             value: function next(d) {
92150               var root = this._root;
92151               var successor = null;
92152
92153               if (d.right) {
92154                 successor = d.right;
92155
92156                 while (successor.left) {
92157                   successor = successor.left;
92158                 }
92159
92160                 return successor;
92161               }
92162
92163               var comparator = this._comparator;
92164
92165               while (root) {
92166                 var cmp = comparator(d.key, root.key);
92167                 if (cmp === 0) break;else if (cmp < 0) {
92168                   successor = root;
92169                   root = root.left;
92170                 } else root = root.right;
92171               }
92172
92173               return successor;
92174             }
92175           }, {
92176             key: "prev",
92177             value: function prev(d) {
92178               var root = this._root;
92179               var predecessor = null;
92180
92181               if (d.left !== null) {
92182                 predecessor = d.left;
92183
92184                 while (predecessor.right) {
92185                   predecessor = predecessor.right;
92186                 }
92187
92188                 return predecessor;
92189               }
92190
92191               var comparator = this._comparator;
92192
92193               while (root) {
92194                 var cmp = comparator(d.key, root.key);
92195                 if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
92196                   predecessor = root;
92197                   root = root.right;
92198                 }
92199               }
92200
92201               return predecessor;
92202             }
92203           }, {
92204             key: "clear",
92205             value: function clear() {
92206               this._root = null;
92207               this._size = 0;
92208               return this;
92209             }
92210           }, {
92211             key: "toList",
92212             value: function toList() {
92213               return _toList(this._root);
92214             }
92215             /**
92216              * Bulk-load items. Both array have to be same size
92217              */
92218
92219           }, {
92220             key: "load",
92221             value: function load(keys) {
92222               var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
92223               var presort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
92224               var size = keys.length;
92225               var comparator = this._comparator; // sort if needed
92226
92227               if (presort) sort$1(keys, values, 0, size - 1, comparator);
92228
92229               if (this._root === null) {
92230                 // empty tree
92231                 this._root = loadRecursive$1(keys, values, 0, size);
92232                 this._size = size;
92233               } else {
92234                 // that re-builds the whole tree from two in-order traversals
92235                 var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
92236                 size = this._size + size;
92237                 this._root = sortedListToBST({
92238                   head: mergedList
92239                 }, 0, size);
92240               }
92241
92242               return this;
92243             }
92244           }, {
92245             key: "isEmpty",
92246             value: function isEmpty() {
92247               return this._root === null;
92248             }
92249           }, {
92250             key: "toString",
92251             value: function toString() {
92252               var printNode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function (n) {
92253                 return String(n.key);
92254               };
92255               var out = [];
92256               printRow(this._root, '', true, function (v) {
92257                 return out.push(v);
92258               }, printNode);
92259               return out.join('');
92260             }
92261           }, {
92262             key: "update",
92263             value: function update(key, newKey, newData) {
92264               var comparator = this._comparator;
92265
92266               var _split2 = _split(key, this._root, comparator),
92267                   left = _split2.left,
92268                   right = _split2.right;
92269
92270               if (comparator(key, newKey) < 0) {
92271                 right = _insert(newKey, newData, right, comparator);
92272               } else {
92273                 left = _insert(newKey, newData, left, comparator);
92274               }
92275
92276               this._root = merge$4(left, right, comparator);
92277             }
92278           }, {
92279             key: "split",
92280             value: function split(key) {
92281               return _split(key, this._root, this._comparator);
92282             }
92283           }, {
92284             key: "size",
92285             get: function get() {
92286               return this._size;
92287             }
92288           }, {
92289             key: "root",
92290             get: function get() {
92291               return this._root;
92292             }
92293           }]);
92294
92295           return Tree;
92296         }();
92297
92298         function loadRecursive$1(keys, values, start, end) {
92299           var size = end - start;
92300
92301           if (size > 0) {
92302             var middle = start + Math.floor(size / 2);
92303             var key = keys[middle];
92304             var data = values[middle];
92305             var node = new Node$1(key, data);
92306             node.left = loadRecursive$1(keys, values, start, middle);
92307             node.right = loadRecursive$1(keys, values, middle + 1, end);
92308             return node;
92309           }
92310
92311           return null;
92312         }
92313
92314         function createList(keys, values) {
92315           var head = new Node$1(null, null);
92316           var p = head;
92317
92318           for (var i = 0; i < keys.length; i++) {
92319             p = p.next = new Node$1(keys[i], values[i]);
92320           }
92321
92322           p.next = null;
92323           return head.next;
92324         }
92325
92326         function _toList(root) {
92327           var current = root;
92328           var Q = [];
92329           var done = false;
92330           var head = new Node$1(null, null);
92331           var p = head;
92332
92333           while (!done) {
92334             if (current) {
92335               Q.push(current);
92336               current = current.left;
92337             } else {
92338               if (Q.length > 0) {
92339                 current = p = p.next = Q.pop();
92340                 current = current.right;
92341               } else done = true;
92342             }
92343           }
92344
92345           p.next = null; // that'll work even if the tree was empty
92346
92347           return head.next;
92348         }
92349
92350         function sortedListToBST(list, start, end) {
92351           var size = end - start;
92352
92353           if (size > 0) {
92354             var middle = start + Math.floor(size / 2);
92355             var left = sortedListToBST(list, start, middle);
92356             var root = list.head;
92357             root.left = left;
92358             list.head = list.head.next;
92359             root.right = sortedListToBST(list, middle + 1, end);
92360             return root;
92361           }
92362
92363           return null;
92364         }
92365
92366         function mergeLists(l1, l2, compare) {
92367           var head = new Node$1(null, null); // dummy
92368
92369           var p = head;
92370           var p1 = l1;
92371           var p2 = l2;
92372
92373           while (p1 !== null && p2 !== null) {
92374             if (compare(p1.key, p2.key) < 0) {
92375               p.next = p1;
92376               p1 = p1.next;
92377             } else {
92378               p.next = p2;
92379               p2 = p2.next;
92380             }
92381
92382             p = p.next;
92383           }
92384
92385           if (p1 !== null) {
92386             p.next = p1;
92387           } else if (p2 !== null) {
92388             p.next = p2;
92389           }
92390
92391           return head.next;
92392         }
92393
92394         function sort$1(keys, values, left, right, compare) {
92395           if (left >= right) return;
92396           var pivot = keys[left + right >> 1];
92397           var i = left - 1;
92398           var j = right + 1;
92399
92400           while (true) {
92401             do {
92402               i++;
92403             } while (compare(keys[i], pivot) < 0);
92404
92405             do {
92406               j--;
92407             } while (compare(keys[j], pivot) > 0);
92408
92409             if (i >= j) break;
92410             var tmp = keys[i];
92411             keys[i] = keys[j];
92412             keys[j] = tmp;
92413             tmp = values[i];
92414             values[i] = values[j];
92415             values[j] = tmp;
92416           }
92417
92418           sort$1(keys, values, left, j, compare);
92419           sort$1(keys, values, j + 1, right, compare);
92420         }
92421
92422         function _classCallCheck$1(instance, Constructor) {
92423           if (!(instance instanceof Constructor)) {
92424             throw new TypeError("Cannot call a class as a function");
92425           }
92426         }
92427
92428         function _defineProperties$1(target, props) {
92429           for (var i = 0; i < props.length; i++) {
92430             var descriptor = props[i];
92431             descriptor.enumerable = descriptor.enumerable || false;
92432             descriptor.configurable = true;
92433             if ("value" in descriptor) descriptor.writable = true;
92434             Object.defineProperty(target, descriptor.key, descriptor);
92435           }
92436         }
92437
92438         function _createClass$1(Constructor, protoProps, staticProps) {
92439           if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
92440           if (staticProps) _defineProperties$1(Constructor, staticProps);
92441           return Constructor;
92442         }
92443         /**
92444          * A bounding box has the format:
92445          *
92446          *  { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
92447          *
92448          */
92449
92450
92451         var isInBbox = function isInBbox(bbox, point) {
92452           return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
92453         };
92454         /* Returns either null, or a bbox (aka an ordered pair of points)
92455          * If there is only one point of overlap, a bbox with identical points
92456          * will be returned */
92457
92458
92459         var getBboxOverlap = function getBboxOverlap(b1, b2) {
92460           // check if the bboxes overlap at all
92461           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
92462
92463           var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
92464           var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
92465
92466           var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
92467           var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
92468
92469           return {
92470             ll: {
92471               x: lowerX,
92472               y: lowerY
92473             },
92474             ur: {
92475               x: upperX,
92476               y: upperY
92477             }
92478           };
92479         };
92480         /* Javascript doesn't do integer math. Everything is
92481          * floating point with percision Number.EPSILON.
92482          *
92483          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
92484          */
92485
92486
92487         var epsilon$2 = Number.EPSILON; // IE Polyfill
92488
92489         if (epsilon$2 === undefined) epsilon$2 = Math.pow(2, -52);
92490         var EPSILON_SQ = epsilon$2 * epsilon$2;
92491         /* FLP comparator */
92492
92493         var cmp = function cmp(a, b) {
92494           // check if they're both 0
92495           if (-epsilon$2 < a && a < epsilon$2) {
92496             if (-epsilon$2 < b && b < epsilon$2) {
92497               return 0;
92498             }
92499           } // check if they're flp equal
92500
92501
92502           var ab = a - b;
92503
92504           if (ab * ab < EPSILON_SQ * a * b) {
92505             return 0;
92506           } // normal comparison
92507
92508
92509           return a < b ? -1 : 1;
92510         };
92511         /**
92512          * This class rounds incoming values sufficiently so that
92513          * floating points problems are, for the most part, avoided.
92514          *
92515          * Incoming points are have their x & y values tested against
92516          * all previously seen x & y values. If either is 'too close'
92517          * to a previously seen value, it's value is 'snapped' to the
92518          * previously seen value.
92519          *
92520          * All points should be rounded by this class before being
92521          * stored in any data structures in the rest of this algorithm.
92522          */
92523
92524
92525         var PtRounder = /*#__PURE__*/function () {
92526           function PtRounder() {
92527             _classCallCheck$1(this, PtRounder);
92528
92529             this.reset();
92530           }
92531
92532           _createClass$1(PtRounder, [{
92533             key: "reset",
92534             value: function reset() {
92535               this.xRounder = new CoordRounder();
92536               this.yRounder = new CoordRounder();
92537             }
92538           }, {
92539             key: "round",
92540             value: function round(x, y) {
92541               return {
92542                 x: this.xRounder.round(x),
92543                 y: this.yRounder.round(y)
92544               };
92545             }
92546           }]);
92547
92548           return PtRounder;
92549         }();
92550
92551         var CoordRounder = /*#__PURE__*/function () {
92552           function CoordRounder() {
92553             _classCallCheck$1(this, CoordRounder);
92554
92555             this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
92556
92557             this.round(0);
92558           } // Note: this can rounds input values backwards or forwards.
92559           //       You might ask, why not restrict this to just rounding
92560           //       forwards? Wouldn't that allow left endpoints to always
92561           //       remain left endpoints during splitting (never change to
92562           //       right). No - it wouldn't, because we snap intersections
92563           //       to endpoints (to establish independence from the segment
92564           //       angle for t-intersections).
92565
92566
92567           _createClass$1(CoordRounder, [{
92568             key: "round",
92569             value: function round(coord) {
92570               var node = this.tree.add(coord);
92571               var prevNode = this.tree.prev(node);
92572
92573               if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
92574                 this.tree.remove(coord);
92575                 return prevNode.key;
92576               }
92577
92578               var nextNode = this.tree.next(node);
92579
92580               if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
92581                 this.tree.remove(coord);
92582                 return nextNode.key;
92583               }
92584
92585               return coord;
92586             }
92587           }]);
92588
92589           return CoordRounder;
92590         }(); // singleton available by import
92591
92592
92593         var rounder = new PtRounder();
92594         /* Cross Product of two vectors with first point at origin */
92595
92596         var crossProduct$1 = function crossProduct(a, b) {
92597           return a.x * b.y - a.y * b.x;
92598         };
92599         /* Dot Product of two vectors with first point at origin */
92600
92601
92602         var dotProduct$1 = function dotProduct(a, b) {
92603           return a.x * b.x + a.y * b.y;
92604         };
92605         /* Comparator for two vectors with same starting point */
92606
92607
92608         var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
92609           var v1 = {
92610             x: endPt1.x - basePt.x,
92611             y: endPt1.y - basePt.y
92612           };
92613           var v2 = {
92614             x: endPt2.x - basePt.x,
92615             y: endPt2.y - basePt.y
92616           };
92617           var kross = crossProduct$1(v1, v2);
92618           return cmp(kross, 0);
92619         };
92620
92621         var length = function length(v) {
92622           return Math.sqrt(dotProduct$1(v, v));
92623         };
92624         /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
92625
92626
92627         var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
92628           var vBase = {
92629             x: pBase.x - pShared.x,
92630             y: pBase.y - pShared.y
92631           };
92632           var vAngle = {
92633             x: pAngle.x - pShared.x,
92634             y: pAngle.y - pShared.y
92635           };
92636           return crossProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
92637         };
92638         /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
92639
92640
92641         var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
92642           var vBase = {
92643             x: pBase.x - pShared.x,
92644             y: pBase.y - pShared.y
92645           };
92646           var vAngle = {
92647             x: pAngle.x - pShared.x,
92648             y: pAngle.y - pShared.y
92649           };
92650           return dotProduct$1(vAngle, vBase) / length(vAngle) / length(vBase);
92651         };
92652         /* Get the x coordinate where the given line (defined by a point and vector)
92653          * crosses the horizontal line with the given y coordiante.
92654          * In the case of parrallel lines (including overlapping ones) returns null. */
92655
92656
92657         var horizontalIntersection = function horizontalIntersection(pt, v, y) {
92658           if (v.y === 0) return null;
92659           return {
92660             x: pt.x + v.x / v.y * (y - pt.y),
92661             y: y
92662           };
92663         };
92664         /* Get the y coordinate where the given line (defined by a point and vector)
92665          * crosses the vertical line with the given x coordiante.
92666          * In the case of parrallel lines (including overlapping ones) returns null. */
92667
92668
92669         var verticalIntersection = function verticalIntersection(pt, v, x) {
92670           if (v.x === 0) return null;
92671           return {
92672             x: x,
92673             y: pt.y + v.y / v.x * (x - pt.x)
92674           };
92675         };
92676         /* Get the intersection of two lines, each defined by a base point and a vector.
92677          * In the case of parrallel lines (including overlapping ones) returns null. */
92678
92679
92680         var intersection$1 = function intersection(pt1, v1, pt2, v2) {
92681           // take some shortcuts for vertical and horizontal lines
92682           // this also ensures we don't calculate an intersection and then discover
92683           // it's actually outside the bounding box of the line
92684           if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
92685           if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
92686           if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
92687           if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
92688           // This algorithm is based on Schneider and Eberly.
92689           // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
92690
92691           var kross = crossProduct$1(v1, v2);
92692           if (kross == 0) return null;
92693           var ve = {
92694             x: pt2.x - pt1.x,
92695             y: pt2.y - pt1.y
92696           };
92697           var d1 = crossProduct$1(ve, v1) / kross;
92698           var d2 = crossProduct$1(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
92699
92700           var x1 = pt1.x + d2 * v1.x,
92701               x2 = pt2.x + d1 * v2.x;
92702           var y1 = pt1.y + d2 * v1.y,
92703               y2 = pt2.y + d1 * v2.y;
92704           var x = (x1 + x2) / 2;
92705           var y = (y1 + y2) / 2;
92706           return {
92707             x: x,
92708             y: y
92709           };
92710         };
92711
92712         var SweepEvent$1 = /*#__PURE__*/function () {
92713           _createClass$1(SweepEvent, null, [{
92714             key: "compare",
92715             // for ordering sweep events in the sweep event queue
92716             value: function compare(a, b) {
92717               // favor event with a point that the sweep line hits first
92718               var ptCmp = SweepEvent.comparePoints(a.point, b.point);
92719               if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
92720
92721               if (a.point !== b.point) a.link(b); // favor right events over left
92722
92723               if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
92724               // ordering of this case is the same as for their segments
92725
92726               return Segment.compare(a.segment, b.segment);
92727             } // for ordering points in sweep line order
92728
92729           }, {
92730             key: "comparePoints",
92731             value: function comparePoints(aPt, bPt) {
92732               if (aPt.x < bPt.x) return -1;
92733               if (aPt.x > bPt.x) return 1;
92734               if (aPt.y < bPt.y) return -1;
92735               if (aPt.y > bPt.y) return 1;
92736               return 0;
92737             } // Warning: 'point' input will be modified and re-used (for performance)
92738
92739           }]);
92740
92741           function SweepEvent(point, isLeft) {
92742             _classCallCheck$1(this, SweepEvent);
92743
92744             if (point.events === undefined) point.events = [this];else point.events.push(this);
92745             this.point = point;
92746             this.isLeft = isLeft; // this.segment, this.otherSE set by factory
92747           }
92748
92749           _createClass$1(SweepEvent, [{
92750             key: "link",
92751             value: function link(other) {
92752               if (other.point === this.point) {
92753                 throw new Error('Tried to link already linked events');
92754               }
92755
92756               var otherEvents = other.point.events;
92757
92758               for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
92759                 var evt = otherEvents[i];
92760                 this.point.events.push(evt);
92761                 evt.point = this.point;
92762               }
92763
92764               this.checkForConsuming();
92765             }
92766             /* Do a pass over our linked events and check to see if any pair
92767              * of segments match, and should be consumed. */
92768
92769           }, {
92770             key: "checkForConsuming",
92771             value: function checkForConsuming() {
92772               // FIXME: The loops in this method run O(n^2) => no good.
92773               //        Maintain little ordered sweep event trees?
92774               //        Can we maintaining an ordering that avoids the need
92775               //        for the re-sorting with getLeftmostComparator in geom-out?
92776               // Compare each pair of events to see if other events also match
92777               var numEvents = this.point.events.length;
92778
92779               for (var i = 0; i < numEvents; i++) {
92780                 var evt1 = this.point.events[i];
92781                 if (evt1.segment.consumedBy !== undefined) continue;
92782
92783                 for (var j = i + 1; j < numEvents; j++) {
92784                   var evt2 = this.point.events[j];
92785                   if (evt2.consumedBy !== undefined) continue;
92786                   if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
92787                   evt1.segment.consume(evt2.segment);
92788                 }
92789               }
92790             }
92791           }, {
92792             key: "getAvailableLinkedEvents",
92793             value: function getAvailableLinkedEvents() {
92794               // point.events is always of length 2 or greater
92795               var events = [];
92796
92797               for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
92798                 var evt = this.point.events[i];
92799
92800                 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
92801                   events.push(evt);
92802                 }
92803               }
92804
92805               return events;
92806             }
92807             /**
92808              * Returns a comparator function for sorting linked events that will
92809              * favor the event that will give us the smallest left-side angle.
92810              * All ring construction starts as low as possible heading to the right,
92811              * so by always turning left as sharp as possible we'll get polygons
92812              * without uncessary loops & holes.
92813              *
92814              * The comparator function has a compute cache such that it avoids
92815              * re-computing already-computed values.
92816              */
92817
92818           }, {
92819             key: "getLeftmostComparator",
92820             value: function getLeftmostComparator(baseEvent) {
92821               var _this = this;
92822
92823               var cache = new Map();
92824
92825               var fillCache = function fillCache(linkedEvent) {
92826                 var nextEvent = linkedEvent.otherSE;
92827                 cache.set(linkedEvent, {
92828                   sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
92829                   cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
92830                 });
92831               };
92832
92833               return function (a, b) {
92834                 if (!cache.has(a)) fillCache(a);
92835                 if (!cache.has(b)) fillCache(b);
92836
92837                 var _cache$get = cache.get(a),
92838                     asine = _cache$get.sine,
92839                     acosine = _cache$get.cosine;
92840
92841                 var _cache$get2 = cache.get(b),
92842                     bsine = _cache$get2.sine,
92843                     bcosine = _cache$get2.cosine; // both on or above x-axis
92844
92845
92846                 if (asine >= 0 && bsine >= 0) {
92847                   if (acosine < bcosine) return 1;
92848                   if (acosine > bcosine) return -1;
92849                   return 0;
92850                 } // both below x-axis
92851
92852
92853                 if (asine < 0 && bsine < 0) {
92854                   if (acosine < bcosine) return -1;
92855                   if (acosine > bcosine) return 1;
92856                   return 0;
92857                 } // one above x-axis, one below
92858
92859
92860                 if (bsine < asine) return -1;
92861                 if (bsine > asine) return 1;
92862                 return 0;
92863               };
92864             }
92865           }]);
92866
92867           return SweepEvent;
92868         }(); // segments and sweep events when all else is identical
92869
92870
92871         var segmentId = 0;
92872
92873         var Segment = /*#__PURE__*/function () {
92874           _createClass$1(Segment, null, [{
92875             key: "compare",
92876
92877             /* This compare() function is for ordering segments in the sweep
92878              * line tree, and does so according to the following criteria:
92879              *
92880              * Consider the vertical line that lies an infinestimal step to the
92881              * right of the right-more of the two left endpoints of the input
92882              * segments. Imagine slowly moving a point up from negative infinity
92883              * in the increasing y direction. Which of the two segments will that
92884              * point intersect first? That segment comes 'before' the other one.
92885              *
92886              * If neither segment would be intersected by such a line, (if one
92887              * or more of the segments are vertical) then the line to be considered
92888              * is directly on the right-more of the two left inputs.
92889              */
92890             value: function compare(a, b) {
92891               var alx = a.leftSE.point.x;
92892               var blx = b.leftSE.point.x;
92893               var arx = a.rightSE.point.x;
92894               var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
92895
92896               if (brx < alx) return 1;
92897               if (arx < blx) return -1;
92898               var aly = a.leftSE.point.y;
92899               var bly = b.leftSE.point.y;
92900               var ary = a.rightSE.point.y;
92901               var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
92902
92903               if (alx < blx) {
92904                 // are the two segments in the same horizontal plane?
92905                 if (bly < aly && bly < ary) return 1;
92906                 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
92907
92908                 var aCmpBLeft = a.comparePoint(b.leftSE.point);
92909                 if (aCmpBLeft < 0) return 1;
92910                 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
92911
92912                 var bCmpARight = b.comparePoint(a.rightSE.point);
92913                 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
92914                 // left endpoint to be first (arbitrary?)
92915
92916                 return -1;
92917               } // is left endpoint of segment A the right-more?
92918
92919
92920               if (alx > blx) {
92921                 if (aly < bly && aly < bry) return -1;
92922                 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
92923
92924                 var bCmpALeft = b.comparePoint(a.leftSE.point);
92925                 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
92926
92927                 var aCmpBRight = a.comparePoint(b.rightSE.point);
92928                 if (aCmpBRight < 0) return 1;
92929                 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
92930                 // left endpoint to be first (arbitrary?)
92931
92932                 return 1;
92933               } // if we get here, the two left endpoints are in the same
92934               // vertical plane, ie alx === blx
92935               // consider the lower left-endpoint to come first
92936
92937
92938               if (aly < bly) return -1;
92939               if (aly > bly) return 1; // left endpoints are identical
92940               // check for colinearity by using the left-more right endpoint
92941               // is the A right endpoint more left-more?
92942
92943               if (arx < brx) {
92944                 var _bCmpARight = b.comparePoint(a.rightSE.point);
92945
92946                 if (_bCmpARight !== 0) return _bCmpARight;
92947               } // is the B right endpoint more left-more?
92948
92949
92950               if (arx > brx) {
92951                 var _aCmpBRight = a.comparePoint(b.rightSE.point);
92952
92953                 if (_aCmpBRight < 0) return 1;
92954                 if (_aCmpBRight > 0) return -1;
92955               }
92956
92957               if (arx !== brx) {
92958                 // are these two [almost] vertical segments with opposite orientation?
92959                 // if so, the one with the lower right endpoint comes first
92960                 var ay = ary - aly;
92961                 var ax = arx - alx;
92962                 var by = bry - bly;
92963                 var bx = brx - blx;
92964                 if (ay > ax && by < bx) return 1;
92965                 if (ay < ax && by > bx) return -1;
92966               } // we have colinear segments with matching orientation
92967               // consider the one with more left-more right endpoint to be first
92968
92969
92970               if (arx > brx) return 1;
92971               if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
92972               // vertical plane, ie arx === brx
92973               // consider the lower right-endpoint to come first
92974
92975               if (ary < bry) return -1;
92976               if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
92977               // fall back on creation order as consistent tie-breaker
92978
92979               if (a.id < b.id) return -1;
92980               if (a.id > b.id) return 1; // identical segment, ie a === b
92981
92982               return 0;
92983             }
92984             /* Warning: a reference to ringWindings input will be stored,
92985              *  and possibly will be later modified */
92986
92987           }]);
92988
92989           function Segment(leftSE, rightSE, rings, windings) {
92990             _classCallCheck$1(this, Segment);
92991
92992             this.id = ++segmentId;
92993             this.leftSE = leftSE;
92994             leftSE.segment = this;
92995             leftSE.otherSE = rightSE;
92996             this.rightSE = rightSE;
92997             rightSE.segment = this;
92998             rightSE.otherSE = leftSE;
92999             this.rings = rings;
93000             this.windings = windings; // left unset for performance, set later in algorithm
93001             // this.ringOut, this.consumedBy, this.prev
93002           }
93003
93004           _createClass$1(Segment, [{
93005             key: "replaceRightSE",
93006
93007             /* When a segment is split, the rightSE is replaced with a new sweep event */
93008             value: function replaceRightSE(newRightSE) {
93009               this.rightSE = newRightSE;
93010               this.rightSE.segment = this;
93011               this.rightSE.otherSE = this.leftSE;
93012               this.leftSE.otherSE = this.rightSE;
93013             }
93014           }, {
93015             key: "bbox",
93016             value: function bbox() {
93017               var y1 = this.leftSE.point.y;
93018               var y2 = this.rightSE.point.y;
93019               return {
93020                 ll: {
93021                   x: this.leftSE.point.x,
93022                   y: y1 < y2 ? y1 : y2
93023                 },
93024                 ur: {
93025                   x: this.rightSE.point.x,
93026                   y: y1 > y2 ? y1 : y2
93027                 }
93028               };
93029             }
93030             /* A vector from the left point to the right */
93031
93032           }, {
93033             key: "vector",
93034             value: function vector() {
93035               return {
93036                 x: this.rightSE.point.x - this.leftSE.point.x,
93037                 y: this.rightSE.point.y - this.leftSE.point.y
93038               };
93039             }
93040           }, {
93041             key: "isAnEndpoint",
93042             value: function isAnEndpoint(pt) {
93043               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;
93044             }
93045             /* Compare this segment with a point.
93046              *
93047              * A point P is considered to be colinear to a segment if there
93048              * exists a distance D such that if we travel along the segment
93049              * from one * endpoint towards the other a distance D, we find
93050              * ourselves at point P.
93051              *
93052              * Return value indicates:
93053              *
93054              *   1: point lies above the segment (to the left of vertical)
93055              *   0: point is colinear to segment
93056              *  -1: point lies below the segment (to the right of vertical)
93057              */
93058
93059           }, {
93060             key: "comparePoint",
93061             value: function comparePoint(point) {
93062               if (this.isAnEndpoint(point)) return 0;
93063               var lPt = this.leftSE.point;
93064               var rPt = this.rightSE.point;
93065               var v = this.vector(); // Exactly vertical segments.
93066
93067               if (lPt.x === rPt.x) {
93068                 if (point.x === lPt.x) return 0;
93069                 return point.x < lPt.x ? 1 : -1;
93070               } // Nearly vertical segments with an intersection.
93071               // Check to see where a point on the line with matching Y coordinate is.
93072
93073
93074               var yDist = (point.y - lPt.y) / v.y;
93075               var xFromYDist = lPt.x + yDist * v.x;
93076               if (point.x === xFromYDist) return 0; // General case.
93077               // Check to see where a point on the line with matching X coordinate is.
93078
93079               var xDist = (point.x - lPt.x) / v.x;
93080               var yFromXDist = lPt.y + xDist * v.y;
93081               if (point.y === yFromXDist) return 0;
93082               return point.y < yFromXDist ? -1 : 1;
93083             }
93084             /**
93085              * Given another segment, returns the first non-trivial intersection
93086              * between the two segments (in terms of sweep line ordering), if it exists.
93087              *
93088              * A 'non-trivial' intersection is one that will cause one or both of the
93089              * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
93090              *
93091              *   * endpoint of segA with endpoint of segB --> trivial
93092              *   * endpoint of segA with point along segB --> non-trivial
93093              *   * endpoint of segB with point along segA --> non-trivial
93094              *   * point along segA with point along segB --> non-trivial
93095              *
93096              * If no non-trivial intersection exists, return null
93097              * Else, return null.
93098              */
93099
93100           }, {
93101             key: "getIntersection",
93102             value: function getIntersection(other) {
93103               // If bboxes don't overlap, there can't be any intersections
93104               var tBbox = this.bbox();
93105               var oBbox = other.bbox();
93106               var bboxOverlap = getBboxOverlap(tBbox, oBbox);
93107               if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
93108               // This will 'snap' intersections to endpoints if possible, and will
93109               // handle cases of colinearity.
93110
93111               var tlp = this.leftSE.point;
93112               var trp = this.rightSE.point;
93113               var olp = other.leftSE.point;
93114               var orp = other.rightSE.point; // does each endpoint touch the other segment?
93115               // note that we restrict the 'touching' definition to only allow segments
93116               // to touch endpoints that lie forward from where we are in the sweep line pass
93117
93118               var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
93119               var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
93120               var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
93121               var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
93122
93123               if (touchesThisLSE && touchesOtherLSE) {
93124                 // these two cases are for colinear segments with matching left
93125                 // endpoints, and one segment being longer than the other
93126                 if (touchesThisRSE && !touchesOtherRSE) return trp;
93127                 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
93128                 // or just on their left endpoint (one trivial intersection
93129
93130                 return null;
93131               } // does this left endpoint matches (other doesn't)
93132
93133
93134               if (touchesThisLSE) {
93135                 // check for segments that just intersect on opposing endpoints
93136                 if (touchesOtherRSE) {
93137                   if (tlp.x === orp.x && tlp.y === orp.y) return null;
93138                 } // t-intersection on left endpoint
93139
93140
93141                 return tlp;
93142               } // does other left endpoint matches (this doesn't)
93143
93144
93145               if (touchesOtherLSE) {
93146                 // check for segments that just intersect on opposing endpoints
93147                 if (touchesThisRSE) {
93148                   if (trp.x === olp.x && trp.y === olp.y) return null;
93149                 } // t-intersection on left endpoint
93150
93151
93152                 return olp;
93153               } // trivial intersection on right endpoints
93154
93155
93156               if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
93157
93158               if (touchesThisRSE) return trp;
93159               if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
93160               // infinite lines laid over the segments
93161
93162               var pt = intersection$1(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
93163               // they would have an endpoint intersection and that case was already handled above
93164
93165               if (pt === null) return null; // is the intersection found between the lines not on the segments?
93166
93167               if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
93168
93169               return rounder.round(pt.x, pt.y);
93170             }
93171             /**
93172              * Split the given segment into multiple segments on the given points.
93173              *  * Each existing segment will retain its leftSE and a new rightSE will be
93174              *    generated for it.
93175              *  * A new segment will be generated which will adopt the original segment's
93176              *    rightSE, and a new leftSE will be generated for it.
93177              *  * If there are more than two points given to split on, new segments
93178              *    in the middle will be generated with new leftSE and rightSE's.
93179              *  * An array of the newly generated SweepEvents will be returned.
93180              *
93181              * Warning: input array of points is modified
93182              */
93183
93184           }, {
93185             key: "split",
93186             value: function split(point) {
93187               var newEvents = [];
93188               var alreadyLinked = point.events !== undefined;
93189               var newLeftSE = new SweepEvent$1(point, true);
93190               var newRightSE = new SweepEvent$1(point, false);
93191               var oldRightSE = this.rightSE;
93192               this.replaceRightSE(newRightSE);
93193               newEvents.push(newRightSE);
93194               newEvents.push(newLeftSE);
93195               var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
93196               // sometimes one of the resulting new segments is vertical, in which
93197               // case its left and right events may need to be swapped
93198
93199               if (SweepEvent$1.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
93200                 newSeg.swapEvents();
93201               }
93202
93203               if (SweepEvent$1.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
93204                 this.swapEvents();
93205               } // in the point we just used to create new sweep events with was already
93206               // linked to other events, we need to check if either of the affected
93207               // segments should be consumed
93208
93209
93210               if (alreadyLinked) {
93211                 newLeftSE.checkForConsuming();
93212                 newRightSE.checkForConsuming();
93213               }
93214
93215               return newEvents;
93216             }
93217             /* Swap which event is left and right */
93218
93219           }, {
93220             key: "swapEvents",
93221             value: function swapEvents() {
93222               var tmpEvt = this.rightSE;
93223               this.rightSE = this.leftSE;
93224               this.leftSE = tmpEvt;
93225               this.leftSE.isLeft = true;
93226               this.rightSE.isLeft = false;
93227
93228               for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
93229                 this.windings[i] *= -1;
93230               }
93231             }
93232             /* Consume another segment. We take their rings under our wing
93233              * and mark them as consumed. Use for perfectly overlapping segments */
93234
93235           }, {
93236             key: "consume",
93237             value: function consume(other) {
93238               var consumer = this;
93239               var consumee = other;
93240
93241               while (consumer.consumedBy) {
93242                 consumer = consumer.consumedBy;
93243               }
93244
93245               while (consumee.consumedBy) {
93246                 consumee = consumee.consumedBy;
93247               }
93248
93249               var cmp = Segment.compare(consumer, consumee);
93250               if (cmp === 0) return; // already consumed
93251               // the winner of the consumption is the earlier segment
93252               // according to sweep line ordering
93253
93254               if (cmp > 0) {
93255                 var tmp = consumer;
93256                 consumer = consumee;
93257                 consumee = tmp;
93258               } // make sure a segment doesn't consume it's prev
93259
93260
93261               if (consumer.prev === consumee) {
93262                 var _tmp = consumer;
93263                 consumer = consumee;
93264                 consumee = _tmp;
93265               }
93266
93267               for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
93268                 var ring = consumee.rings[i];
93269                 var winding = consumee.windings[i];
93270                 var index = consumer.rings.indexOf(ring);
93271
93272                 if (index === -1) {
93273                   consumer.rings.push(ring);
93274                   consumer.windings.push(winding);
93275                 } else consumer.windings[index] += winding;
93276               }
93277
93278               consumee.rings = null;
93279               consumee.windings = null;
93280               consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
93281
93282               consumee.leftSE.consumedBy = consumer.leftSE;
93283               consumee.rightSE.consumedBy = consumer.rightSE;
93284             }
93285             /* The first segment previous segment chain that is in the result */
93286
93287           }, {
93288             key: "prevInResult",
93289             value: function prevInResult() {
93290               if (this._prevInResult !== undefined) return this._prevInResult;
93291               if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
93292               return this._prevInResult;
93293             }
93294           }, {
93295             key: "beforeState",
93296             value: function beforeState() {
93297               if (this._beforeState !== undefined) return this._beforeState;
93298               if (!this.prev) this._beforeState = {
93299                 rings: [],
93300                 windings: [],
93301                 multiPolys: []
93302               };else {
93303                 var seg = this.prev.consumedBy || this.prev;
93304                 this._beforeState = seg.afterState();
93305               }
93306               return this._beforeState;
93307             }
93308           }, {
93309             key: "afterState",
93310             value: function afterState() {
93311               if (this._afterState !== undefined) return this._afterState;
93312               var beforeState = this.beforeState();
93313               this._afterState = {
93314                 rings: beforeState.rings.slice(0),
93315                 windings: beforeState.windings.slice(0),
93316                 multiPolys: []
93317               };
93318               var ringsAfter = this._afterState.rings;
93319               var windingsAfter = this._afterState.windings;
93320               var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
93321
93322               for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
93323                 var ring = this.rings[i];
93324                 var winding = this.windings[i];
93325                 var index = ringsAfter.indexOf(ring);
93326
93327                 if (index === -1) {
93328                   ringsAfter.push(ring);
93329                   windingsAfter.push(winding);
93330                 } else windingsAfter[index] += winding;
93331               } // calcualte polysAfter
93332
93333
93334               var polysAfter = [];
93335               var polysExclude = [];
93336
93337               for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
93338                 if (windingsAfter[_i] === 0) continue; // non-zero rule
93339
93340                 var _ring = ringsAfter[_i];
93341                 var poly = _ring.poly;
93342                 if (polysExclude.indexOf(poly) !== -1) continue;
93343                 if (_ring.isExterior) polysAfter.push(poly);else {
93344                   if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
93345
93346                   var _index = polysAfter.indexOf(_ring.poly);
93347
93348                   if (_index !== -1) polysAfter.splice(_index, 1);
93349                 }
93350               } // calculate multiPolysAfter
93351
93352
93353               for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
93354                 var mp = polysAfter[_i2].multiPoly;
93355                 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
93356               }
93357
93358               return this._afterState;
93359             }
93360             /* Is this segment part of the final result? */
93361
93362           }, {
93363             key: "isInResult",
93364             value: function isInResult() {
93365               // if we've been consumed, we're not in the result
93366               if (this.consumedBy) return false;
93367               if (this._isInResult !== undefined) return this._isInResult;
93368               var mpsBefore = this.beforeState().multiPolys;
93369               var mpsAfter = this.afterState().multiPolys;
93370
93371               switch (operation.type) {
93372                 case 'union':
93373                   {
93374                     // UNION - included iff:
93375                     //  * On one side of us there is 0 poly interiors AND
93376                     //  * On the other side there is 1 or more.
93377                     var noBefores = mpsBefore.length === 0;
93378                     var noAfters = mpsAfter.length === 0;
93379                     this._isInResult = noBefores !== noAfters;
93380                     break;
93381                   }
93382
93383                 case 'intersection':
93384                   {
93385                     // INTERSECTION - included iff:
93386                     //  * on one side of us all multipolys are rep. with poly interiors AND
93387                     //  * on the other side of us, not all multipolys are repsented
93388                     //    with poly interiors
93389                     var least;
93390                     var most;
93391
93392                     if (mpsBefore.length < mpsAfter.length) {
93393                       least = mpsBefore.length;
93394                       most = mpsAfter.length;
93395                     } else {
93396                       least = mpsAfter.length;
93397                       most = mpsBefore.length;
93398                     }
93399
93400                     this._isInResult = most === operation.numMultiPolys && least < most;
93401                     break;
93402                   }
93403
93404                 case 'xor':
93405                   {
93406                     // XOR - included iff:
93407                     //  * the difference between the number of multipolys represented
93408                     //    with poly interiors on our two sides is an odd number
93409                     var diff = Math.abs(mpsBefore.length - mpsAfter.length);
93410                     this._isInResult = diff % 2 === 1;
93411                     break;
93412                   }
93413
93414                 case 'difference':
93415                   {
93416                     // DIFFERENCE included iff:
93417                     //  * on exactly one side, we have just the subject
93418                     var isJustSubject = function isJustSubject(mps) {
93419                       return mps.length === 1 && mps[0].isSubject;
93420                     };
93421
93422                     this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
93423                     break;
93424                   }
93425
93426                 default:
93427                   throw new Error("Unrecognized operation type found ".concat(operation.type));
93428               }
93429
93430               return this._isInResult;
93431             }
93432           }], [{
93433             key: "fromRing",
93434             value: function fromRing(pt1, pt2, ring) {
93435               var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
93436
93437               var cmpPts = SweepEvent$1.comparePoints(pt1, pt2);
93438
93439               if (cmpPts < 0) {
93440                 leftPt = pt1;
93441                 rightPt = pt2;
93442                 winding = 1;
93443               } else if (cmpPts > 0) {
93444                 leftPt = pt2;
93445                 rightPt = pt1;
93446                 winding = -1;
93447               } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
93448
93449               var leftSE = new SweepEvent$1(leftPt, true);
93450               var rightSE = new SweepEvent$1(rightPt, false);
93451               return new Segment(leftSE, rightSE, [ring], [winding]);
93452             }
93453           }]);
93454
93455           return Segment;
93456         }();
93457
93458         var RingIn = /*#__PURE__*/function () {
93459           function RingIn(geomRing, poly, isExterior) {
93460             _classCallCheck$1(this, RingIn);
93461
93462             if (!Array.isArray(geomRing) || geomRing.length === 0) {
93463               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93464             }
93465
93466             this.poly = poly;
93467             this.isExterior = isExterior;
93468             this.segments = [];
93469
93470             if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
93471               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93472             }
93473
93474             var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
93475             this.bbox = {
93476               ll: {
93477                 x: firstPoint.x,
93478                 y: firstPoint.y
93479               },
93480               ur: {
93481                 x: firstPoint.x,
93482                 y: firstPoint.y
93483               }
93484             };
93485             var prevPoint = firstPoint;
93486
93487             for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
93488               if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
93489                 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93490               }
93491
93492               var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
93493
93494               if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
93495               this.segments.push(Segment.fromRing(prevPoint, point, this));
93496               if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
93497               if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
93498               if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
93499               if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
93500               prevPoint = point;
93501             } // add segment from last to first if last is not the same as first
93502
93503
93504             if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
93505               this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
93506             }
93507           }
93508
93509           _createClass$1(RingIn, [{
93510             key: "getSweepEvents",
93511             value: function getSweepEvents() {
93512               var sweepEvents = [];
93513
93514               for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
93515                 var segment = this.segments[i];
93516                 sweepEvents.push(segment.leftSE);
93517                 sweepEvents.push(segment.rightSE);
93518               }
93519
93520               return sweepEvents;
93521             }
93522           }]);
93523
93524           return RingIn;
93525         }();
93526
93527         var PolyIn = /*#__PURE__*/function () {
93528           function PolyIn(geomPoly, multiPoly) {
93529             _classCallCheck$1(this, PolyIn);
93530
93531             if (!Array.isArray(geomPoly)) {
93532               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93533             }
93534
93535             this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
93536
93537             this.bbox = {
93538               ll: {
93539                 x: this.exteriorRing.bbox.ll.x,
93540                 y: this.exteriorRing.bbox.ll.y
93541               },
93542               ur: {
93543                 x: this.exteriorRing.bbox.ur.x,
93544                 y: this.exteriorRing.bbox.ur.y
93545               }
93546             };
93547             this.interiorRings = [];
93548
93549             for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
93550               var ring = new RingIn(geomPoly[i], this, false);
93551               if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
93552               if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
93553               if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
93554               if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
93555               this.interiorRings.push(ring);
93556             }
93557
93558             this.multiPoly = multiPoly;
93559           }
93560
93561           _createClass$1(PolyIn, [{
93562             key: "getSweepEvents",
93563             value: function getSweepEvents() {
93564               var sweepEvents = this.exteriorRing.getSweepEvents();
93565
93566               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93567                 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
93568
93569                 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
93570                   sweepEvents.push(ringSweepEvents[j]);
93571                 }
93572               }
93573
93574               return sweepEvents;
93575             }
93576           }]);
93577
93578           return PolyIn;
93579         }();
93580
93581         var MultiPolyIn = /*#__PURE__*/function () {
93582           function MultiPolyIn(geom, isSubject) {
93583             _classCallCheck$1(this, MultiPolyIn);
93584
93585             if (!Array.isArray(geom)) {
93586               throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
93587             }
93588
93589             try {
93590               // if the input looks like a polygon, convert it to a multipolygon
93591               if (typeof geom[0][0][0] === 'number') geom = [geom];
93592             } catch (ex) {// The input is either malformed or has empty arrays.
93593               // In either case, it will be handled later on.
93594             }
93595
93596             this.polys = [];
93597             this.bbox = {
93598               ll: {
93599                 x: Number.POSITIVE_INFINITY,
93600                 y: Number.POSITIVE_INFINITY
93601               },
93602               ur: {
93603                 x: Number.NEGATIVE_INFINITY,
93604                 y: Number.NEGATIVE_INFINITY
93605               }
93606             };
93607
93608             for (var i = 0, iMax = geom.length; i < iMax; i++) {
93609               var poly = new PolyIn(geom[i], this);
93610               if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
93611               if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
93612               if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
93613               if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
93614               this.polys.push(poly);
93615             }
93616
93617             this.isSubject = isSubject;
93618           }
93619
93620           _createClass$1(MultiPolyIn, [{
93621             key: "getSweepEvents",
93622             value: function getSweepEvents() {
93623               var sweepEvents = [];
93624
93625               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93626                 var polySweepEvents = this.polys[i].getSweepEvents();
93627
93628                 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
93629                   sweepEvents.push(polySweepEvents[j]);
93630                 }
93631               }
93632
93633               return sweepEvents;
93634             }
93635           }]);
93636
93637           return MultiPolyIn;
93638         }();
93639
93640         var RingOut = /*#__PURE__*/function () {
93641           _createClass$1(RingOut, null, [{
93642             key: "factory",
93643
93644             /* Given the segments from the sweep line pass, compute & return a series
93645              * of closed rings from all the segments marked to be part of the result */
93646             value: function factory(allSegments) {
93647               var ringsOut = [];
93648
93649               for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
93650                 var segment = allSegments[i];
93651                 if (!segment.isInResult() || segment.ringOut) continue;
93652                 var prevEvent = null;
93653                 var event = segment.leftSE;
93654                 var nextEvent = segment.rightSE;
93655                 var events = [event];
93656                 var startingPoint = event.point;
93657                 var intersectionLEs = [];
93658                 /* Walk the chain of linked events to form a closed ring */
93659
93660                 while (true) {
93661                   prevEvent = event;
93662                   event = nextEvent;
93663                   events.push(event);
93664                   /* Is the ring complete? */
93665
93666                   if (event.point === startingPoint) break;
93667
93668                   while (true) {
93669                     var availableLEs = event.getAvailableLinkedEvents();
93670                     /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
93671                      * part of the algorithm malfunctioned... please file a bug report. */
93672
93673                     if (availableLEs.length === 0) {
93674                       var firstPt = events[0].point;
93675                       var lastPt = events[events.length - 1].point;
93676                       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, "]."));
93677                     }
93678                     /* Only one way to go, so cotinue on the path */
93679
93680
93681                     if (availableLEs.length === 1) {
93682                       nextEvent = availableLEs[0].otherSE;
93683                       break;
93684                     }
93685                     /* We must have an intersection. Check for a completed loop */
93686
93687
93688                     var indexLE = null;
93689
93690                     for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
93691                       if (intersectionLEs[j].point === event.point) {
93692                         indexLE = j;
93693                         break;
93694                       }
93695                     }
93696                     /* Found a completed loop. Cut that off and make a ring */
93697
93698
93699                     if (indexLE !== null) {
93700                       var intersectionLE = intersectionLEs.splice(indexLE)[0];
93701                       var ringEvents = events.splice(intersectionLE.index);
93702                       ringEvents.unshift(ringEvents[0].otherSE);
93703                       ringsOut.push(new RingOut(ringEvents.reverse()));
93704                       continue;
93705                     }
93706                     /* register the intersection */
93707
93708
93709                     intersectionLEs.push({
93710                       index: events.length,
93711                       point: event.point
93712                     });
93713                     /* Choose the left-most option to continue the walk */
93714
93715                     var comparator = event.getLeftmostComparator(prevEvent);
93716                     nextEvent = availableLEs.sort(comparator)[0].otherSE;
93717                     break;
93718                   }
93719                 }
93720
93721                 ringsOut.push(new RingOut(events));
93722               }
93723
93724               return ringsOut;
93725             }
93726           }]);
93727
93728           function RingOut(events) {
93729             _classCallCheck$1(this, RingOut);
93730
93731             this.events = events;
93732
93733             for (var i = 0, iMax = events.length; i < iMax; i++) {
93734               events[i].segment.ringOut = this;
93735             }
93736
93737             this.poly = null;
93738           }
93739
93740           _createClass$1(RingOut, [{
93741             key: "getGeom",
93742             value: function getGeom() {
93743               // Remove superfluous points (ie extra points along a straight line),
93744               var prevPt = this.events[0].point;
93745               var points = [prevPt];
93746
93747               for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
93748                 var _pt = this.events[i].point;
93749                 var _nextPt = this.events[i + 1].point;
93750                 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
93751                 points.push(_pt);
93752                 prevPt = _pt;
93753               } // ring was all (within rounding error of angle calc) colinear points
93754
93755
93756               if (points.length === 1) return null; // check if the starting point is necessary
93757
93758               var pt = points[0];
93759               var nextPt = points[1];
93760               if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
93761               points.push(points[0]);
93762               var step = this.isExteriorRing() ? 1 : -1;
93763               var iStart = this.isExteriorRing() ? 0 : points.length - 1;
93764               var iEnd = this.isExteriorRing() ? points.length : -1;
93765               var orderedPoints = [];
93766
93767               for (var _i = iStart; _i != iEnd; _i += step) {
93768                 orderedPoints.push([points[_i].x, points[_i].y]);
93769               }
93770
93771               return orderedPoints;
93772             }
93773           }, {
93774             key: "isExteriorRing",
93775             value: function isExteriorRing() {
93776               if (this._isExteriorRing === undefined) {
93777                 var enclosing = this.enclosingRing();
93778                 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
93779               }
93780
93781               return this._isExteriorRing;
93782             }
93783           }, {
93784             key: "enclosingRing",
93785             value: function enclosingRing() {
93786               if (this._enclosingRing === undefined) {
93787                 this._enclosingRing = this._calcEnclosingRing();
93788               }
93789
93790               return this._enclosingRing;
93791             }
93792             /* Returns the ring that encloses this one, if any */
93793
93794           }, {
93795             key: "_calcEnclosingRing",
93796             value: function _calcEnclosingRing() {
93797               // start with the ealier sweep line event so that the prevSeg
93798               // chain doesn't lead us inside of a loop of ours
93799               var leftMostEvt = this.events[0];
93800
93801               for (var i = 1, iMax = this.events.length; i < iMax; i++) {
93802                 var evt = this.events[i];
93803                 if (SweepEvent$1.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
93804               }
93805
93806               var prevSeg = leftMostEvt.segment.prevInResult();
93807               var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93808
93809               while (true) {
93810                 // no segment found, thus no ring can enclose us
93811                 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
93812                 // segment must loop back around and enclose us
93813
93814                 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
93815                 // segment must either loop around us or the ring of the prev prev
93816                 // seg, which would make us and the ring of the prev peers
93817
93818                 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
93819                   if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
93820                     return prevSeg.ringOut;
93821                   } else return prevSeg.ringOut.enclosingRing();
93822                 } // two segments are from the same ring, so this was a penisula
93823                 // of that ring. iterate downward, keep searching
93824
93825
93826                 prevSeg = prevPrevSeg.prevInResult();
93827                 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
93828               }
93829             }
93830           }]);
93831
93832           return RingOut;
93833         }();
93834
93835         var PolyOut = /*#__PURE__*/function () {
93836           function PolyOut(exteriorRing) {
93837             _classCallCheck$1(this, PolyOut);
93838
93839             this.exteriorRing = exteriorRing;
93840             exteriorRing.poly = this;
93841             this.interiorRings = [];
93842           }
93843
93844           _createClass$1(PolyOut, [{
93845             key: "addInterior",
93846             value: function addInterior(ring) {
93847               this.interiorRings.push(ring);
93848               ring.poly = this;
93849             }
93850           }, {
93851             key: "getGeom",
93852             value: function getGeom() {
93853               var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
93854
93855               if (geom[0] === null) return null;
93856
93857               for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
93858                 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
93859
93860                 if (ringGeom === null) continue;
93861                 geom.push(ringGeom);
93862               }
93863
93864               return geom;
93865             }
93866           }]);
93867
93868           return PolyOut;
93869         }();
93870
93871         var MultiPolyOut = /*#__PURE__*/function () {
93872           function MultiPolyOut(rings) {
93873             _classCallCheck$1(this, MultiPolyOut);
93874
93875             this.rings = rings;
93876             this.polys = this._composePolys(rings);
93877           }
93878
93879           _createClass$1(MultiPolyOut, [{
93880             key: "getGeom",
93881             value: function getGeom() {
93882               var geom = [];
93883
93884               for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
93885                 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
93886
93887                 if (polyGeom === null) continue;
93888                 geom.push(polyGeom);
93889               }
93890
93891               return geom;
93892             }
93893           }, {
93894             key: "_composePolys",
93895             value: function _composePolys(rings) {
93896               var polys = [];
93897
93898               for (var i = 0, iMax = rings.length; i < iMax; i++) {
93899                 var ring = rings[i];
93900                 if (ring.poly) continue;
93901                 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
93902                   var enclosingRing = ring.enclosingRing();
93903                   if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
93904                   enclosingRing.poly.addInterior(ring);
93905                 }
93906               }
93907
93908               return polys;
93909             }
93910           }]);
93911
93912           return MultiPolyOut;
93913         }();
93914         /**
93915          * NOTE:  We must be careful not to change any segments while
93916          *        they are in the SplayTree. AFAIK, there's no way to tell
93917          *        the tree to rebalance itself - thus before splitting
93918          *        a segment that's in the tree, we remove it from the tree,
93919          *        do the split, then re-insert it. (Even though splitting a
93920          *        segment *shouldn't* change its correct position in the
93921          *        sweep line tree, the reality is because of rounding errors,
93922          *        it sometimes does.)
93923          */
93924
93925
93926         var SweepLine = /*#__PURE__*/function () {
93927           function SweepLine(queue) {
93928             var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
93929
93930             _classCallCheck$1(this, SweepLine);
93931
93932             this.queue = queue;
93933             this.tree = new Tree(comparator);
93934             this.segments = [];
93935           }
93936
93937           _createClass$1(SweepLine, [{
93938             key: "process",
93939             value: function process(event) {
93940               var segment = event.segment;
93941               var newEvents = []; // if we've already been consumed by another segment,
93942               // clean up our body parts and get out
93943
93944               if (event.consumedBy) {
93945                 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
93946                 return newEvents;
93947               }
93948
93949               var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
93950               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.');
93951               var prevNode = node;
93952               var nextNode = node;
93953               var prevSeg = undefined;
93954               var nextSeg = undefined; // skip consumed segments still in tree
93955
93956               while (prevSeg === undefined) {
93957                 prevNode = this.tree.prev(prevNode);
93958                 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
93959               } // skip consumed segments still in tree
93960
93961
93962               while (nextSeg === undefined) {
93963                 nextNode = this.tree.next(nextNode);
93964                 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
93965               }
93966
93967               if (event.isLeft) {
93968                 // Check for intersections against the previous segment in the sweep line
93969                 var prevMySplitter = null;
93970
93971                 if (prevSeg) {
93972                   var prevInter = prevSeg.getIntersection(segment);
93973
93974                   if (prevInter !== null) {
93975                     if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
93976
93977                     if (!prevSeg.isAnEndpoint(prevInter)) {
93978                       var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
93979
93980                       for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
93981                         newEvents.push(newEventsFromSplit[i]);
93982                       }
93983                     }
93984                   }
93985                 } // Check for intersections against the next segment in the sweep line
93986
93987
93988                 var nextMySplitter = null;
93989
93990                 if (nextSeg) {
93991                   var nextInter = nextSeg.getIntersection(segment);
93992
93993                   if (nextInter !== null) {
93994                     if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
93995
93996                     if (!nextSeg.isAnEndpoint(nextInter)) {
93997                       var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
93998
93999                       for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
94000                         newEvents.push(_newEventsFromSplit[_i]);
94001                       }
94002                     }
94003                   }
94004                 } // For simplicity, even if we find more than one intersection we only
94005                 // spilt on the 'earliest' (sweep-line style) of the intersections.
94006                 // The other intersection will be handled in a future process().
94007
94008
94009                 if (prevMySplitter !== null || nextMySplitter !== null) {
94010                   var mySplitter = null;
94011                   if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
94012                     var cmpSplitters = SweepEvent$1.comparePoints(prevMySplitter, nextMySplitter);
94013                     mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
94014                   } // Rounding errors can cause changes in ordering,
94015                   // so remove afected segments and right sweep events before splitting
94016
94017                   this.queue.remove(segment.rightSE);
94018                   newEvents.push(segment.rightSE);
94019
94020                   var _newEventsFromSplit2 = segment.split(mySplitter);
94021
94022                   for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
94023                     newEvents.push(_newEventsFromSplit2[_i2]);
94024                   }
94025                 }
94026
94027                 if (newEvents.length > 0) {
94028                   // We found some intersections, so re-do the current event to
94029                   // make sure sweep line ordering is totally consistent for later
94030                   // use with the segment 'prev' pointers
94031                   this.tree.remove(segment);
94032                   newEvents.push(event);
94033                 } else {
94034                   // done with left event
94035                   this.segments.push(segment);
94036                   segment.prev = prevSeg;
94037                 }
94038               } else {
94039                 // event.isRight
94040                 // since we're about to be removed from the sweep line, check for
94041                 // intersections between our previous and next segments
94042                 if (prevSeg && nextSeg) {
94043                   var inter = prevSeg.getIntersection(nextSeg);
94044
94045                   if (inter !== null) {
94046                     if (!prevSeg.isAnEndpoint(inter)) {
94047                       var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
94048
94049                       for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
94050                         newEvents.push(_newEventsFromSplit3[_i3]);
94051                       }
94052                     }
94053
94054                     if (!nextSeg.isAnEndpoint(inter)) {
94055                       var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
94056
94057                       for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
94058                         newEvents.push(_newEventsFromSplit4[_i4]);
94059                       }
94060                     }
94061                   }
94062                 }
94063
94064                 this.tree.remove(segment);
94065               }
94066
94067               return newEvents;
94068             }
94069             /* Safely split a segment that is currently in the datastructures
94070              * IE - a segment other than the one that is currently being processed. */
94071
94072           }, {
94073             key: "_splitSafely",
94074             value: function _splitSafely(seg, pt) {
94075               // Rounding errors can cause changes in ordering,
94076               // so remove afected segments and right sweep events before splitting
94077               // removeNode() doesn't work, so have re-find the seg
94078               // https://github.com/w8r/splay-tree/pull/5
94079               this.tree.remove(seg);
94080               var rightSE = seg.rightSE;
94081               this.queue.remove(rightSE);
94082               var newEvents = seg.split(pt);
94083               newEvents.push(rightSE); // splitting can trigger consumption
94084
94085               if (seg.consumedBy === undefined) this.tree.insert(seg);
94086               return newEvents;
94087             }
94088           }]);
94089
94090           return SweepLine;
94091         }();
94092
94093         var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
94094         var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
94095
94096         var Operation = /*#__PURE__*/function () {
94097           function Operation() {
94098             _classCallCheck$1(this, Operation);
94099           }
94100
94101           _createClass$1(Operation, [{
94102             key: "run",
94103             value: function run(type, geom, moreGeoms) {
94104               operation.type = type;
94105               rounder.reset();
94106               /* Convert inputs to MultiPoly objects */
94107
94108               var multipolys = [new MultiPolyIn(geom, true)];
94109
94110               for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
94111                 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
94112               }
94113
94114               operation.numMultiPolys = multipolys.length;
94115               /* BBox optimization for difference operation
94116                * If the bbox of a multipolygon that's part of the clipping doesn't
94117                * intersect the bbox of the subject at all, we can just drop that
94118                * multiploygon. */
94119
94120               if (operation.type === 'difference') {
94121                 // in place removal
94122                 var subject = multipolys[0];
94123                 var _i = 1;
94124
94125                 while (_i < multipolys.length) {
94126                   if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
94127                 }
94128               }
94129               /* BBox optimization for intersection operation
94130                * If we can find any pair of multipolygons whose bbox does not overlap,
94131                * then the result will be empty. */
94132
94133
94134               if (operation.type === 'intersection') {
94135                 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
94136                 //       it could be optimized to O(n * ln(n))
94137                 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
94138                   var mpA = multipolys[_i2];
94139
94140                   for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
94141                     if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
94142                   }
94143                 }
94144               }
94145               /* Put segment endpoints in a priority queue */
94146
94147
94148               var queue = new Tree(SweepEvent$1.compare);
94149
94150               for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
94151                 var sweepEvents = multipolys[_i3].getSweepEvents();
94152
94153                 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
94154                   queue.insert(sweepEvents[_j]);
94155
94156                   if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
94157                     // prevents an infinite loop, an otherwise common manifestation of bugs
94158                     throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
94159                   }
94160                 }
94161               }
94162               /* Pass the sweep line over those endpoints */
94163
94164
94165               var sweepLine = new SweepLine(queue);
94166               var prevQueueSize = queue.size;
94167               var node = queue.pop();
94168
94169               while (node) {
94170                 var evt = node.key;
94171
94172                 if (queue.size === prevQueueSize) {
94173                   // prevents an infinite loop, an otherwise common manifestation of bugs
94174                   var seg = evt.segment;
94175                   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.');
94176                 }
94177
94178                 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
94179                   // prevents an infinite loop, an otherwise common manifestation of bugs
94180                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
94181                 }
94182
94183                 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
94184                   // prevents an infinite loop, an otherwise common manifestation of bugs
94185                   throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
94186                 }
94187
94188                 var newEvents = sweepLine.process(evt);
94189
94190                 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
94191                   var _evt = newEvents[_i4];
94192                   if (_evt.consumedBy === undefined) queue.insert(_evt);
94193                 }
94194
94195                 prevQueueSize = queue.size;
94196                 node = queue.pop();
94197               } // free some memory we don't need anymore
94198
94199
94200               rounder.reset();
94201               /* Collect and compile segments we're keeping into a multipolygon */
94202
94203               var ringsOut = RingOut.factory(sweepLine.segments);
94204               var result = new MultiPolyOut(ringsOut);
94205               return result.getGeom();
94206             }
94207           }]);
94208
94209           return Operation;
94210         }(); // singleton available by import
94211
94212
94213         var operation = new Operation();
94214
94215         var union$1 = function union(geom) {
94216           for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
94217             moreGeoms[_key - 1] = arguments[_key];
94218           }
94219
94220           return operation.run('union', geom, moreGeoms);
94221         };
94222
94223         var intersection$1$1 = function intersection(geom) {
94224           for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
94225             moreGeoms[_key2 - 1] = arguments[_key2];
94226           }
94227
94228           return operation.run('intersection', geom, moreGeoms);
94229         };
94230
94231         var xor = function xor(geom) {
94232           for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
94233             moreGeoms[_key3 - 1] = arguments[_key3];
94234           }
94235
94236           return operation.run('xor', geom, moreGeoms);
94237         };
94238
94239         var difference = function difference(subjectGeom) {
94240           for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
94241             clippingGeoms[_key4 - 1] = arguments[_key4];
94242           }
94243
94244           return operation.run('difference', subjectGeom, clippingGeoms);
94245         };
94246
94247         var index$1 = {
94248           union: union$1,
94249           intersection: intersection$1$1,
94250           xor: xor,
94251           difference: difference
94252         };
94253
94254         var geojsonPrecision = createCommonjsModule(function (module) {
94255           (function () {
94256             function parse(t, coordinatePrecision, extrasPrecision) {
94257               function point(p) {
94258                 return p.map(function (e, index) {
94259                   if (index < 2) {
94260                     return 1 * e.toFixed(coordinatePrecision);
94261                   } else {
94262                     return 1 * e.toFixed(extrasPrecision);
94263                   }
94264                 });
94265               }
94266
94267               function multi(l) {
94268                 return l.map(point);
94269               }
94270
94271               function poly(p) {
94272                 return p.map(multi);
94273               }
94274
94275               function multiPoly(m) {
94276                 return m.map(poly);
94277               }
94278
94279               function geometry(obj) {
94280                 if (!obj) {
94281                   return {};
94282                 }
94283
94284                 switch (obj.type) {
94285                   case "Point":
94286                     obj.coordinates = point(obj.coordinates);
94287                     return obj;
94288
94289                   case "LineString":
94290                   case "MultiPoint":
94291                     obj.coordinates = multi(obj.coordinates);
94292                     return obj;
94293
94294                   case "Polygon":
94295                   case "MultiLineString":
94296                     obj.coordinates = poly(obj.coordinates);
94297                     return obj;
94298
94299                   case "MultiPolygon":
94300                     obj.coordinates = multiPoly(obj.coordinates);
94301                     return obj;
94302
94303                   case "GeometryCollection":
94304                     obj.geometries = obj.geometries.map(geometry);
94305                     return obj;
94306
94307                   default:
94308                     return {};
94309                 }
94310               }
94311
94312               function feature(obj) {
94313                 obj.geometry = geometry(obj.geometry);
94314                 return obj;
94315               }
94316
94317               function featureCollection(f) {
94318                 f.features = f.features.map(feature);
94319                 return f;
94320               }
94321
94322               function geometryCollection(g) {
94323                 g.geometries = g.geometries.map(geometry);
94324                 return g;
94325               }
94326
94327               if (!t) {
94328                 return t;
94329               }
94330
94331               switch (t.type) {
94332                 case "Feature":
94333                   return feature(t);
94334
94335                 case "GeometryCollection":
94336                   return geometryCollection(t);
94337
94338                 case "FeatureCollection":
94339                   return featureCollection(t);
94340
94341                 case "Point":
94342                 case "LineString":
94343                 case "Polygon":
94344                 case "MultiPoint":
94345                 case "MultiPolygon":
94346                 case "MultiLineString":
94347                   return geometry(t);
94348
94349                 default:
94350                   return t;
94351               }
94352             }
94353
94354             module.exports = parse;
94355             module.exports.parse = parse;
94356           })();
94357         });
94358
94359         function isObject$4(obj) {
94360           return _typeof(obj) === 'object' && obj !== null;
94361         }
94362
94363         function forEach(obj, cb) {
94364           if (Array.isArray(obj)) {
94365             obj.forEach(cb);
94366           } else if (isObject$4(obj)) {
94367             Object.keys(obj).forEach(function (key) {
94368               var val = obj[key];
94369               cb(val, key);
94370             });
94371           }
94372         }
94373
94374         function getTreeDepth(obj) {
94375           var depth = 0;
94376
94377           if (Array.isArray(obj) || isObject$4(obj)) {
94378             forEach(obj, function (val) {
94379               if (Array.isArray(val) || isObject$4(val)) {
94380                 var tmpDepth = getTreeDepth(val);
94381
94382                 if (tmpDepth > depth) {
94383                   depth = tmpDepth;
94384                 }
94385               }
94386             });
94387             return depth + 1;
94388           }
94389
94390           return depth;
94391         }
94392
94393         function stringify(obj, options) {
94394           options = options || {};
94395           var indent = JSON.stringify([1], null, get$5(options, 'indent', 2)).slice(2, -3);
94396           var addMargin = get$5(options, 'margins', false);
94397           var addArrayMargin = get$5(options, 'arrayMargins', false);
94398           var addObjectMargin = get$5(options, 'objectMargins', false);
94399           var maxLength = indent === '' ? Infinity : get$5(options, 'maxLength', 80);
94400           var maxNesting = get$5(options, 'maxNesting', Infinity);
94401           return function _stringify(obj, currentIndent, reserved) {
94402             if (obj && typeof obj.toJSON === 'function') {
94403               obj = obj.toJSON();
94404             }
94405
94406             var string = JSON.stringify(obj);
94407
94408             if (string === undefined) {
94409               return string;
94410             }
94411
94412             var length = maxLength - currentIndent.length - reserved;
94413             var treeDepth = getTreeDepth(obj);
94414
94415             if (treeDepth <= maxNesting && string.length <= length) {
94416               var prettified = prettify(string, {
94417                 addMargin: addMargin,
94418                 addArrayMargin: addArrayMargin,
94419                 addObjectMargin: addObjectMargin
94420               });
94421
94422               if (prettified.length <= length) {
94423                 return prettified;
94424               }
94425             }
94426
94427             if (isObject$4(obj)) {
94428               var nextIndent = currentIndent + indent;
94429               var items = [];
94430               var delimiters;
94431
94432               var comma = function comma(array, index) {
94433                 return index === array.length - 1 ? 0 : 1;
94434               };
94435
94436               if (Array.isArray(obj)) {
94437                 for (var index = 0; index < obj.length; index++) {
94438                   items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
94439                 }
94440
94441                 delimiters = '[]';
94442               } else {
94443                 Object.keys(obj).forEach(function (key, index, array) {
94444                   var keyPart = JSON.stringify(key) + ': ';
94445
94446                   var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
94447
94448                   if (value !== undefined) {
94449                     items.push(keyPart + value);
94450                   }
94451                 });
94452                 delimiters = '{}';
94453               }
94454
94455               if (items.length > 0) {
94456                 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
94457               }
94458             }
94459
94460             return string;
94461           }(obj, '', 0);
94462         } // Note: This regex matches even invalid JSON strings, but since we’re
94463         // working on the output of `JSON.stringify` we know that only valid strings
94464         // are present (unless the user supplied a weird `options.indent` but in
94465         // that case we don’t care since the output would be invalid anyway).
94466
94467
94468         var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
94469
94470         function prettify(string, options) {
94471           options = options || {};
94472           var tokens = {
94473             '{': '{',
94474             '}': '}',
94475             '[': '[',
94476             ']': ']',
94477             ',': ', ',
94478             ':': ': '
94479           };
94480
94481           if (options.addMargin || options.addObjectMargin) {
94482             tokens['{'] = '{ ';
94483             tokens['}'] = ' }';
94484           }
94485
94486           if (options.addMargin || options.addArrayMargin) {
94487             tokens['['] = '[ ';
94488             tokens[']'] = ' ]';
94489           }
94490
94491           return string.replace(stringOrChar, function (match, string) {
94492             return string ? match : tokens[match];
94493           });
94494         }
94495
94496         function get$5(options, name, defaultValue) {
94497           return name in options ? options[name] : defaultValue;
94498         }
94499
94500         var jsonStringifyPrettyCompact = stringify;
94501
94502         var _default$3 = /*#__PURE__*/function () {
94503           // constructor
94504           //
94505           // `fc`  Optional FeatureCollection of known features
94506           //
94507           // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
94508           // Each feature must have a filename-like `id`, for example: `something.geojson`
94509           //
94510           // {
94511           //   "type": "FeatureCollection"
94512           //   "features": [
94513           //     {
94514           //       "type": "Feature",
94515           //       "id": "philly_metro.geojson",
94516           //       "properties": { … },
94517           //       "geometry": { … }
94518           //     }
94519           //   ]
94520           // }
94521           function _default(fc) {
94522             var _this = this;
94523
94524             _classCallCheck(this, _default);
94525
94526             // The _cache retains resolved features, so if you ask for the same thing multiple times
94527             // we don't repeat the expensive resolving/clipping operations.
94528             //
94529             // Each feature has a stable identifier that is used as the cache key.
94530             // The identifiers look like:
94531             // - for point locations, the stringified point:          e.g. '[8.67039,49.41882]'
94532             // - for geojson locations, the geojson id:               e.g. 'de-hamburg.geojson'
94533             // - for countrycoder locations, feature.id property:     e.g. 'Q2'  (countrycoder uses Wikidata identifiers)
94534             // - for aggregated locationSets, +[include]-[exclude]:   e.g '+[Q2]-[Q18,Q27611]'
94535             this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
94536             // When strict mode = false, return `null` for invalid locations or locationSets.
94537
94538             this._strict = true; // process input FeatureCollection
94539
94540             if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
94541               fc.features.forEach(function (feature) {
94542                 feature.properties = feature.properties || {};
94543                 var props = feature.properties; // get `id` from either `id` or `properties`
94544
94545                 var id = feature.id || props.id;
94546                 if (!id || !/^\S+\.geojson$/i.test(id)) return; // ensure `id` exists and is lowercase
94547
94548                 id = id.toLowerCase();
94549                 feature.id = id;
94550                 props.id = id; // ensure `area` property exists
94551
94552                 if (!props.area) {
94553                   var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
94554
94555                   props.area = Number(area.toFixed(2));
94556                 }
94557
94558                 _this._cache[id] = feature;
94559               });
94560             } // Replace CountryCoder world geometry to be a polygon covering the world.
94561
94562
94563             var world = _cloneDeep(feature('Q2'));
94564
94565             world.geometry = {
94566               type: 'Polygon',
94567               coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
94568             };
94569             world.id = 'Q2';
94570             world.properties.id = 'Q2';
94571             world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
94572
94573             this._cache.Q2 = world;
94574           } // validateLocation
94575           // `location`  The location to validate
94576           //
94577           // Pass a `location` value to validate
94578           //
94579           // Returns a result like:
94580           //   {
94581           //     type:     'point', 'geojson', or 'countrycoder'
94582           //     location:  the queried location
94583           //     id:        the stable identifier for the feature
94584           //   }
94585           // or `null` if the location is invalid
94586           //
94587
94588
94589           _createClass(_default, [{
94590             key: "validateLocation",
94591             value: function validateLocation(location) {
94592               if (Array.isArray(location)) {
94593                 // a [lon,lat] coordinate pair?
94594                 if (location.length === 2 && Number.isFinite(location[0]) && Number.isFinite(location[1]) && location[0] >= -180 && location[0] <= 180 && location[1] >= -90 && location[1] <= 90) {
94595                   var id = '[' + location.toString() + ']';
94596                   return {
94597                     type: 'point',
94598                     location: location,
94599                     id: id
94600                   };
94601                 }
94602               } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
94603                 // a .geojson filename?
94604                 var _id = location.toLowerCase();
94605
94606                 if (this._cache[_id]) {
94607                   return {
94608                     type: 'geojson',
94609                     location: location,
94610                     id: _id
94611                   };
94612                 }
94613               } else if (typeof location === 'string' || typeof location === 'number') {
94614                 // a country-coder value?
94615                 var feature$1 = feature(location);
94616
94617                 if (feature$1) {
94618                   // Use wikidata QID as the identifier, since that seems to be the one
94619                   // property that everything in CountryCoder is guaranteed to have.
94620                   var _id2 = feature$1.properties.wikidata;
94621                   return {
94622                     type: 'countrycoder',
94623                     location: location,
94624                     id: _id2
94625                   };
94626                 }
94627               }
94628
94629               if (this._strict) {
94630                 throw new Error("validateLocation:  Invalid location: \"".concat(location, "\"."));
94631               } else {
94632                 return null;
94633               }
94634             } // resolveLocation
94635             // `location`  The location to resolve
94636             //
94637             // Pass a `location` value to resolve
94638             //
94639             // Returns a result like:
94640             //   {
94641             //     type:      'point', 'geojson', or 'countrycoder'
94642             //     location:  the queried location
94643             //     id:        a stable identifier for the feature
94644             //     feature:   the resolved GeoJSON feature
94645             //   }
94646             //  or `null` if the location is invalid
94647             //
94648
94649           }, {
94650             key: "resolveLocation",
94651             value: function resolveLocation(location) {
94652               var valid = this.validateLocation(location);
94653               if (!valid) return null;
94654               var id = valid.id; // return a result from cache if we can
94655
94656               if (this._cache[id]) {
94657                 return Object.assign(valid, {
94658                   feature: this._cache[id]
94659                 });
94660               } // a [lon,lat] coordinate pair?
94661
94662
94663               if (valid.type === 'point') {
94664                 var RADIUS = 25000; // meters
94665
94666                 var EDGES = 10;
94667                 var PRECISION = 3;
94668                 var area = Math.PI * RADIUS * RADIUS / 1e6; // m² to km²
94669
94670                 var feature$1 = this._cache[id] = geojsonPrecision({
94671                   type: 'Feature',
94672                   id: id,
94673                   properties: {
94674                     id: id,
94675                     area: Number(area.toFixed(2))
94676                   },
94677                   geometry: circleToPolygon(location, RADIUS, EDGES)
94678                 }, PRECISION);
94679                 return Object.assign(valid, {
94680                   feature: feature$1
94681                 }); // a .geojson filename?
94682               } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
94683                 var _feature = _cloneDeep(feature(id));
94684
94685                 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
94686                 // CountryCoder includes higher level features which are made up of members.
94687                 // These features don't have their own geometry, but CountryCoder provides an
94688                 //   `aggregateFeature` method to combine these members into a MultiPolygon.
94689                 // BUT, when we try to actually work with these aggregated MultiPolygons,
94690                 //   Turf/JSTS gets crashy because of topography bugs.
94691                 // SO, we'll aggregate the features ourselves by unioning them together.
94692                 // This approach also has the benefit of removing all the internal boaders and
94693                 //   simplifying the regional polygons a lot.
94694
94695                 if (Array.isArray(props.members)) {
94696                   var seed = _feature.geometry ? _feature : null;
94697                   var aggregate = props.members.reduce(_locationReducer.bind(this), seed);
94698                   _feature.geometry = aggregate.geometry;
94699                 } // ensure `area` property exists
94700
94701
94702                 if (!props.area) {
94703                   var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
94704
94705
94706                   props.area = Number(_area.toFixed(2));
94707                 } // ensure `id` property exists
94708
94709
94710                 _feature.id = id;
94711                 props.id = id;
94712                 this._cache[id] = _feature;
94713                 return Object.assign(valid, {
94714                   feature: _feature
94715                 });
94716               }
94717
94718               if (this._strict) {
94719                 throw new Error("resolveLocation:  Couldn't resolve location \"".concat(location, "\"."));
94720               } else {
94721                 return null;
94722               }
94723             } // validateLocationSet
94724             // `locationSet`  the locationSet to validate
94725             //
94726             // Pass a locationSet Object to validate like:
94727             //   {
94728             //     include: [ Array of locations ],
94729             //     exclude: [ Array of locations ]
94730             //   }
94731             //
94732             // Returns a result like:
94733             //   {
94734             //     type:         'locationset'
94735             //     locationSet:  the queried locationSet
94736             //     id:           the stable identifier for the feature
94737             //   }
94738             // or `null` if the locationSet is invalid
94739             //
94740
94741           }, {
94742             key: "validateLocationSet",
94743             value: function validateLocationSet(locationSet) {
94744               locationSet = locationSet || {};
94745               var validator = this.validateLocation.bind(this);
94746               var include = (locationSet.include || []).map(validator).filter(Boolean);
94747               var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
94748
94749               if (!include.length) {
94750                 if (this._strict) {
94751                   throw new Error("validateLocationSet:  LocationSet includes nothing.");
94752                 } else {
94753                   // non-strict mode, replace an empty locationSet with one that includes "the world"
94754                   locationSet.include = ['Q2'];
94755                   include = [{
94756                     type: 'countrycoder',
94757                     location: 'Q2',
94758                     id: 'Q2'
94759                   }];
94760                 }
94761               } // generate stable identifier
94762
94763
94764               include.sort(_sortLocations);
94765               var id = '+[' + include.map(function (d) {
94766                 return d.id;
94767               }).join(',') + ']';
94768
94769               if (exclude.length) {
94770                 exclude.sort(_sortLocations);
94771                 id += '-[' + exclude.map(function (d) {
94772                   return d.id;
94773                 }).join(',') + ']';
94774               }
94775
94776               return {
94777                 type: 'locationset',
94778                 locationSet: locationSet,
94779                 id: id
94780               };
94781             } // resolveLocationSet
94782             // `locationSet`  the locationSet to resolve
94783             //
94784             // Pass a locationSet Object to validate like:
94785             //   {
94786             //     include: [ Array of locations ],
94787             //     exclude: [ Array of locations ]
94788             //   }
94789             //
94790             // Returns a result like:
94791             //   {
94792             //     type:         'locationset'
94793             //     locationSet:  the queried locationSet
94794             //     id:           the stable identifier for the feature
94795             //     feature:      the resolved GeoJSON feature
94796             //   }
94797             // or `null` if the locationSet is invalid
94798             //
94799
94800           }, {
94801             key: "resolveLocationSet",
94802             value: function resolveLocationSet(locationSet) {
94803               locationSet = locationSet || {};
94804               var valid = this.validateLocationSet(locationSet);
94805               if (!valid) return null;
94806               var id = valid.id; // return a result from cache if we can
94807
94808               if (this._cache[id]) {
94809                 return Object.assign(valid, {
94810                   feature: this._cache[id]
94811                 });
94812               }
94813
94814               var resolver = this.resolveLocation.bind(this);
94815               var include = (locationSet.include || []).map(resolver).filter(Boolean);
94816               var exclude = (locationSet.exclude || []).map(resolver).filter(Boolean); // return quickly if it's a single included location..
94817
94818               if (include.length === 1 && exclude.length === 0) {
94819                 return Object.assign(valid, {
94820                   feature: include[0].feature
94821                 });
94822               } // calculate unions
94823
94824
94825               var includeGeoJSON = include.map(function (d) {
94826                 return d.location;
94827               }).reduce(_locationReducer.bind(this), null);
94828               var excludeGeoJSON = exclude.map(function (d) {
94829                 return d.location;
94830               }).reduce(_locationReducer.bind(this), null); // calculate difference, update `area` and return result
94831
94832               var resultGeoJSON = excludeGeoJSON ? _clip(includeGeoJSON, excludeGeoJSON, 'DIFFERENCE') : includeGeoJSON;
94833               var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
94834
94835               resultGeoJSON.id = id;
94836               resultGeoJSON.properties = {
94837                 id: id,
94838                 area: Number(area.toFixed(2))
94839               };
94840               this._cache[id] = resultGeoJSON;
94841               return Object.assign(valid, {
94842                 feature: resultGeoJSON
94843               });
94844             } // strict
94845             //
94846
94847           }, {
94848             key: "strict",
94849             value: function strict(val) {
94850               if (val === undefined) {
94851                 // get
94852                 return this._strict;
94853               } else {
94854                 // set
94855                 this._strict = val;
94856                 return this;
94857               }
94858             } // cache
94859             // convenience method to access the internal cache
94860
94861           }, {
94862             key: "cache",
94863             value: function cache() {
94864               return this._cache;
94865             } // stringify
94866             // convenience method to prettyStringify the given object
94867
94868           }, {
94869             key: "stringify",
94870             value: function stringify(obj, options) {
94871               return jsonStringifyPrettyCompact(obj, options);
94872             }
94873           }]);
94874
94875           return _default;
94876         }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
94877
94878         function _clip(a, b, which) {
94879           var fn = {
94880             UNION: index$1.union,
94881             DIFFERENCE: index$1.difference
94882           }[which];
94883           var coords = fn(a.geometry.coordinates, b.geometry.coordinates);
94884           return {
94885             type: 'Feature',
94886             properties: {},
94887             geometry: {
94888               type: whichType(coords),
94889               coordinates: coords
94890             }
94891           }; // is this a Polygon or a MultiPolygon?
94892
94893           function whichType(coords) {
94894             var a = Array.isArray(coords);
94895             var b = a && Array.isArray(coords[0]);
94896             var c = b && Array.isArray(coords[0][0]);
94897             var d = c && Array.isArray(coords[0][0][0]);
94898             return d ? 'MultiPolygon' : 'Polygon';
94899           }
94900         } // Reduce an array of locations into a single GeoJSON feature
94901
94902
94903         function _locationReducer(accumulator, location) {
94904           /* eslint-disable no-console, no-invalid-this */
94905           var result;
94906
94907           try {
94908             var resolved = this.resolveLocation(location);
94909
94910             if (!resolved || !resolved.feature) {
94911               console.warn("Warning:  Couldn't resolve location \"".concat(location, "\""));
94912               return accumulator;
94913             }
94914
94915             result = !accumulator ? resolved.feature : _clip(accumulator, resolved.feature, 'UNION');
94916           } catch (e) {
94917             console.warn("Warning:  Error resolving location \"".concat(location, "\""));
94918             console.warn(e);
94919             result = accumulator;
94920           }
94921
94922           return result;
94923           /* eslint-enable no-console, no-invalid-this */
94924         }
94925
94926         function _cloneDeep(obj) {
94927           return JSON.parse(JSON.stringify(obj));
94928         } // Sorting the location lists is ok because they end up unioned together.
94929         // This sorting makes it possible to generate a deterministic id.
94930
94931
94932         function _sortLocations(a, b) {
94933           var rank = {
94934             countrycoder: 1,
94935             geojson: 2,
94936             point: 3
94937           };
94938           var aRank = rank[a.type];
94939           var bRank = rank[b.type];
94940           return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
94941         }
94942
94943         var _oci = null;
94944         function uiSuccess(context) {
94945           var MAXEVENTS = 2;
94946           var dispatch$1 = dispatch('cancel');
94947
94948           var _changeset;
94949
94950           var _location;
94951
94952           ensureOSMCommunityIndex(); // start fetching the data
94953
94954           function ensureOSMCommunityIndex() {
94955             var data = _mainFileFetcher;
94956             return Promise.all([data.get('oci_resources'), data.get('oci_features')]).then(function (vals) {
94957               if (_oci) return _oci;
94958               var ociResources = vals[0].resources;
94959               var loco = new _default$3(vals[1]);
94960               var ociFeatures = {};
94961               Object.values(ociResources).forEach(function (resource) {
94962                 var feature = loco.resolveLocationSet(resource.locationSet).feature;
94963                 var ociFeature = ociFeatures[feature.id];
94964
94965                 if (!ociFeature) {
94966                   ociFeature = JSON.parse(JSON.stringify(feature)); // deep clone
94967
94968                   ociFeature.properties.resourceIDs = new Set();
94969                   ociFeatures[feature.id] = ociFeature;
94970                 }
94971
94972                 ociFeature.properties.resourceIDs.add(resource.id);
94973               });
94974               return _oci = {
94975                 features: ociFeatures,
94976                 resources: ociResources,
94977                 query: whichPolygon_1({
94978                   type: 'FeatureCollection',
94979                   features: Object.values(ociFeatures)
94980                 })
94981               };
94982             });
94983           } // string-to-date parsing in JavaScript is weird
94984
94985
94986           function parseEventDate(when) {
94987             if (!when) return;
94988             var raw = when.trim();
94989             if (!raw) return;
94990
94991             if (!/Z$/.test(raw)) {
94992               // if no trailing 'Z', add one
94993               raw += 'Z'; // this forces date to be parsed as a UTC date
94994             }
94995
94996             var parsed = new Date(raw);
94997             return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
94998           }
94999
95000           function success(selection) {
95001             var header = selection.append('div').attr('class', 'header fillL');
95002             header.append('h3').html(_t.html('success.just_edited'));
95003             header.append('button').attr('class', 'close').on('click', function () {
95004               return dispatch$1.call('cancel');
95005             }).call(svgIcon('#iD-icon-close'));
95006             var body = selection.append('div').attr('class', 'body save-success fillL');
95007             var summary = body.append('div').attr('class', 'save-summary');
95008             summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
95009               where: _location
95010             }));
95011             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'));
95012             var osm = context.connection();
95013             if (!osm) return;
95014             var changesetURL = osm.changesetURL(_changeset.id);
95015             var table = summary.append('table').attr('class', 'summary-table');
95016             var row = table.append('tr').attr('class', 'summary-row');
95017             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');
95018             var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
95019             summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
95020             summaryDetail.append('div').html(_t.html('success.changeset_id', {
95021               changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
95022             })); // Get OSM community index features intersecting the map..
95023
95024             ensureOSMCommunityIndex().then(function (oci) {
95025               var communities = [];
95026               var properties = oci.query(context.map().center(), true) || []; // Gather the communities from the result
95027
95028               properties.forEach(function (props) {
95029                 var resourceIDs = Array.from(props.resourceIDs);
95030                 resourceIDs.forEach(function (resourceID) {
95031                   var resource = oci.resources[resourceID];
95032                   communities.push({
95033                     area: props.area || Infinity,
95034                     order: resource.order || 0,
95035                     resource: resource
95036                   });
95037                 });
95038               }); // sort communities by feature area ascending, community order descending
95039
95040               communities.sort(function (a, b) {
95041                 return a.area - b.area || b.order - a.order;
95042               });
95043               body.call(showCommunityLinks, communities.map(function (c) {
95044                 return c.resource;
95045               }));
95046             });
95047           }
95048
95049           function showCommunityLinks(selection, resources) {
95050             var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
95051             communityLinks.append('h3').html(_t.html('success.like_osm'));
95052             var table = communityLinks.append('table').attr('class', 'community-table');
95053             var row = table.selectAll('.community-row').data(resources);
95054             var rowEnter = row.enter().append('tr').attr('class', 'community-row');
95055             rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
95056               return d.url;
95057             }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
95058               return "#community-".concat(d.type);
95059             });
95060             var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
95061             communityDetail.each(showCommunityDetails);
95062             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'));
95063           }
95064
95065           function showCommunityDetails(d) {
95066             var selection = select(this);
95067             var communityID = d.id;
95068             var replacements = {
95069               url: linkify(d.url),
95070               signupUrl: linkify(d.signupUrl || d.url)
95071             };
95072             selection.append('div').attr('class', 'community-name').append('a').attr('target', '_blank').attr('href', d.url).html(_t.html("community.".concat(d.id, ".name")));
95073             var descriptionHTML = _t.html("community.".concat(d.id, ".description"), replacements);
95074
95075             if (d.type === 'reddit') {
95076               // linkify subreddits  #4997
95077               descriptionHTML = descriptionHTML.replace(/(\/r\/\w*\/*)/i, function (match) {
95078                 return linkify(d.url, match);
95079               });
95080             }
95081
95082             selection.append('div').attr('class', 'community-description').html(descriptionHTML);
95083
95084             if (d.extendedDescription || d.languageCodes && d.languageCodes.length) {
95085               selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
95086             }
95087
95088             var nextEvents = (d.events || []).map(function (event) {
95089               event.date = parseEventDate(event.when);
95090               return event;
95091             }).filter(function (event) {
95092               // date is valid and future (or today)
95093               var t = event.date.getTime();
95094               var now = new Date().setHours(0, 0, 0, 0);
95095               return !isNaN(t) && t >= now;
95096             }).sort(function (a, b) {
95097               // sort by date ascending
95098               return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
95099             }).slice(0, MAXEVENTS); // limit number of events shown
95100
95101             if (nextEvents.length) {
95102               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);
95103             }
95104
95105             function showMore(selection) {
95106               var more = selection.selectAll('.community-more').data([0]);
95107               var moreEnter = more.enter().append('div').attr('class', 'community-more');
95108
95109               if (d.extendedDescription) {
95110                 moreEnter.append('div').attr('class', 'community-extended-description').html(_t.html("community.".concat(d.id, ".extendedDescription"), replacements));
95111               }
95112
95113               if (d.languageCodes && d.languageCodes.length) {
95114                 var languageList = d.languageCodes.map(function (code) {
95115                   return _mainLocalizer.languageName(code);
95116                 }).join(', ');
95117                 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
95118                   languages: languageList
95119                 }));
95120               }
95121             }
95122
95123             function showNextEvents(selection) {
95124               var events = selection.append('div').attr('class', 'community-events');
95125               var item = events.selectAll('.community-event').data(nextEvents);
95126               var itemEnter = item.enter().append('div').attr('class', 'community-event');
95127               itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
95128                 return d.url;
95129               }).html(function (d) {
95130                 var name = d.name;
95131
95132                 if (d.i18n && d.id) {
95133                   name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
95134                     "default": name
95135                   });
95136                 }
95137
95138                 return name;
95139               });
95140               itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
95141                 var options = {
95142                   weekday: 'short',
95143                   day: 'numeric',
95144                   month: 'short',
95145                   year: 'numeric'
95146                 };
95147
95148                 if (d.date.getHours() || d.date.getMinutes()) {
95149                   // include time if it has one
95150                   options.hour = 'numeric';
95151                   options.minute = 'numeric';
95152                 }
95153
95154                 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
95155               });
95156               itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
95157                 var where = d.where;
95158
95159                 if (d.i18n && d.id) {
95160                   where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
95161                     "default": where
95162                   });
95163                 }
95164
95165                 return where;
95166               });
95167               itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
95168                 var description = d.description;
95169
95170                 if (d.i18n && d.id) {
95171                   description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
95172                     "default": description
95173                   });
95174                 }
95175
95176                 return description;
95177               });
95178             }
95179
95180             function linkify(url, text) {
95181               text = text || url;
95182               return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
95183             }
95184           }
95185
95186           success.changeset = function (val) {
95187             if (!arguments.length) return _changeset;
95188             _changeset = val;
95189             return success;
95190           };
95191
95192           success.location = function (val) {
95193             if (!arguments.length) return _location;
95194             _location = val;
95195             return success;
95196           };
95197
95198           return utilRebind(success, dispatch$1, 'on');
95199         }
95200
95201         function modeSave(context) {
95202           var mode = {
95203             id: 'save'
95204           };
95205           var keybinding = utilKeybinding('modeSave');
95206           var commit = uiCommit(context).on('cancel', cancel);
95207
95208           var _conflictsUi; // uiConflicts
95209
95210
95211           var _location;
95212
95213           var _success;
95214
95215           var uploader = context.uploader().on('saveStarted.modeSave', function () {
95216             keybindingOff();
95217           }) // fire off some async work that we want to be ready later
95218           .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
95219             cancel();
95220           }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
95221
95222           function cancel() {
95223             context.enter(modeBrowse(context));
95224           }
95225
95226           function showProgress(num, total) {
95227             var modal = context.container().select('.loading-modal .modal-section');
95228             var progress = modal.selectAll('.progress').data([0]); // enter/update
95229
95230             progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
95231               num: num,
95232               total: total
95233             }));
95234           }
95235
95236           function showConflicts(changeset, conflicts, origChanges) {
95237             var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
95238             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
95239             _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
95240               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95241               selection.remove();
95242               keybindingOn();
95243               uploader.cancelConflictResolution();
95244             }).on('save', function () {
95245               context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95246               selection.remove();
95247               uploader.processResolvedConflicts(changeset);
95248             });
95249             selection.call(_conflictsUi);
95250           }
95251
95252           function showErrors(errors) {
95253             keybindingOn();
95254             var selection = uiConfirm(context.container());
95255             selection.select('.modal-section.header').append('h3').text(_t('save.error'));
95256             addErrors(selection, errors);
95257             selection.okButton();
95258           }
95259
95260           function addErrors(selection, data) {
95261             var message = selection.select('.modal-section.message-text');
95262             var items = message.selectAll('.error-container').data(data);
95263             var enter = items.enter().append('div').attr('class', 'error-container');
95264             enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
95265               return d.msg || _t('save.unknown_error_details');
95266             }).on('click', function (d3_event) {
95267               d3_event.preventDefault();
95268               var error = select(this);
95269               var detail = select(this.nextElementSibling);
95270               var exp = error.classed('expanded');
95271               detail.style('display', exp ? 'none' : 'block');
95272               error.classed('expanded', !exp);
95273             });
95274             var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
95275             details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
95276               return d.details || [];
95277             }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
95278               return d;
95279             });
95280             items.exit().remove();
95281           }
95282
95283           function showSuccess(changeset) {
95284             commit.reset();
95285
95286             var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
95287               context.ui().sidebar.hide();
95288             });
95289
95290             context.enter(modeBrowse(context).sidebar(ui));
95291           }
95292
95293           function keybindingOn() {
95294             select(document).call(keybinding.on('⎋', cancel, true));
95295           }
95296
95297           function keybindingOff() {
95298             select(document).call(keybinding.unbind);
95299           } // Reverse geocode current map location so we can display a message on
95300           // the success screen like "Thank you for editing around place, region."
95301
95302
95303           function prepareForSuccess() {
95304             _success = uiSuccess(context);
95305             _location = null;
95306             if (!services.geocoder) return;
95307             services.geocoder.reverse(context.map().center(), function (err, result) {
95308               if (err || !result || !result.address) return;
95309               var addr = result.address;
95310               var place = addr && (addr.town || addr.city || addr.county) || '';
95311               var region = addr && (addr.state || addr.country) || '';
95312               var separator = place && region ? _t('success.thank_you_where.separator') : '';
95313               _location = _t('success.thank_you_where.format', {
95314                 place: place,
95315                 separator: separator,
95316                 region: region
95317               });
95318             });
95319           }
95320
95321           mode.selectedIDs = function () {
95322             return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
95323           };
95324
95325           mode.enter = function () {
95326             // Show sidebar
95327             context.ui().sidebar.expand();
95328
95329             function done() {
95330               context.ui().sidebar.show(commit);
95331             }
95332
95333             keybindingOn();
95334             context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
95335             var osm = context.connection();
95336
95337             if (!osm) {
95338               cancel();
95339               return;
95340             }
95341
95342             if (osm.authenticated()) {
95343               done();
95344             } else {
95345               osm.authenticate(function (err) {
95346                 if (err) {
95347                   cancel();
95348                 } else {
95349                   done();
95350                 }
95351               });
95352             }
95353           };
95354
95355           mode.exit = function () {
95356             keybindingOff();
95357             context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
95358             context.ui().sidebar.hide();
95359           };
95360
95361           return mode;
95362         }
95363
95364         function uiToolOldDrawModes(context) {
95365           var tool = {
95366             id: 'old_modes',
95367             label: _t.html('toolbar.add_feature')
95368           };
95369           var modes = [modeAddPoint(context, {
95370             title: _t.html('modes.add_point.title'),
95371             button: 'point',
95372             description: _t.html('modes.add_point.description'),
95373             preset: _mainPresetIndex.item('point'),
95374             key: '1'
95375           }), modeAddLine(context, {
95376             title: _t.html('modes.add_line.title'),
95377             button: 'line',
95378             description: _t.html('modes.add_line.description'),
95379             preset: _mainPresetIndex.item('line'),
95380             key: '2'
95381           }), modeAddArea(context, {
95382             title: _t.html('modes.add_area.title'),
95383             button: 'area',
95384             description: _t.html('modes.add_area.description'),
95385             preset: _mainPresetIndex.item('area'),
95386             key: '3'
95387           })];
95388
95389           function enabled() {
95390             return osmEditable();
95391           }
95392
95393           function osmEditable() {
95394             return context.editable();
95395           }
95396
95397           modes.forEach(function (mode) {
95398             context.keybinding().on(mode.key, function () {
95399               if (!enabled()) return;
95400
95401               if (mode.id === context.mode().id) {
95402                 context.enter(modeBrowse(context));
95403               } else {
95404                 context.enter(mode);
95405               }
95406             });
95407           });
95408
95409           tool.render = function (selection) {
95410             var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
95411
95412             var debouncedUpdate = debounce(update, 500, {
95413               leading: true,
95414               trailing: true
95415             });
95416
95417             context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
95418             context.on('enter.modes', update);
95419             update();
95420
95421             function update() {
95422               var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
95423                 return d.id;
95424               }); // exit
95425
95426               buttons.exit().remove(); // enter
95427
95428               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
95429                 return d.id + ' add-button bar-button';
95430               }).on('click.mode-buttons', function (d3_event, d) {
95431                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
95432
95433                 var currMode = context.mode().id;
95434                 if (/^draw/.test(currMode)) return;
95435
95436                 if (d.id === currMode) {
95437                   context.enter(modeBrowse(context));
95438                 } else {
95439                   context.enter(d);
95440                 }
95441               }).call(uiTooltip().placement('bottom').title(function (d) {
95442                 return d.description;
95443               }).keys(function (d) {
95444                 return [d.key];
95445               }).scrollContainer(context.container().select('.top-toolbar')));
95446               buttonsEnter.each(function (d) {
95447                 select(this).call(svgIcon('#iD-icon-' + d.button));
95448               });
95449               buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
95450                 return mode.title;
95451               }); // if we are adding/removing the buttons, check if toolbar has overflowed
95452
95453               if (buttons.enter().size() || buttons.exit().size()) {
95454                 context.ui().checkOverflow('.top-toolbar', true);
95455               } // update
95456
95457
95458               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
95459                 return !enabled();
95460               }).classed('active', function (d) {
95461                 return context.mode() && context.mode().button === d.button;
95462               });
95463             }
95464           };
95465
95466           return tool;
95467         }
95468
95469         function uiToolNotes(context) {
95470           var tool = {
95471             id: 'notes',
95472             label: _t.html('modes.add_note.label')
95473           };
95474           var mode = modeAddNote(context);
95475
95476           function enabled() {
95477             return notesEnabled() && notesEditable();
95478           }
95479
95480           function notesEnabled() {
95481             var noteLayer = context.layers().layer('notes');
95482             return noteLayer && noteLayer.enabled();
95483           }
95484
95485           function notesEditable() {
95486             var mode = context.mode();
95487             return context.map().notesEditable() && mode && mode.id !== 'save';
95488           }
95489
95490           context.keybinding().on(mode.key, function () {
95491             if (!enabled()) return;
95492
95493             if (mode.id === context.mode().id) {
95494               context.enter(modeBrowse(context));
95495             } else {
95496               context.enter(mode);
95497             }
95498           });
95499
95500           tool.render = function (selection) {
95501             var debouncedUpdate = debounce(update, 500, {
95502               leading: true,
95503               trailing: true
95504             });
95505
95506             context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
95507             context.on('enter.notes', update);
95508             update();
95509
95510             function update() {
95511               var showNotes = notesEnabled();
95512               var data = showNotes ? [mode] : [];
95513               var buttons = selection.selectAll('button.add-button').data(data, function (d) {
95514                 return d.id;
95515               }); // exit
95516
95517               buttons.exit().remove(); // enter
95518
95519               var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
95520                 return d.id + ' add-button bar-button';
95521               }).on('click.notes', function (d3_event, d) {
95522                 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
95523
95524                 var currMode = context.mode().id;
95525                 if (/^draw/.test(currMode)) return;
95526
95527                 if (d.id === currMode) {
95528                   context.enter(modeBrowse(context));
95529                 } else {
95530                   context.enter(d);
95531                 }
95532               }).call(uiTooltip().placement('bottom').title(function (d) {
95533                 return d.description;
95534               }).keys(function (d) {
95535                 return [d.key];
95536               }).scrollContainer(context.container().select('.top-toolbar')));
95537               buttonsEnter.each(function (d) {
95538                 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
95539               }); // if we are adding/removing the buttons, check if toolbar has overflowed
95540
95541               if (buttons.enter().size() || buttons.exit().size()) {
95542                 context.ui().checkOverflow('.top-toolbar', true);
95543               } // update
95544
95545
95546               buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
95547                 return !enabled();
95548               }).classed('active', function (d) {
95549                 return context.mode() && context.mode().button === d.button;
95550               });
95551             }
95552           };
95553
95554           tool.uninstall = function () {
95555             context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
95556             context.map().on('move.notes', null).on('drawn.notes', null);
95557           };
95558
95559           return tool;
95560         }
95561
95562         function uiToolSave(context) {
95563           var tool = {
95564             id: 'save',
95565             label: _t.html('save.title')
95566           };
95567           var button = null;
95568           var tooltipBehavior = null;
95569           var history = context.history();
95570           var key = uiCmd('⌘S');
95571           var _numChanges = 0;
95572
95573           function isSaving() {
95574             var mode = context.mode();
95575             return mode && mode.id === 'save';
95576           }
95577
95578           function isDisabled() {
95579             return _numChanges === 0 || isSaving();
95580           }
95581
95582           function save(d3_event) {
95583             d3_event.preventDefault();
95584
95585             if (!context.inIntro() && !isSaving() && history.hasChanges()) {
95586               context.enter(modeSave(context));
95587             }
95588           }
95589
95590           function bgColor() {
95591             var step;
95592
95593             if (_numChanges === 0) {
95594               return null;
95595             } else if (_numChanges <= 50) {
95596               step = _numChanges / 50;
95597               return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
95598             } else {
95599               step = Math.min((_numChanges - 50) / 50, 1.0);
95600               return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
95601             }
95602           }
95603
95604           function updateCount() {
95605             var val = history.difference().summary().length;
95606             if (val === _numChanges) return;
95607             _numChanges = val;
95608
95609             if (tooltipBehavior) {
95610               tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
95611             }
95612
95613             if (button) {
95614               button.classed('disabled', isDisabled()).style('background', bgColor());
95615               button.select('span.count').html(_numChanges);
95616             }
95617           }
95618
95619           tool.render = function (selection) {
95620             tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
95621             var lastPointerUpType;
95622             button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
95623               lastPointerUpType = d3_event.pointerType;
95624             }).on('click', function (d3_event) {
95625               save(d3_event);
95626
95627               if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
95628                 // there are no tooltips for touch interactions so flash feedback instead
95629                 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
95630               }
95631
95632               lastPointerUpType = null;
95633             }).call(tooltipBehavior);
95634             button.call(svgIcon('#iD-icon-save'));
95635             button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
95636             updateCount();
95637             context.keybinding().on(key, save, true);
95638             context.history().on('change.save', updateCount);
95639             context.on('enter.save', function () {
95640               if (button) {
95641                 button.classed('disabled', isDisabled());
95642
95643                 if (isSaving()) {
95644                   button.call(tooltipBehavior.hide);
95645                 }
95646               }
95647             });
95648           };
95649
95650           tool.uninstall = function () {
95651             context.keybinding().off(key, true);
95652             context.history().on('change.save', null);
95653             context.on('enter.save', null);
95654             button = null;
95655             tooltipBehavior = null;
95656           };
95657
95658           return tool;
95659         }
95660
95661         function uiToolSidebarToggle(context) {
95662           var tool = {
95663             id: 'sidebar_toggle',
95664             label: _t.html('toolbar.inspect')
95665           };
95666
95667           tool.render = function (selection) {
95668             selection.append('button').attr('class', 'bar-button').on('click', function () {
95669               context.ui().sidebar.toggle();
95670             }).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')));
95671           };
95672
95673           return tool;
95674         }
95675
95676         function uiToolUndoRedo(context) {
95677           var tool = {
95678             id: 'undo_redo',
95679             label: _t.html('toolbar.undo_redo')
95680           };
95681           var commands = [{
95682             id: 'undo',
95683             cmd: uiCmd('⌘Z'),
95684             action: function action() {
95685               context.undo();
95686             },
95687             annotation: function annotation() {
95688               return context.history().undoAnnotation();
95689             },
95690             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
95691           }, {
95692             id: 'redo',
95693             cmd: uiCmd('⌘⇧Z'),
95694             action: function action() {
95695               context.redo();
95696             },
95697             annotation: function annotation() {
95698               return context.history().redoAnnotation();
95699             },
95700             icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
95701           }];
95702
95703           function editable() {
95704             return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
95705             /* ignore min zoom */
95706             );
95707           }
95708
95709           tool.render = function (selection) {
95710             var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
95711               return d.annotation() ? _t.html(d.id + '.tooltip', {
95712                 action: d.annotation()
95713               }) : _t.html(d.id + '.nothing');
95714             }).keys(function (d) {
95715               return [d.cmd];
95716             }).scrollContainer(context.container().select('.top-toolbar'));
95717             var lastPointerUpType;
95718             var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
95719               return 'disabled ' + d.id + '-button bar-button';
95720             }).on('pointerup', function (d3_event) {
95721               // `pointerup` is always called before `click`
95722               lastPointerUpType = d3_event.pointerType;
95723             }).on('click', function (d3_event, d) {
95724               d3_event.preventDefault();
95725               var annotation = d.annotation();
95726
95727               if (editable() && annotation) {
95728                 d.action();
95729               }
95730
95731               if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
95732                 // there are no tooltips for touch interactions so flash feedback instead
95733                 var text = annotation ? _t(d.id + '.tooltip', {
95734                   action: annotation
95735                 }) : _t(d.id + '.nothing');
95736                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
95737               }
95738
95739               lastPointerUpType = null;
95740             }).call(tooltipBehavior);
95741             buttons.each(function (d) {
95742               select(this).call(svgIcon('#' + d.icon));
95743             });
95744             context.keybinding().on(commands[0].cmd, function (d3_event) {
95745               d3_event.preventDefault();
95746               if (editable()) commands[0].action();
95747             }).on(commands[1].cmd, function (d3_event) {
95748               d3_event.preventDefault();
95749               if (editable()) commands[1].action();
95750             });
95751
95752             var debouncedUpdate = debounce(update, 500, {
95753               leading: true,
95754               trailing: true
95755             });
95756
95757             context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
95758             context.history().on('change.undo_redo', function (difference) {
95759               if (difference) update();
95760             });
95761             context.on('enter.undo_redo', update);
95762
95763             function update() {
95764               buttons.classed('disabled', function (d) {
95765                 return !editable() || !d.annotation();
95766               }).each(function () {
95767                 var selection = select(this);
95768
95769                 if (!selection.select('.tooltip.in').empty()) {
95770                   selection.call(tooltipBehavior.updateContent);
95771                 }
95772               });
95773             }
95774           };
95775
95776           tool.uninstall = function () {
95777             context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
95778             context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
95779             context.history().on('change.undo_redo', null);
95780             context.on('enter.undo_redo', null);
95781           };
95782
95783           return tool;
95784         }
95785
95786         function uiTopToolbar(context) {
95787           var sidebarToggle = uiToolSidebarToggle(context),
95788               modes = uiToolOldDrawModes(context),
95789               notes = uiToolNotes(context),
95790               undoRedo = uiToolUndoRedo(context),
95791               save = uiToolSave(context);
95792
95793           function notesEnabled() {
95794             var noteLayer = context.layers().layer('notes');
95795             return noteLayer && noteLayer.enabled();
95796           }
95797
95798           function topToolbar(bar) {
95799             bar.on('wheel.topToolbar', function (d3_event) {
95800               if (!d3_event.deltaX) {
95801                 // translate vertical scrolling into horizontal scrolling in case
95802                 // the user doesn't have an input device that can scroll horizontally
95803                 bar.node().scrollLeft += d3_event.deltaY;
95804               }
95805             });
95806
95807             var debouncedUpdate = debounce(update, 500, {
95808               leading: true,
95809               trailing: true
95810             });
95811
95812             context.layers().on('change.topToolbar', debouncedUpdate);
95813             update();
95814
95815             function update() {
95816               var tools = [sidebarToggle, 'spacer', modes];
95817               tools.push('spacer');
95818
95819               if (notesEnabled()) {
95820                 tools = tools.concat([notes, 'spacer']);
95821               }
95822
95823               tools = tools.concat([undoRedo, save]);
95824               var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
95825                 return d.id || d;
95826               });
95827               toolbarItems.exit().each(function (d) {
95828                 if (d.uninstall) {
95829                   d.uninstall();
95830                 }
95831               }).remove();
95832               var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
95833                 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
95834                 if (d.klass) classes += ' ' + d.klass;
95835                 return classes;
95836               });
95837               var actionableItems = itemsEnter.filter(function (d) {
95838                 return d !== 'spacer';
95839               });
95840               actionableItems.append('div').attr('class', 'item-content').each(function (d) {
95841                 select(this).call(d.render, bar);
95842               });
95843               actionableItems.append('div').attr('class', 'item-label').html(function (d) {
95844                 return d.label;
95845               });
95846             }
95847           }
95848
95849           return topToolbar;
95850         }
95851
95852         var sawVersion = null;
95853         var isNewVersion = false;
95854         var isNewUser = false;
95855         function uiVersion(context) {
95856           var currVersion = context.version;
95857           var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
95858
95859           if (sawVersion === null && matchedVersion !== null) {
95860             if (corePreferences('sawVersion')) {
95861               isNewUser = false;
95862               isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
95863             } else {
95864               isNewUser = true;
95865               isNewVersion = true;
95866             }
95867
95868             corePreferences('sawVersion', currVersion);
95869             sawVersion = currVersion;
95870           }
95871
95872           return function (selection) {
95873             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
95874
95875             if (isNewVersion && !isNewUser) {
95876               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', {
95877                 version: currVersion
95878               })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
95879             }
95880           };
95881         }
95882
95883         function uiZoom(context) {
95884           var zooms = [{
95885             id: 'zoom-in',
95886             icon: 'iD-icon-plus',
95887             title: _t.html('zoom.in'),
95888             action: zoomIn,
95889             disabled: function disabled() {
95890               return !context.map().canZoomIn();
95891             },
95892             disabledTitle: _t.html('zoom.disabled.in'),
95893             key: '+'
95894           }, {
95895             id: 'zoom-out',
95896             icon: 'iD-icon-minus',
95897             title: _t.html('zoom.out'),
95898             action: zoomOut,
95899             disabled: function disabled() {
95900               return !context.map().canZoomOut();
95901             },
95902             disabledTitle: _t.html('zoom.disabled.out'),
95903             key: '-'
95904           }];
95905
95906           function zoomIn(d3_event) {
95907             if (d3_event.shiftKey) return;
95908             d3_event.preventDefault();
95909             context.map().zoomIn();
95910           }
95911
95912           function zoomOut(d3_event) {
95913             if (d3_event.shiftKey) return;
95914             d3_event.preventDefault();
95915             context.map().zoomOut();
95916           }
95917
95918           function zoomInFurther(d3_event) {
95919             if (d3_event.shiftKey) return;
95920             d3_event.preventDefault();
95921             context.map().zoomInFurther();
95922           }
95923
95924           function zoomOutFurther(d3_event) {
95925             if (d3_event.shiftKey) return;
95926             d3_event.preventDefault();
95927             context.map().zoomOutFurther();
95928           }
95929
95930           return function (selection) {
95931             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
95932               if (d.disabled()) {
95933                 return d.disabledTitle;
95934               }
95935
95936               return d.title;
95937             }).keys(function (d) {
95938               return [d.key];
95939             });
95940             var lastPointerUpType;
95941             var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
95942               return d.id;
95943             }).on('pointerup.editor', function (d3_event) {
95944               lastPointerUpType = d3_event.pointerType;
95945             }).on('click.editor', function (d3_event, d) {
95946               if (!d.disabled()) {
95947                 d.action(d3_event);
95948               } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
95949                 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
95950               }
95951
95952               lastPointerUpType = null;
95953             }).call(tooltipBehavior);
95954             buttons.each(function (d) {
95955               select(this).call(svgIcon('#' + d.icon, 'light'));
95956             });
95957             utilKeybinding.plusKeys.forEach(function (key) {
95958               context.keybinding().on([key], zoomIn);
95959               context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
95960             });
95961             utilKeybinding.minusKeys.forEach(function (key) {
95962               context.keybinding().on([key], zoomOut);
95963               context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
95964             });
95965
95966             function updateButtonStates() {
95967               buttons.classed('disabled', function (d) {
95968                 return d.disabled();
95969               }).each(function () {
95970                 var selection = select(this);
95971
95972                 if (!selection.select('.tooltip.in').empty()) {
95973                   selection.call(tooltipBehavior.updateContent);
95974                 }
95975               });
95976             }
95977
95978             updateButtonStates();
95979             context.map().on('move.uiZoom', updateButtonStates);
95980           };
95981         }
95982
95983         function uiZoomToSelection(context) {
95984           function isDisabled() {
95985             var mode = context.mode();
95986             return !mode || !mode.zoomToSelected;
95987           }
95988
95989           var _lastPointerUpType;
95990
95991           function pointerup(d3_event) {
95992             _lastPointerUpType = d3_event.pointerType;
95993           }
95994
95995           function click(d3_event) {
95996             d3_event.preventDefault();
95997
95998             if (isDisabled()) {
95999               if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
96000                 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
96001               }
96002             } else {
96003               var mode = context.mode();
96004
96005               if (mode && mode.zoomToSelected) {
96006                 mode.zoomToSelected();
96007               }
96008             }
96009
96010             _lastPointerUpType = null;
96011           }
96012
96013           return function (selection) {
96014             var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
96015               if (isDisabled()) {
96016                 return _t.html('inspector.zoom_to.no_selection');
96017               }
96018
96019               return _t.html('inspector.zoom_to.title');
96020             }).keys([_t('inspector.zoom_to.key')]);
96021             var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
96022
96023             function setEnabledState() {
96024               button.classed('disabled', isDisabled());
96025
96026               if (!button.select('.tooltip.in').empty()) {
96027                 button.call(tooltipBehavior.updateContent);
96028               }
96029             }
96030
96031             context.on('enter.uiZoomToSelection', setEnabledState);
96032             setEnabledState();
96033           };
96034         }
96035
96036         function uiPane(id, context) {
96037           var _key;
96038
96039           var _label = '';
96040           var _description = '';
96041           var _iconName = '';
96042
96043           var _sections; // array of uiSection objects
96044
96045
96046           var _paneSelection = select(null);
96047
96048           var _paneTooltip;
96049
96050           var pane = {
96051             id: id
96052           };
96053
96054           pane.label = function (val) {
96055             if (!arguments.length) return _label;
96056             _label = val;
96057             return pane;
96058           };
96059
96060           pane.key = function (val) {
96061             if (!arguments.length) return _key;
96062             _key = val;
96063             return pane;
96064           };
96065
96066           pane.description = function (val) {
96067             if (!arguments.length) return _description;
96068             _description = val;
96069             return pane;
96070           };
96071
96072           pane.iconName = function (val) {
96073             if (!arguments.length) return _iconName;
96074             _iconName = val;
96075             return pane;
96076           };
96077
96078           pane.sections = function (val) {
96079             if (!arguments.length) return _sections;
96080             _sections = val;
96081             return pane;
96082           };
96083
96084           pane.selection = function () {
96085             return _paneSelection;
96086           };
96087
96088           function hidePane() {
96089             context.ui().togglePanes();
96090           }
96091
96092           pane.togglePane = function (d3_event) {
96093             if (d3_event) d3_event.preventDefault();
96094
96095             _paneTooltip.hide();
96096
96097             context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
96098           };
96099
96100           pane.renderToggleButton = function (selection) {
96101             if (!_paneTooltip) {
96102               _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
96103             }
96104
96105             selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
96106           };
96107
96108           pane.renderContent = function (selection) {
96109             // override to fully customize content
96110             if (_sections) {
96111               _sections.forEach(function (section) {
96112                 selection.call(section.render);
96113               });
96114             }
96115           };
96116
96117           pane.renderPane = function (selection) {
96118             _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
96119
96120             var heading = _paneSelection.append('div').attr('class', 'pane-heading');
96121
96122             heading.append('h2').html(_label);
96123             heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
96124
96125             _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
96126
96127             if (_key) {
96128               context.keybinding().on(_key, pane.togglePane);
96129             }
96130           };
96131
96132           return pane;
96133         }
96134
96135         function uiSectionBackgroundDisplayOptions(context) {
96136           var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
96137
96138           var _detected = utilDetect();
96139
96140           var _storedOpacity = corePreferences('background-opacity');
96141
96142           var _minVal = 0;
96143
96144           var _maxVal = _detected.cssfilters ? 3 : 1;
96145
96146           var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
96147
96148           var _options = {
96149             brightness: _storedOpacity !== null ? +_storedOpacity : 1,
96150             contrast: 1,
96151             saturation: 1,
96152             sharpness: 1
96153           };
96154
96155           function clamp(x, min, max) {
96156             return Math.max(min, Math.min(x, max));
96157           }
96158
96159           function updateValue(d, val) {
96160             val = clamp(val, _minVal, _maxVal);
96161             _options[d] = val;
96162             context.background()[d](val);
96163
96164             if (d === 'brightness') {
96165               corePreferences('background-opacity', val);
96166             }
96167
96168             section.reRender();
96169           }
96170
96171           function renderDisclosureContent(selection) {
96172             var container = selection.selectAll('.display-options-container').data([0]);
96173             var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
96174
96175             var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
96176               return 'display-control display-control-' + d;
96177             });
96178             slidersEnter.append('h5').html(function (d) {
96179               return _t.html('background.' + d);
96180             }).append('span').attr('class', function (d) {
96181               return 'display-option-value display-option-value-' + d;
96182             });
96183             var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
96184             sildersControlEnter.append('input').attr('class', function (d) {
96185               return 'display-option-input display-option-input-' + d;
96186             }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
96187               var val = select(this).property('value');
96188
96189               if (!val && d3_event && d3_event.target) {
96190                 val = d3_event.target.value;
96191               }
96192
96193               updateValue(d, val);
96194             });
96195             sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
96196               return 'display-option-reset display-option-reset-' + d;
96197             }).on('click', function (d3_event, d) {
96198               if (d3_event.button !== 0) return;
96199               updateValue(d, 1);
96200             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
96201
96202             containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
96203               d3_event.preventDefault();
96204
96205               for (var i = 0; i < _sliders.length; i++) {
96206                 updateValue(_sliders[i], 1);
96207               }
96208             }); // update
96209
96210             container = containerEnter.merge(container);
96211             container.selectAll('.display-option-input').property('value', function (d) {
96212               return _options[d];
96213             });
96214             container.selectAll('.display-option-value').html(function (d) {
96215               return Math.floor(_options[d] * 100) + '%';
96216             });
96217             container.selectAll('.display-option-reset').classed('disabled', function (d) {
96218               return _options[d] === 1;
96219             }); // first time only, set brightness if needed
96220
96221             if (containerEnter.size() && _options.brightness !== 1) {
96222               context.background().brightness(_options.brightness);
96223             }
96224           }
96225
96226           return section;
96227         }
96228
96229         function uiSettingsCustomBackground() {
96230           var dispatch$1 = dispatch('change');
96231
96232           function render(selection) {
96233             // keep separate copies of original and current settings
96234             var _origSettings = {
96235               template: corePreferences('background-custom-template')
96236             };
96237             var _currSettings = {
96238               template: corePreferences('background-custom-template')
96239             };
96240             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
96241             var modal = uiConfirm(selection).okButton();
96242             modal.classed('settings-modal settings-custom-background', true);
96243             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
96244             var textSection = modal.select('.modal-section.message-text');
96245             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, "`");
96246             textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
96247             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
96248
96249             var buttonSection = modal.select('.modal-section.buttons');
96250             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
96251             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
96252             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
96253
96254             function isSaveDisabled() {
96255               return null;
96256             } // restore the original template
96257
96258
96259             function clickCancel() {
96260               textSection.select('.field-template').property('value', _origSettings.template);
96261               corePreferences('background-custom-template', _origSettings.template);
96262               this.blur();
96263               modal.close();
96264             } // accept the current template
96265
96266
96267             function clickSave() {
96268               _currSettings.template = textSection.select('.field-template').property('value');
96269               corePreferences('background-custom-template', _currSettings.template);
96270               this.blur();
96271               modal.close();
96272               dispatch$1.call('change', this, _currSettings);
96273             }
96274           }
96275
96276           return utilRebind(render, dispatch$1, 'on');
96277         }
96278
96279         function uiSectionBackgroundList(context) {
96280           var _backgroundList = select(null);
96281
96282           var _customSource = context.background().findSource('custom');
96283
96284           var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
96285
96286           var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
96287
96288           function previousBackgroundID() {
96289             return corePreferences('background-last-used-toggle');
96290           }
96291
96292           function renderDisclosureContent(selection) {
96293             // the background list
96294             var container = selection.selectAll('.layer-background-list').data([0]);
96295             _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
96296
96297             var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
96298             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'));
96299             minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96300               d3_event.preventDefault();
96301               uiMapInMap.toggle();
96302             });
96303             minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
96304             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'));
96305             panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96306               d3_event.preventDefault();
96307               context.ui().info.toggle('background');
96308             });
96309             panelLabelEnter.append('span').html(_t.html('background.panel.description'));
96310             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'));
96311             locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
96312               d3_event.preventDefault();
96313               context.ui().info.toggle('location');
96314             });
96315             locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
96316
96317             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'));
96318
96319             _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
96320               chooseBackground(d);
96321             }, function (d) {
96322               return !d.isHidden() && !d.overlay;
96323             });
96324           }
96325
96326           function setTooltips(selection) {
96327             selection.each(function (d, i, nodes) {
96328               var item = select(this).select('label');
96329               var span = item.select('span');
96330               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
96331               var description = d.description();
96332               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
96333               item.call(uiTooltip().destroyAny);
96334
96335               if (d.id === previousBackgroundID()) {
96336                 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
96337               } else if (description || isOverflowing) {
96338                 item.call(uiTooltip().placement(placement).title(description || d.label()));
96339               }
96340             });
96341           }
96342
96343           function drawListItems(layerList, type, change, filter) {
96344             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
96345               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
96346             });
96347             var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
96348             // arrow key navigation of radio values likes to work in the order
96349             // they were added, not the display document order.
96350             .data(sources, function (d, i) {
96351               return d.id + '---' + i;
96352             });
96353             layerLinks.exit().remove();
96354             var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
96355               return d.id === 'custom';
96356             }).classed('best', function (d) {
96357               return d.best();
96358             });
96359             var label = enter.append('label');
96360             label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
96361               return d.id;
96362             }).on('change', change);
96363             label.append('span').html(function (d) {
96364               return d.label();
96365             });
96366             enter.filter(function (d) {
96367               return d.id === 'custom';
96368             }).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) {
96369               d3_event.preventDefault();
96370               editCustom();
96371             }).call(svgIcon('#iD-icon-more'));
96372             enter.filter(function (d) {
96373               return d.best();
96374             }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('&#9733;');
96375             layerList.call(updateLayerSelections);
96376           }
96377
96378           function updateLayerSelections(selection) {
96379             function active(d) {
96380               return context.background().showsLayer(d);
96381             }
96382
96383             selection.selectAll('li').classed('active', active).classed('switch', function (d) {
96384               return d.id === previousBackgroundID();
96385             }).call(setTooltips).selectAll('input').property('checked', active);
96386           }
96387
96388           function chooseBackground(d) {
96389             if (d.id === 'custom' && !d.template()) {
96390               return editCustom();
96391             }
96392
96393             var previousBackground = context.background().baseLayerSource();
96394             corePreferences('background-last-used-toggle', previousBackground.id);
96395             corePreferences('background-last-used', d.id);
96396             context.background().baseLayerSource(d);
96397           }
96398
96399           function customChanged(d) {
96400             if (d && d.template) {
96401               _customSource.template(d.template);
96402
96403               chooseBackground(_customSource);
96404             } else {
96405               _customSource.template('');
96406
96407               chooseBackground(context.background().findSource('none'));
96408             }
96409           }
96410
96411           function editCustom() {
96412             context.container().call(_settingsCustomBackground);
96413           }
96414
96415           context.background().on('change.background_list', function () {
96416             _backgroundList.call(updateLayerSelections);
96417           });
96418           context.map().on('move.background_list', debounce(function () {
96419             // layers in-view may have changed due to map move
96420             window.requestIdleCallback(section.reRender);
96421           }, 1000));
96422           return section;
96423         }
96424
96425         function uiSectionBackgroundOffset(context) {
96426           var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
96427
96428           var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
96429
96430           var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
96431
96432           function updateValue() {
96433             var meters = geoOffsetToMeters(context.background().offset());
96434             var x = +meters[0].toFixed(2);
96435             var y = +meters[1].toFixed(2);
96436             context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
96437             context.container().selectAll('.nudge-reset').classed('disabled', function () {
96438               return x === 0 && y === 0;
96439             });
96440           }
96441
96442           function resetOffset() {
96443             context.background().offset([0, 0]);
96444             updateValue();
96445           }
96446
96447           function nudge(d) {
96448             context.background().nudge(d, context.map().zoom());
96449             updateValue();
96450           }
96451
96452           function inputOffset() {
96453             var input = select(this);
96454             var d = input.node().value;
96455             if (d === '') return resetOffset();
96456             d = d.replace(/;/g, ',').split(',').map(function (n) {
96457               // if n is NaN, it will always get mapped to false.
96458               return !isNaN(n) && n;
96459             });
96460
96461             if (d.length !== 2 || !d[0] || !d[1]) {
96462               input.classed('error', true);
96463               return;
96464             }
96465
96466             context.background().offset(geoMetersToOffset(d));
96467             updateValue();
96468           }
96469
96470           function dragOffset(d3_event) {
96471             if (d3_event.button !== 0) return;
96472             var origin = [d3_event.clientX, d3_event.clientY];
96473             var pointerId = d3_event.pointerId || 'mouse';
96474             context.container().append('div').attr('class', 'nudge-surface');
96475             select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
96476
96477             if (_pointerPrefix === 'pointer') {
96478               select(window).on('pointercancel.drag-bg-offset', pointerup);
96479             }
96480
96481             function pointermove(d3_event) {
96482               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
96483               var latest = [d3_event.clientX, d3_event.clientY];
96484               var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
96485               origin = latest;
96486               nudge(d);
96487             }
96488
96489             function pointerup(d3_event) {
96490               if (pointerId !== (d3_event.pointerId || 'mouse')) return;
96491               if (d3_event.button !== 0) return;
96492               context.container().selectAll('.nudge-surface').remove();
96493               select(window).on('.drag-bg-offset', null);
96494             }
96495           }
96496
96497           function renderDisclosureContent(selection) {
96498             var container = selection.selectAll('.nudge-container').data([0]);
96499             var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
96500             containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
96501             var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
96502             var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
96503             nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
96504             nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
96505               return d[0] + ' nudge';
96506             }).on('click', function (d3_event, d) {
96507               nudge(d[1]);
96508             });
96509             nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
96510               d3_event.preventDefault();
96511               resetOffset();
96512             }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
96513             updateValue();
96514           }
96515
96516           context.background().on('change.backgroundOffset-update', updateValue);
96517           return section;
96518         }
96519
96520         function uiSectionOverlayList(context) {
96521           var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
96522
96523           var _overlayList = select(null);
96524
96525           function setTooltips(selection) {
96526             selection.each(function (d, i, nodes) {
96527               var item = select(this).select('label');
96528               var span = item.select('span');
96529               var placement = i < nodes.length / 2 ? 'bottom' : 'top';
96530               var description = d.description();
96531               var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
96532               item.call(uiTooltip().destroyAny);
96533
96534               if (description || isOverflowing) {
96535                 item.call(uiTooltip().placement(placement).title(description || d.name()));
96536               }
96537             });
96538           }
96539
96540           function updateLayerSelections(selection) {
96541             function active(d) {
96542               return context.background().showsLayer(d);
96543             }
96544
96545             selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
96546           }
96547
96548           function chooseOverlay(d3_event, d) {
96549             d3_event.preventDefault();
96550             context.background().toggleOverlayLayer(d);
96551
96552             _overlayList.call(updateLayerSelections);
96553
96554             document.activeElement.blur();
96555           }
96556
96557           function drawListItems(layerList, type, change, filter) {
96558             var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
96559             var layerLinks = layerList.selectAll('li').data(sources, function (d) {
96560               return d.name();
96561             });
96562             layerLinks.exit().remove();
96563             var enter = layerLinks.enter().append('li');
96564             var label = enter.append('label');
96565             label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
96566             label.append('span').html(function (d) {
96567               return d.label();
96568             });
96569             layerList.selectAll('li').sort(sortSources);
96570             layerList.call(updateLayerSelections);
96571
96572             function sortSources(a, b) {
96573               return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
96574             }
96575           }
96576
96577           function renderDisclosureContent(selection) {
96578             var container = selection.selectAll('.layer-overlay-list').data([0]);
96579             _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
96580
96581             _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
96582               return !d.isHidden() && d.overlay;
96583             });
96584           }
96585
96586           context.map().on('move.overlay_list', debounce(function () {
96587             // layers in-view may have changed due to map move
96588             window.requestIdleCallback(section.reRender);
96589           }, 1000));
96590           return section;
96591         }
96592
96593         function uiPaneBackground(context) {
96594           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)]);
96595           return backgroundPane;
96596         }
96597
96598         function uiPaneHelp(context) {
96599           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']]];
96600           var headings = {
96601             'help.help.open_data_h': 3,
96602             'help.help.before_start_h': 3,
96603             'help.help.open_source_h': 3,
96604             'help.overview.navigation_h': 3,
96605             'help.overview.features_h': 3,
96606             'help.editing.select_h': 3,
96607             'help.editing.multiselect_h': 3,
96608             'help.editing.undo_redo_h': 3,
96609             'help.editing.save_h': 3,
96610             'help.editing.upload_h': 3,
96611             'help.editing.backups_h': 3,
96612             'help.editing.keyboard_h': 3,
96613             'help.feature_editor.type_h': 3,
96614             'help.feature_editor.fields_h': 3,
96615             'help.feature_editor.tags_h': 3,
96616             'help.points.add_point_h': 3,
96617             'help.points.move_point_h': 3,
96618             'help.points.delete_point_h': 3,
96619             'help.lines.add_line_h': 3,
96620             'help.lines.modify_line_h': 3,
96621             'help.lines.connect_line_h': 3,
96622             'help.lines.disconnect_line_h': 3,
96623             'help.lines.move_line_h': 3,
96624             'help.lines.delete_line_h': 3,
96625             'help.areas.point_or_area_h': 3,
96626             'help.areas.add_area_h': 3,
96627             'help.areas.square_area_h': 3,
96628             'help.areas.modify_area_h': 3,
96629             'help.areas.delete_area_h': 3,
96630             'help.relations.edit_relation_h': 3,
96631             'help.relations.maintain_relation_h': 3,
96632             'help.relations.relation_types_h': 2,
96633             'help.relations.multipolygon_h': 3,
96634             'help.relations.turn_restriction_h': 3,
96635             'help.relations.route_h': 3,
96636             'help.relations.boundary_h': 3,
96637             'help.notes.add_note_h': 3,
96638             'help.notes.update_note_h': 3,
96639             'help.notes.save_note_h': 3,
96640             'help.imagery.sources_h': 3,
96641             'help.imagery.offsets_h': 3,
96642             'help.streetlevel.using_h': 3,
96643             'help.gps.using_h': 3,
96644             'help.qa.tools_h': 3,
96645             'help.qa.issues_h': 3
96646           }; // For each section, squash all the texts into a single markdown document
96647
96648           var docs = docKeys.map(function (key) {
96649             var helpkey = 'help.' + key[0];
96650             var helpPaneReplacements = {
96651               version: context.version
96652             };
96653             var text = key[1].reduce(function (all, part) {
96654               var subkey = helpkey + '.' + part;
96655               var depth = headings[subkey]; // is this subkey a heading?
96656
96657               var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
96658
96659               return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
96660             }, '');
96661             return {
96662               title: _t.html(helpkey + '.title'),
96663               content: marked_1(text.trim()) // use keyboard key styling for shortcuts
96664               .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
96665             };
96666           });
96667           var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
96668
96669           helpPane.renderContent = function (content) {
96670             function clickHelp(d, i) {
96671               var rtl = _mainLocalizer.textDirection() === 'rtl';
96672               content.property('scrollTop', 0);
96673               helpPane.selection().select('.pane-heading h2').html(d.title);
96674               body.html(d.content);
96675               body.selectAll('a').attr('target', '_blank');
96676               menuItems.classed('selected', function (m) {
96677                 return m.title === d.title;
96678               });
96679               nav.html('');
96680
96681               if (rtl) {
96682                 nav.call(drawNext).call(drawPrevious);
96683               } else {
96684                 nav.call(drawPrevious).call(drawNext);
96685               }
96686
96687               function drawNext(selection) {
96688                 if (i < docs.length - 1) {
96689                   var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
96690                     d3_event.preventDefault();
96691                     clickHelp(docs[i + 1], i + 1);
96692                   });
96693                   nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
96694                 }
96695               }
96696
96697               function drawPrevious(selection) {
96698                 if (i > 0) {
96699                   var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
96700                     d3_event.preventDefault();
96701                     clickHelp(docs[i - 1], i - 1);
96702                   });
96703                   prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
96704                 }
96705               }
96706             }
96707
96708             function clickWalkthrough(d3_event) {
96709               d3_event.preventDefault();
96710               if (context.inIntro()) return;
96711               context.container().call(uiIntro(context));
96712               context.ui().togglePanes();
96713             }
96714
96715             function clickShortcuts(d3_event) {
96716               d3_event.preventDefault();
96717               context.container().call(context.ui().shortcuts, true);
96718             }
96719
96720             var toc = content.append('ul').attr('class', 'toc');
96721             var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
96722               return d.title;
96723             }).on('click', function (d3_event, d) {
96724               d3_event.preventDefault();
96725               clickHelp(d, docs.indexOf(d));
96726             });
96727             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);
96728             shortcuts.append('div').html(_t.html('shortcuts.title'));
96729             var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
96730             walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
96731             walkthrough.append('div').html(_t.html('splash.walkthrough'));
96732             var helpContent = content.append('div').attr('class', 'left-content');
96733             var body = helpContent.append('div').attr('class', 'body');
96734             var nav = helpContent.append('div').attr('class', 'nav');
96735             clickHelp(docs[0], 0);
96736           };
96737
96738           return helpPane;
96739         }
96740
96741         function uiSectionValidationIssues(id, severity, context) {
96742           var _issues = [];
96743           var section = uiSection(id, context).label(function () {
96744             if (!_issues) return '';
96745             var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
96746             return _t('inspector.title_count', {
96747               title: _t.html('issues.' + severity + 's.list_title'),
96748               count: issueCountText
96749             });
96750           }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
96751             return _issues && _issues.length;
96752           });
96753
96754           function getOptions() {
96755             return {
96756               what: corePreferences('validate-what') || 'edited',
96757               where: corePreferences('validate-where') || 'all'
96758             };
96759           } // get and cache the issues to display, unordered
96760
96761
96762           function reloadIssues() {
96763             _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
96764           }
96765
96766           function renderDisclosureContent(selection) {
96767             var center = context.map().center();
96768             var graph = context.graph(); // sort issues by distance away from the center of the map
96769
96770             var issues = _issues.map(function withDistance(issue) {
96771               var extent = issue.extent(graph);
96772               var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
96773               return Object.assign(issue, {
96774                 dist: dist
96775               });
96776             }).sort(function byDistance(a, b) {
96777               return a.dist - b.dist;
96778             }); // cut off at 1000
96779
96780
96781             issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
96782
96783             selection.call(drawIssuesList, issues);
96784           }
96785
96786           function drawIssuesList(selection, issues) {
96787             var list = selection.selectAll('.issues-list').data([0]);
96788             list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
96789             var items = list.selectAll('li').data(issues, function (d) {
96790               return d.id;
96791             }); // Exit
96792
96793             items.exit().remove(); // Enter
96794
96795             var itemsEnter = items.enter().append('li').attr('class', function (d) {
96796               return 'issue severity-' + d.severity;
96797             });
96798             var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
96799               context.validator().focusIssue(d);
96800             }).on('mouseover', function (d3_event, d) {
96801               utilHighlightEntities(d.entityIds, true, context);
96802             }).on('mouseout', function (d3_event, d) {
96803               utilHighlightEntities(d.entityIds, false, context);
96804             });
96805             var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
96806             textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
96807               var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
96808               select(this).call(svgIcon(iconName));
96809             });
96810             textEnter.append('span').attr('class', 'issue-message');
96811             /*
96812             labelsEnter
96813                 .append('span')
96814                 .attr('class', 'issue-autofix')
96815                 .each(function(d) {
96816                     if (!d.autoFix) return;
96817                      d3_select(this)
96818                         .append('button')
96819                         .attr('title', t('issues.fix_one.title'))
96820                         .datum(d.autoFix)  // set button datum to the autofix
96821                         .attr('class', 'autofix action')
96822                         .on('click', function(d3_event, d) {
96823                             d3_event.preventDefault();
96824                             d3_event.stopPropagation();
96825                              var issuesEntityIDs = d.issue.entityIds;
96826                             utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
96827                              context.perform.apply(context, d.autoArgs);
96828                             context.validator().validate();
96829                         })
96830                         .call(svgIcon('#iD-icon-wrench'));
96831                 });
96832             */
96833             // Update
96834
96835             items = items.merge(itemsEnter).order();
96836             items.selectAll('.issue-message').html(function (d) {
96837               return d.message(context);
96838             });
96839             /*
96840             // autofix
96841             var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
96842              var autoFixAll = selection.selectAll('.autofix-all')
96843                 .data(canAutoFix.length ? [0] : []);
96844              // exit
96845             autoFixAll.exit()
96846                 .remove();
96847              // enter
96848             var autoFixAllEnter = autoFixAll.enter()
96849                 .insert('div', '.issues-list')
96850                 .attr('class', 'autofix-all');
96851              var linkEnter = autoFixAllEnter
96852                 .append('a')
96853                 .attr('class', 'autofix-all-link')
96854                 .attr('href', '#');
96855              linkEnter
96856                 .append('span')
96857                 .attr('class', 'autofix-all-link-text')
96858                 .html(t.html('issues.fix_all.title'));
96859              linkEnter
96860                 .append('span')
96861                 .attr('class', 'autofix-all-link-icon')
96862                 .call(svgIcon('#iD-icon-wrench'));
96863              if (severity === 'warning') {
96864                 renderIgnoredIssuesReset(selection);
96865             }
96866              // update
96867             autoFixAll = autoFixAll
96868                 .merge(autoFixAllEnter);
96869              autoFixAll.selectAll('.autofix-all-link')
96870                 .on('click', function() {
96871                     context.pauseChangeDispatch();
96872                     context.perform(actionNoop());
96873                     canAutoFix.forEach(function(issue) {
96874                         var args = issue.autoFix.autoArgs.slice();  // copy
96875                         if (typeof args[args.length - 1] !== 'function') {
96876                             args.pop();
96877                         }
96878                         args.push(t('issues.fix_all.annotation'));
96879                         context.replace.apply(context, args);
96880                     });
96881                     context.resumeChangeDispatch();
96882                     context.validator().validate();
96883                 });
96884             */
96885           }
96886
96887           context.validator().on('validated.uiSectionValidationIssues' + id, function () {
96888             window.requestIdleCallback(function () {
96889               reloadIssues();
96890               section.reRender();
96891             });
96892           });
96893           context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
96894             window.requestIdleCallback(function () {
96895               if (getOptions().where === 'visible') {
96896                 // must refetch issues if they are viewport-dependent
96897                 reloadIssues();
96898               } // always reload list to re-sort-by-distance
96899
96900
96901               section.reRender();
96902             });
96903           }, 1000));
96904           return section;
96905         }
96906
96907         function uiSectionValidationOptions(context) {
96908           var section = uiSection('issues-options', context).content(renderContent);
96909
96910           function renderContent(selection) {
96911             var container = selection.selectAll('.issues-options-container').data([0]);
96912             container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
96913             var data = [{
96914               key: 'what',
96915               values: ['edited', 'all']
96916             }, {
96917               key: 'where',
96918               values: ['visible', 'all']
96919             }];
96920             var options = container.selectAll('.issues-option').data(data, function (d) {
96921               return d.key;
96922             });
96923             var optionsEnter = options.enter().append('div').attr('class', function (d) {
96924               return 'issues-option issues-option-' + d.key;
96925             });
96926             optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
96927               return _t.html('issues.options.' + d.key + '.title');
96928             });
96929             var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
96930               return d.values.map(function (val) {
96931                 return {
96932                   value: val,
96933                   key: d.key
96934                 };
96935               });
96936             }).enter().append('label');
96937             valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
96938               return 'issues-option-' + d.key;
96939             }).attr('value', function (d) {
96940               return d.value;
96941             }).property('checked', function (d) {
96942               return getOptions()[d.key] === d.value;
96943             }).on('change', function (d3_event, d) {
96944               updateOptionValue(d3_event, d.key, d.value);
96945             });
96946             valuesEnter.append('span').html(function (d) {
96947               return _t.html('issues.options.' + d.key + '.' + d.value);
96948             });
96949           }
96950
96951           function getOptions() {
96952             return {
96953               what: corePreferences('validate-what') || 'edited',
96954               // 'all', 'edited'
96955               where: corePreferences('validate-where') || 'all' // 'all', 'visible'
96956
96957             };
96958           }
96959
96960           function updateOptionValue(d3_event, d, val) {
96961             if (!val && d3_event && d3_event.target) {
96962               val = d3_event.target.value;
96963             }
96964
96965             corePreferences('validate-' + d, val);
96966             context.validator().validate();
96967           }
96968
96969           return section;
96970         }
96971
96972         function uiSectionValidationRules(context) {
96973           var MINSQUARE = 0;
96974           var MAXSQUARE = 20;
96975           var DEFAULTSQUARE = 5; // see also unsquare_way.js
96976
96977           var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
96978
96979           var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
96980             return key !== 'maprules';
96981           }).sort(function (key1, key2) {
96982             // alphabetize by localized title
96983             return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
96984           });
96985
96986           function renderDisclosureContent(selection) {
96987             var container = selection.selectAll('.issues-rulelist-container').data([0]);
96988             var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
96989             containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
96990             var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
96991             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
96992               d3_event.preventDefault();
96993               context.validator().disableRules(_ruleKeys);
96994             });
96995             ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
96996               d3_event.preventDefault();
96997               context.validator().disableRules([]);
96998             }); // Update
96999
97000             container = container.merge(containerEnter);
97001             container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
97002           }
97003
97004           function drawListItems(selection, data, type, name, change, active) {
97005             var items = selection.selectAll('li').data(data); // Exit
97006
97007             items.exit().remove(); // Enter
97008
97009             var enter = items.enter().append('li');
97010
97011             if (name === 'rule') {
97012               enter.call(uiTooltip().title(function (d) {
97013                 return _t.html('issues.' + d + '.tip');
97014               }).placement('top'));
97015             }
97016
97017             var label = enter.append('label');
97018             label.append('input').attr('type', type).attr('name', name).on('change', change);
97019             label.append('span').html(function (d) {
97020               var params = {};
97021
97022               if (d === 'unsquare_way') {
97023                 params.val = '<span class="square-degrees"></span>';
97024               }
97025
97026               return _t.html('issues.' + d + '.title', params);
97027             }); // Update
97028
97029             items = items.merge(enter);
97030             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
97031
97032             var degStr = corePreferences('validate-square-degrees');
97033
97034             if (degStr === null) {
97035               degStr = DEFAULTSQUARE.toString();
97036             }
97037
97038             var span = items.selectAll('.square-degrees');
97039             var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
97040
97041             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) {
97042               d3_event.preventDefault();
97043               d3_event.stopPropagation();
97044               this.select();
97045             }).on('keyup', function (d3_event) {
97046               if (d3_event.keyCode === 13) {
97047                 // ↩ Return
97048                 this.blur();
97049                 this.select();
97050               }
97051             }).on('blur', changeSquare).merge(input).property('value', degStr);
97052           }
97053
97054           function changeSquare() {
97055             var input = select(this);
97056             var degStr = utilGetSetValue(input).trim();
97057             var degNum = parseFloat(degStr, 10);
97058
97059             if (!isFinite(degNum)) {
97060               degNum = DEFAULTSQUARE;
97061             } else if (degNum > MAXSQUARE) {
97062               degNum = MAXSQUARE;
97063             } else if (degNum < MINSQUARE) {
97064               degNum = MINSQUARE;
97065             }
97066
97067             degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
97068
97069             degStr = degNum.toString();
97070             input.property('value', degStr);
97071             corePreferences('validate-square-degrees', degStr);
97072             context.validator().reloadUnsquareIssues();
97073           }
97074
97075           function isRuleEnabled(d) {
97076             return context.validator().isRuleEnabled(d);
97077           }
97078
97079           function toggleRule(d3_event, d) {
97080             context.validator().toggleRule(d);
97081           }
97082
97083           context.validator().on('validated.uiSectionValidationRules', function () {
97084             window.requestIdleCallback(section.reRender);
97085           });
97086           return section;
97087         }
97088
97089         function uiSectionValidationStatus(context) {
97090           var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
97091             var issues = context.validator().getIssues(getOptions());
97092             return issues.length === 0;
97093           });
97094
97095           function getOptions() {
97096             return {
97097               what: corePreferences('validate-what') || 'edited',
97098               where: corePreferences('validate-where') || 'all'
97099             };
97100           }
97101
97102           function renderContent(selection) {
97103             var box = selection.selectAll('.box').data([0]);
97104             var boxEnter = box.enter().append('div').attr('class', 'box');
97105             boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
97106             var noIssuesMessage = boxEnter.append('span');
97107             noIssuesMessage.append('strong').attr('class', 'message');
97108             noIssuesMessage.append('br');
97109             noIssuesMessage.append('span').attr('class', 'details');
97110             renderIgnoredIssuesReset(selection);
97111             setNoIssuesText(selection);
97112           }
97113
97114           function renderIgnoredIssuesReset(selection) {
97115             var ignoredIssues = context.validator().getIssues({
97116               what: 'all',
97117               where: 'all',
97118               includeDisabledRules: true,
97119               includeIgnored: 'only'
97120             });
97121             var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
97122
97123             resetIgnored.exit().remove(); // enter
97124
97125             var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
97126             resetIgnoredEnter.append('a').attr('href', '#'); // update
97127
97128             resetIgnored = resetIgnored.merge(resetIgnoredEnter);
97129             resetIgnored.select('a').html(_t('inspector.title_count', {
97130               title: _t.html('issues.reset_ignored'),
97131               count: ignoredIssues.length
97132             }));
97133             resetIgnored.on('click', function (d3_event) {
97134               d3_event.preventDefault();
97135               context.validator().resetIgnoredIssues();
97136             });
97137           }
97138
97139           function setNoIssuesText(selection) {
97140             var opts = getOptions();
97141
97142             function checkForHiddenIssues(cases) {
97143               for (var type in cases) {
97144                 var hiddenOpts = cases[type];
97145                 var hiddenIssues = context.validator().getIssues(hiddenOpts);
97146
97147                 if (hiddenIssues.length) {
97148                   selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
97149                     count: hiddenIssues.length.toString()
97150                   }));
97151                   return;
97152                 }
97153               }
97154
97155               selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
97156             }
97157
97158             var messageType;
97159
97160             if (opts.what === 'edited' && opts.where === 'visible') {
97161               messageType = 'edits_in_view';
97162               checkForHiddenIssues({
97163                 elsewhere: {
97164                   what: 'edited',
97165                   where: 'all'
97166                 },
97167                 everything_else: {
97168                   what: 'all',
97169                   where: 'visible'
97170                 },
97171                 disabled_rules: {
97172                   what: 'edited',
97173                   where: 'visible',
97174                   includeDisabledRules: 'only'
97175                 },
97176                 everything_else_elsewhere: {
97177                   what: 'all',
97178                   where: 'all'
97179                 },
97180                 disabled_rules_elsewhere: {
97181                   what: 'edited',
97182                   where: 'all',
97183                   includeDisabledRules: 'only'
97184                 },
97185                 ignored_issues: {
97186                   what: 'edited',
97187                   where: 'visible',
97188                   includeIgnored: 'only'
97189                 },
97190                 ignored_issues_elsewhere: {
97191                   what: 'edited',
97192                   where: 'all',
97193                   includeIgnored: 'only'
97194                 }
97195               });
97196             } else if (opts.what === 'edited' && opts.where === 'all') {
97197               messageType = 'edits';
97198               checkForHiddenIssues({
97199                 everything_else: {
97200                   what: 'all',
97201                   where: 'all'
97202                 },
97203                 disabled_rules: {
97204                   what: 'edited',
97205                   where: 'all',
97206                   includeDisabledRules: 'only'
97207                 },
97208                 ignored_issues: {
97209                   what: 'edited',
97210                   where: 'all',
97211                   includeIgnored: 'only'
97212                 }
97213               });
97214             } else if (opts.what === 'all' && opts.where === 'visible') {
97215               messageType = 'everything_in_view';
97216               checkForHiddenIssues({
97217                 elsewhere: {
97218                   what: 'all',
97219                   where: 'all'
97220                 },
97221                 disabled_rules: {
97222                   what: 'all',
97223                   where: 'visible',
97224                   includeDisabledRules: 'only'
97225                 },
97226                 disabled_rules_elsewhere: {
97227                   what: 'all',
97228                   where: 'all',
97229                   includeDisabledRules: 'only'
97230                 },
97231                 ignored_issues: {
97232                   what: 'all',
97233                   where: 'visible',
97234                   includeIgnored: 'only'
97235                 },
97236                 ignored_issues_elsewhere: {
97237                   what: 'all',
97238                   where: 'all',
97239                   includeIgnored: 'only'
97240                 }
97241               });
97242             } else if (opts.what === 'all' && opts.where === 'all') {
97243               messageType = 'everything';
97244               checkForHiddenIssues({
97245                 disabled_rules: {
97246                   what: 'all',
97247                   where: 'all',
97248                   includeDisabledRules: 'only'
97249                 },
97250                 ignored_issues: {
97251                   what: 'all',
97252                   where: 'all',
97253                   includeIgnored: 'only'
97254                 }
97255               });
97256             }
97257
97258             if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
97259               messageType = 'no_edits';
97260             }
97261
97262             selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
97263           }
97264
97265           context.validator().on('validated.uiSectionValidationStatus', function () {
97266             window.requestIdleCallback(section.reRender);
97267           });
97268           context.map().on('move.uiSectionValidationStatus', debounce(function () {
97269             window.requestIdleCallback(section.reRender);
97270           }, 1000));
97271           return section;
97272         }
97273
97274         function uiPaneIssues(context) {
97275           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)]);
97276           return issuesPane;
97277         }
97278
97279         function uiSettingsCustomData(context) {
97280           var dispatch$1 = dispatch('change');
97281
97282           function render(selection) {
97283             var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
97284
97285             var _origSettings = {
97286               fileList: dataLayer && dataLayer.fileList() || null,
97287               url: corePreferences('settings-custom-data-url')
97288             };
97289             var _currSettings = {
97290               fileList: dataLayer && dataLayer.fileList() || null,
97291               url: corePreferences('settings-custom-data-url')
97292             }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
97293
97294             var modal = uiConfirm(selection).okButton();
97295             modal.classed('settings-modal settings-custom-data', true);
97296             modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
97297             var textSection = modal.select('.modal-section.message-text');
97298             textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
97299             textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
97300             .on('change', function (d3_event) {
97301               var files = d3_event.target.files;
97302
97303               if (files && files.length) {
97304                 _currSettings.url = '';
97305                 textSection.select('.field-url').property('value', '');
97306                 _currSettings.fileList = files;
97307               } else {
97308                 _currSettings.fileList = null;
97309               }
97310             });
97311             textSection.append('h4').html(_t.html('settings.custom_data.or'));
97312             textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
97313             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
97314
97315             var buttonSection = modal.select('.modal-section.buttons');
97316             buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
97317             buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
97318             buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
97319
97320             function isSaveDisabled() {
97321               return null;
97322             } // restore the original url
97323
97324
97325             function clickCancel() {
97326               textSection.select('.field-url').property('value', _origSettings.url);
97327               corePreferences('settings-custom-data-url', _origSettings.url);
97328               this.blur();
97329               modal.close();
97330             } // accept the current url
97331
97332
97333             function clickSave() {
97334               _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
97335
97336               if (_currSettings.url) {
97337                 _currSettings.fileList = null;
97338               }
97339
97340               if (_currSettings.fileList) {
97341                 _currSettings.url = '';
97342               }
97343
97344               corePreferences('settings-custom-data-url', _currSettings.url);
97345               this.blur();
97346               modal.close();
97347               dispatch$1.call('change', this, _currSettings);
97348             }
97349           }
97350
97351           return utilRebind(render, dispatch$1, 'on');
97352         }
97353
97354         function uiSectionDataLayers(context) {
97355           var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
97356           var layers = context.layers();
97357           var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
97358
97359           function renderDisclosureContent(selection) {
97360             var container = selection.selectAll('.data-layer-container').data([0]);
97361             container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
97362             .call(drawPanelItems);
97363           }
97364
97365           function showsLayer(which) {
97366             var layer = layers.layer(which);
97367
97368             if (layer) {
97369               return layer.enabled();
97370             }
97371
97372             return false;
97373           }
97374
97375           function setLayer(which, enabled) {
97376             // Don't allow layer changes while drawing - #6584
97377             var mode = context.mode();
97378             if (mode && /^draw/.test(mode.id)) return;
97379             var layer = layers.layer(which);
97380
97381             if (layer) {
97382               layer.enabled(enabled);
97383
97384               if (!enabled && (which === 'osm' || which === 'notes')) {
97385                 context.enter(modeBrowse(context));
97386               }
97387             }
97388           }
97389
97390           function toggleLayer(which) {
97391             setLayer(which, !showsLayer(which));
97392           }
97393
97394           function drawOsmItems(selection) {
97395             var osmKeys = ['osm', 'notes'];
97396             var osmLayers = layers.all().filter(function (obj) {
97397               return osmKeys.indexOf(obj.id) !== -1;
97398             });
97399             var ul = selection.selectAll('.layer-list-osm').data([0]);
97400             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
97401             var li = ul.selectAll('.list-item').data(osmLayers);
97402             li.exit().remove();
97403             var liEnter = li.enter().append('li').attr('class', function (d) {
97404               return 'list-item list-item-' + d.id;
97405             });
97406             var labelEnter = liEnter.append('label').each(function (d) {
97407               if (d.id === 'osm') {
97408                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
97409               } else {
97410                 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
97411               }
97412             });
97413             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97414               toggleLayer(d.id);
97415             });
97416             labelEnter.append('span').html(function (d) {
97417               return _t.html('map_data.layers.' + d.id + '.title');
97418             }); // Update
97419
97420             li.merge(liEnter).classed('active', function (d) {
97421               return d.layer.enabled();
97422             }).selectAll('input').property('checked', function (d) {
97423               return d.layer.enabled();
97424             });
97425           }
97426
97427           function drawQAItems(selection) {
97428             var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
97429             var qaLayers = layers.all().filter(function (obj) {
97430               return qaKeys.indexOf(obj.id) !== -1;
97431             });
97432             var ul = selection.selectAll('.layer-list-qa').data([0]);
97433             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
97434             var li = ul.selectAll('.list-item').data(qaLayers);
97435             li.exit().remove();
97436             var liEnter = li.enter().append('li').attr('class', function (d) {
97437               return 'list-item list-item-' + d.id;
97438             });
97439             var labelEnter = liEnter.append('label').each(function (d) {
97440               select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
97441             });
97442             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97443               toggleLayer(d.id);
97444             });
97445             labelEnter.append('span').html(function (d) {
97446               return _t.html('map_data.layers.' + d.id + '.title');
97447             }); // Update
97448
97449             li.merge(liEnter).classed('active', function (d) {
97450               return d.layer.enabled();
97451             }).selectAll('input').property('checked', function (d) {
97452               return d.layer.enabled();
97453             });
97454           } // Beta feature - sample vector layers to support Detroit Mapping Challenge
97455           // https://github.com/osmus/detroit-mapping-challenge
97456
97457
97458           function drawVectorItems(selection) {
97459             var dataLayer = layers.layer('data');
97460             var vtData = [{
97461               name: 'Detroit Neighborhoods/Parks',
97462               src: 'neighborhoods-parks',
97463               tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
97464               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'
97465             }, {
97466               name: 'Detroit Composite POIs',
97467               src: 'composite-poi',
97468               tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
97469               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'
97470             }, {
97471               name: 'Detroit All-The-Places POIs',
97472               src: 'alltheplaces-poi',
97473               tooltip: 'Public domain business location data created by web scrapers.',
97474               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'
97475             }]; // Only show this if the map is around Detroit..
97476
97477             var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
97478             var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
97479             var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
97480             container.exit().remove();
97481             var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
97482             containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
97483             containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
97484             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');
97485             container = container.merge(containerEnter);
97486             var ul = container.selectAll('.layer-list-vectortile');
97487             var li = ul.selectAll('.list-item').data(vtData);
97488             li.exit().remove();
97489             var liEnter = li.enter().append('li').attr('class', function (d) {
97490               return 'list-item list-item-' + d.src;
97491             });
97492             var labelEnter = liEnter.append('label').each(function (d) {
97493               select(this).call(uiTooltip().title(d.tooltip).placement('top'));
97494             });
97495             labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
97496             labelEnter.append('span').html(function (d) {
97497               return d.name;
97498             }); // Update
97499
97500             li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
97501
97502             function isVTLayerSelected(d) {
97503               return dataLayer && dataLayer.template() === d.template;
97504             }
97505
97506             function selectVTLayer(d3_event, d) {
97507               corePreferences('settings-custom-data-url', d.template);
97508
97509               if (dataLayer) {
97510                 dataLayer.template(d.template, d.src);
97511                 dataLayer.enabled(true);
97512               }
97513             }
97514           }
97515
97516           function drawCustomDataItems(selection) {
97517             var dataLayer = layers.layer('data');
97518             var hasData = dataLayer && dataLayer.hasData();
97519             var showsData = hasData && dataLayer.enabled();
97520             var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
97521
97522             ul.exit().remove(); // Enter
97523
97524             var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
97525             var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
97526             var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
97527             labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
97528               toggleLayer('data');
97529             });
97530             labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
97531             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) {
97532               d3_event.preventDefault();
97533               editCustom();
97534             }).call(svgIcon('#iD-icon-more'));
97535             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) {
97536               if (select(this).classed('disabled')) return;
97537               d3_event.preventDefault();
97538               d3_event.stopPropagation();
97539               dataLayer.fitZoom();
97540             }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
97541
97542             ul = ul.merge(ulEnter);
97543             ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
97544             ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
97545           }
97546
97547           function editCustom() {
97548             context.container().call(settingsCustomData);
97549           }
97550
97551           function customChanged(d) {
97552             var dataLayer = layers.layer('data');
97553
97554             if (d && d.url) {
97555               dataLayer.url(d.url);
97556             } else if (d && d.fileList) {
97557               dataLayer.fileList(d.fileList);
97558             }
97559           }
97560
97561           function drawPanelItems(selection) {
97562             var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
97563             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'));
97564             historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97565               d3_event.preventDefault();
97566               context.ui().info.toggle('history');
97567             });
97568             historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
97569             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'));
97570             measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97571               d3_event.preventDefault();
97572               context.ui().info.toggle('measurement');
97573             });
97574             measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
97575           }
97576
97577           context.layers().on('change.uiSectionDataLayers', section.reRender);
97578           context.map().on('move.uiSectionDataLayers', debounce(function () {
97579             // Detroit layers may have moved in or out of view
97580             window.requestIdleCallback(section.reRender);
97581           }, 1000));
97582           return section;
97583         }
97584
97585         function uiSectionMapFeatures(context) {
97586           var _features = context.features().keys();
97587
97588           var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97589
97590           function renderDisclosureContent(selection) {
97591             var container = selection.selectAll('.layer-feature-list-container').data([0]);
97592             var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
97593             containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
97594             var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
97595             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
97596               d3_event.preventDefault();
97597               context.features().disableAll();
97598             });
97599             footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
97600               d3_event.preventDefault();
97601               context.features().enableAll();
97602             }); // Update
97603
97604             container = container.merge(containerEnter);
97605             container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
97606           }
97607
97608           function drawListItems(selection, data, type, name, change, active) {
97609             var items = selection.selectAll('li').data(data); // Exit
97610
97611             items.exit().remove(); // Enter
97612
97613             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
97614               var tip = _t.html(name + '.' + d + '.tooltip');
97615
97616               if (autoHiddenFeature(d)) {
97617                 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
97618                 tip += '<div>' + msg + '</div>';
97619               }
97620
97621               return tip;
97622             }).placement('top'));
97623             var label = enter.append('label');
97624             label.append('input').attr('type', type).attr('name', name).on('change', change);
97625             label.append('span').html(function (d) {
97626               return _t.html(name + '.' + d + '.description');
97627             }); // Update
97628
97629             items = items.merge(enter);
97630             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
97631           }
97632
97633           function autoHiddenFeature(d) {
97634             return context.features().autoHidden(d);
97635           }
97636
97637           function showsFeature(d) {
97638             return context.features().enabled(d);
97639           }
97640
97641           function clickFeature(d3_event, d) {
97642             context.features().toggle(d);
97643           }
97644
97645           function showsLayer(id) {
97646             var layer = context.layers().layer(id);
97647             return layer && layer.enabled();
97648           } // add listeners
97649
97650
97651           context.features().on('change.map_features', section.reRender);
97652           return section;
97653         }
97654
97655         function uiSectionMapStyleOptions(context) {
97656           var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97657
97658           function renderDisclosureContent(selection) {
97659             var container = selection.selectAll('.layer-fill-list').data([0]);
97660             container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
97661             var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
97662             container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
97663               return context.surface().classed('highlight-edited');
97664             });
97665           }
97666
97667           function drawListItems(selection, data, type, name, change, active) {
97668             var items = selection.selectAll('li').data(data); // Exit
97669
97670             items.exit().remove(); // Enter
97671
97672             var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
97673               return _t.html(name + '.' + d + '.tooltip');
97674             }).keys(function (d) {
97675               var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
97676               if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
97677               return key ? [key] : null;
97678             }).placement('top'));
97679             var label = enter.append('label');
97680             label.append('input').attr('type', type).attr('name', name).on('change', change);
97681             label.append('span').html(function (d) {
97682               return _t.html(name + '.' + d + '.description');
97683             }); // Update
97684
97685             items = items.merge(enter);
97686             items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
97687           }
97688
97689           function isActiveFill(d) {
97690             return context.map().activeAreaFill() === d;
97691           }
97692
97693           function toggleHighlightEdited(d3_event) {
97694             d3_event.preventDefault();
97695             context.map().toggleHighlightEdited();
97696           }
97697
97698           function setFill(d3_event, d) {
97699             context.map().activeAreaFill(d);
97700           }
97701
97702           context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
97703           return section;
97704         }
97705
97706         function uiSectionPhotoOverlays(context) {
97707           var layers = context.layers();
97708           var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
97709
97710           function renderDisclosureContent(selection) {
97711             var container = selection.selectAll('.photo-overlay-container').data([0]);
97712             container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
97713           }
97714
97715           function drawPhotoItems(selection) {
97716             var photoKeys = context.photos().overlayLayerIDs();
97717             var photoLayers = layers.all().filter(function (obj) {
97718               return photoKeys.indexOf(obj.id) !== -1;
97719             });
97720             var data = photoLayers.filter(function (obj) {
97721               return obj.layer.supported();
97722             });
97723
97724             function layerSupported(d) {
97725               return d.layer && d.layer.supported();
97726             }
97727
97728             function layerEnabled(d) {
97729               return layerSupported(d) && d.layer.enabled();
97730             }
97731
97732             var ul = selection.selectAll('.layer-list-photos').data([0]);
97733             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
97734             var li = ul.selectAll('.list-item-photos').data(data);
97735             li.exit().remove();
97736             var liEnter = li.enter().append('li').attr('class', function (d) {
97737               var classes = 'list-item-photos list-item-' + d.id;
97738
97739               if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
97740                 classes += ' indented';
97741               }
97742
97743               return classes;
97744             });
97745             var labelEnter = liEnter.append('label').each(function (d) {
97746               var titleID;
97747               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';
97748               select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
97749             });
97750             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97751               toggleLayer(d.id);
97752             });
97753             labelEnter.append('span').html(function (d) {
97754               var id = d.id;
97755               if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
97756               return _t.html(id.replace(/-/g, '_') + '.title');
97757             }); // Update
97758
97759             li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
97760           }
97761
97762           function drawPhotoTypeItems(selection) {
97763             var data = context.photos().allPhotoTypes();
97764
97765             function typeEnabled(d) {
97766               return context.photos().showsPhotoType(d);
97767             }
97768
97769             var ul = selection.selectAll('.layer-list-photo-types').data([0]);
97770             ul.exit().remove();
97771             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
97772             var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
97773             li.exit().remove();
97774             var liEnter = li.enter().append('li').attr('class', function (d) {
97775               return 'list-item-photo-types list-item-' + d;
97776             });
97777             var labelEnter = liEnter.append('label').each(function (d) {
97778               select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
97779             });
97780             labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
97781               context.photos().togglePhotoType(d);
97782             });
97783             labelEnter.append('span').html(function (d) {
97784               return _t.html('photo_overlays.photo_type.' + d + '.title');
97785             }); // Update
97786
97787             li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
97788           }
97789
97790           function drawDateFilter(selection) {
97791             var data = context.photos().dateFilters();
97792
97793             function filterEnabled(d) {
97794               return context.photos().dateFilterValue(d);
97795             }
97796
97797             var ul = selection.selectAll('.layer-list-date-filter').data([0]);
97798             ul.exit().remove();
97799             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
97800             var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
97801             li.exit().remove();
97802             var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
97803             var labelEnter = liEnter.append('label').each(function (d) {
97804               select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
97805             });
97806             labelEnter.append('span').html(function (d) {
97807               return _t.html('photo_overlays.date_filter.' + d + '.title');
97808             });
97809             labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
97810               utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97811             }).on('change', function (d3_event, d) {
97812               var value = utilGetSetValue(select(this)).trim();
97813               context.photos().setDateFilter(d, value, true); // reload the displayed dates
97814
97815               li.selectAll('input').each(function (d) {
97816                 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
97817               });
97818             });
97819             li = li.merge(liEnter).classed('active', filterEnabled);
97820           }
97821
97822           function drawUsernameFilter(selection) {
97823             function filterEnabled() {
97824               return context.photos().usernames();
97825             }
97826
97827             var ul = selection.selectAll('.layer-list-username-filter').data([0]);
97828             ul.exit().remove();
97829             ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
97830             var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
97831             li.exit().remove();
97832             var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
97833             var labelEnter = liEnter.append('label').each(function () {
97834               select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
97835             });
97836             labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
97837             labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
97838               var value = select(this).property('value');
97839               context.photos().setUsernameFilter(value, true);
97840               select(this).property('value', usernameValue);
97841             });
97842             li.merge(liEnter).classed('active', filterEnabled);
97843
97844             function usernameValue() {
97845               var usernames = context.photos().usernames();
97846               if (usernames) return usernames.join('; ');
97847               return usernames;
97848             }
97849           }
97850
97851           function toggleLayer(which) {
97852             setLayer(which, !showsLayer(which));
97853           }
97854
97855           function showsLayer(which) {
97856             var layer = layers.layer(which);
97857
97858             if (layer) {
97859               return layer.enabled();
97860             }
97861
97862             return false;
97863           }
97864
97865           function setLayer(which, enabled) {
97866             var layer = layers.layer(which);
97867
97868             if (layer) {
97869               layer.enabled(enabled);
97870             }
97871           }
97872
97873           context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
97874           context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
97875           return section;
97876         }
97877
97878         function uiPaneMapData(context) {
97879           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)]);
97880           return mapDataPane;
97881         }
97882
97883         function uiSectionPrivacy(context) {
97884           var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
97885
97886           var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
97887
97888           function renderDisclosureContent(selection) {
97889             // enter
97890             var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
97891             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'));
97892             thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
97893               d3_event.preventDefault();
97894               _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
97895               corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
97896               update();
97897             });
97898             thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
97899
97900             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'));
97901             update();
97902
97903             function update() {
97904               selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
97905             }
97906           }
97907
97908           return section;
97909         }
97910
97911         function uiPanePreferences(context) {
97912           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)]);
97913           return preferencesPane;
97914         }
97915
97916         function uiInit(context) {
97917           var _initCounter = 0;
97918           var _needWidth = {};
97919
97920           var _lastPointerType;
97921
97922           function render(container) {
97923             container.on('click.ui', function (d3_event) {
97924               // we're only concerned with the primary mouse button
97925               if (d3_event.button !== 0) return;
97926               if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
97927
97928               var isOkayTarget = d3_event.composedPath().some(function (node) {
97929                 // we only care about element nodes
97930                 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
97931                 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
97932                 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
97933                 node.nodeName === 'A');
97934               });
97935               if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
97936
97937               d3_event.preventDefault();
97938             });
97939             var detected = utilDetect(); // only WebKit supports gesture events
97940
97941             if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
97942             // but we only need to do this on desktop Safari anyway. – #7694
97943             !detected.isMobileWebKit) {
97944               // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
97945               // CSS property, but on desktop Safari we need to manually cancel the
97946               // default gesture events.
97947               container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
97948                 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
97949                 d3_event.preventDefault();
97950               });
97951             }
97952
97953             if ('PointerEvent' in window) {
97954               select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
97955                 var pointerType = d3_event.pointerType || 'mouse';
97956
97957                 if (_lastPointerType !== pointerType) {
97958                   _lastPointerType = pointerType;
97959                   container.attr('pointer', pointerType);
97960                 }
97961               }, true);
97962             } else {
97963               _lastPointerType = 'mouse';
97964               container.attr('pointer', 'mouse');
97965             }
97966
97967             container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
97968
97969             container.call(uiFullScreen(context));
97970             var map = context.map();
97971             map.redrawEnable(false); // don't draw until we've set zoom/lat/long
97972
97973             map.on('hitMinZoom.ui', function () {
97974               ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
97975             });
97976             container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
97977             container.append('div').attr('class', 'sidebar').call(ui.sidebar);
97978             var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
97979
97980             content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
97981             content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
97982             var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
97983             // pressing, even if it's not targeted. This conflicts with long-pressing
97984             // to show the edit menu. We add a selectable offscreen element as the first
97985             // child to trick Safari into not showing the selection UI.
97986
97987             overMap.append('div').attr('class', 'select-trap').text('t');
97988             overMap.call(uiMapInMap(context)).call(uiNotice(context));
97989             overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
97990
97991             var controls = overMap.append('div').attr('class', 'map-controls');
97992             controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
97993             controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
97994             controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context)); // Add panes
97995             // This should happen after map is initialized, as some require surface()
97996
97997             var panes = overMap.append('div').attr('class', 'map-panes');
97998             var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
97999             uiPanes.forEach(function (pane) {
98000               controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
98001               panes.call(pane.renderPane);
98002             });
98003             ui.info = uiInfo(context);
98004             overMap.call(ui.info);
98005             overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left,  'ar'=right
98006             .classed('hide', true).call(ui.photoviewer);
98007             overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
98008
98009             var about = content.append('div').attr('class', 'map-footer');
98010             about.append('div').attr('class', 'api-status').call(uiStatus(context));
98011             var footer = about.append('div').attr('class', 'map-footer-bar fillD');
98012             footer.append('div').attr('class', 'flash-wrap footer-hide');
98013             var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
98014             footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
98015             var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
98016             aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
98017             var apiConnections = context.apiConnections();
98018
98019             if (apiConnections && apiConnections.length > 1) {
98020               aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
98021             }
98022
98023             aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
98024             aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
98025             var issueLinks = aboutList.append('li');
98026             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'));
98027             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'));
98028             aboutList.append('li').attr('class', 'version').call(uiVersion(context));
98029
98030             if (!context.embed()) {
98031               aboutList.call(uiAccount(context));
98032             } // Setup map dimensions and move map to initial center/zoom.
98033             // This should happen after .main-content and toolbars exist.
98034
98035
98036             ui.onResize();
98037             map.redrawEnable(true);
98038             ui.hash = behaviorHash(context);
98039             ui.hash();
98040
98041             if (!ui.hash.hadHash) {
98042               map.centerZoom([0, 0], 2);
98043             } // Bind events
98044
98045
98046             window.onbeforeunload = function () {
98047               return context.save();
98048             };
98049
98050             window.onunload = function () {
98051               context.history().unlock();
98052             };
98053
98054             select(window).on('resize.editor', function () {
98055               ui.onResize();
98056             });
98057             var panPixels = 80;
98058             context.keybinding().on('⌫', function (d3_event) {
98059               d3_event.preventDefault();
98060             }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
98061             .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) {
98062               if (d3_event) {
98063                 d3_event.stopImmediatePropagation();
98064                 d3_event.preventDefault();
98065               }
98066
98067               var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
98068
98069               if (previousBackground) {
98070                 var currentBackground = context.background().baseLayerSource();
98071                 corePreferences('background-last-used-toggle', currentBackground.id);
98072                 corePreferences('background-last-used', previousBackground.id);
98073                 context.background().baseLayerSource(previousBackground);
98074               }
98075             }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
98076               d3_event.preventDefault();
98077               d3_event.stopPropagation();
98078               context.map().toggleWireframe();
98079             }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
98080               d3_event.preventDefault();
98081               d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
98082
98083               var mode = context.mode();
98084               if (mode && /^draw/.test(mode.id)) return;
98085               var layer = context.layers().layer('osm');
98086
98087               if (layer) {
98088                 layer.enabled(!layer.enabled());
98089
98090                 if (!layer.enabled()) {
98091                   context.enter(modeBrowse(context));
98092                 }
98093               }
98094             }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
98095               d3_event.preventDefault();
98096               context.map().toggleHighlightEdited();
98097             });
98098             context.on('enter.editor', function (entered) {
98099               container.classed('mode-' + entered.id, true);
98100             }).on('exit.editor', function (exited) {
98101               container.classed('mode-' + exited.id, false);
98102             });
98103             context.enter(modeBrowse(context));
98104
98105             if (!_initCounter++) {
98106               if (!ui.hash.startWalkthrough) {
98107                 context.container().call(uiSplash(context)).call(uiRestore(context));
98108               }
98109
98110               context.container().call(ui.shortcuts);
98111             }
98112
98113             var osm = context.connection();
98114             var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
98115
98116             if (osm && auth) {
98117               osm.on('authLoading.ui', function () {
98118                 context.container().call(auth);
98119               }).on('authDone.ui', function () {
98120                 auth.close();
98121               });
98122             }
98123
98124             _initCounter++;
98125
98126             if (ui.hash.startWalkthrough) {
98127               ui.hash.startWalkthrough = false;
98128               context.container().call(uiIntro(context));
98129             }
98130
98131             function pan(d) {
98132               return function (d3_event) {
98133                 if (d3_event.shiftKey) return;
98134                 if (context.container().select('.combobox').size()) return;
98135                 d3_event.preventDefault();
98136                 context.map().pan(d, 100);
98137               };
98138             }
98139           }
98140
98141           var ui = {};
98142
98143           var _loadPromise; // renders the iD interface into the container node
98144
98145
98146           ui.ensureLoaded = function () {
98147             if (_loadPromise) return _loadPromise;
98148             return _loadPromise = Promise.all([// must have strings and presets before loading the UI
98149             _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
98150               if (!context.container().empty()) render(context.container());
98151             })["catch"](function (err) {
98152               return console.error(err);
98153             }); // eslint-disable-line
98154           }; // `ui.restart()` will destroy and rebuild the entire iD interface,
98155           // for example to switch the locale while iD is running.
98156
98157
98158           ui.restart = function () {
98159             context.keybinding().clear();
98160             _loadPromise = null;
98161             context.container().selectAll('*').remove();
98162             ui.ensureLoaded();
98163           };
98164
98165           ui.lastPointerType = function () {
98166             return _lastPointerType;
98167           };
98168
98169           ui.svgDefs = svgDefs(context);
98170           ui.flash = uiFlash(context);
98171           ui.sidebar = uiSidebar(context);
98172           ui.photoviewer = uiPhotoviewer(context);
98173           ui.shortcuts = uiShortcuts(context);
98174
98175           ui.onResize = function (withPan) {
98176             var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
98177             // This will call `getBoundingClientRect` and trigger reflow,
98178             //  but the values will be cached for later use.
98179
98180             var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
98181             utilGetDimensions(context.container().select('.sidebar'), true);
98182
98183             if (withPan !== undefined) {
98184               map.redrawEnable(false);
98185               map.pan(withPan);
98186               map.redrawEnable(true);
98187             }
98188
98189             map.dimensions(mapDimensions);
98190             ui.photoviewer.onMapResize(); // check if header or footer have overflowed
98191
98192             ui.checkOverflow('.top-toolbar');
98193             ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
98194
98195             var resizeWindowEvent = document.createEvent('Event');
98196             resizeWindowEvent.initEvent('resizeWindow', true, true);
98197             document.dispatchEvent(resizeWindowEvent);
98198           }; // Call checkOverflow when resizing or whenever the contents change.
98199
98200
98201           ui.checkOverflow = function (selector, reset) {
98202             if (reset) {
98203               delete _needWidth[selector];
98204             }
98205
98206             var selection = context.container().select(selector);
98207             if (selection.empty()) return;
98208             var scrollWidth = selection.property('scrollWidth');
98209             var clientWidth = selection.property('clientWidth');
98210             var needed = _needWidth[selector] || scrollWidth;
98211
98212             if (scrollWidth > clientWidth) {
98213               // overflow happening
98214               selection.classed('narrow', true);
98215
98216               if (!_needWidth[selector]) {
98217                 _needWidth[selector] = scrollWidth;
98218               }
98219             } else if (scrollWidth >= needed) {
98220               selection.classed('narrow', false);
98221             }
98222           };
98223
98224           ui.togglePanes = function (showPane) {
98225             var hidePanes = context.container().selectAll('.map-pane.shown');
98226             var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
98227             hidePanes.classed('shown', false).classed('hide', true);
98228             context.container().selectAll('.map-pane-control button').classed('active', false);
98229
98230             if (showPane) {
98231               hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
98232               context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
98233               showPane.classed('shown', true).classed('hide', false);
98234
98235               if (hidePanes.empty()) {
98236                 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
98237               } else {
98238                 showPane.style(side, '0px');
98239               }
98240             } else {
98241               hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
98242                 select(this).classed('shown', false).classed('hide', true);
98243               });
98244             }
98245           };
98246
98247           var _editMenu = uiEditMenu(context);
98248
98249           ui.editMenu = function () {
98250             return _editMenu;
98251           };
98252
98253           ui.showEditMenu = function (anchorPoint, triggerType, operations) {
98254             // remove any displayed menu
98255             ui.closeEditMenu();
98256             if (!operations && context.mode().operations) operations = context.mode().operations();
98257             if (!operations || !operations.length) return; // disable menu if in wide selection, for example
98258
98259             if (!context.map().editableDataEnabled()) return;
98260             var surfaceNode = context.surface().node();
98261
98262             if (surfaceNode.focus) {
98263               // FF doesn't support it
98264               // focus the surface or else clicking off the menu may not trigger modeBrowse
98265               surfaceNode.focus();
98266             }
98267
98268             operations.forEach(function (operation) {
98269               if (operation.point) operation.point(anchorPoint);
98270             });
98271
98272             _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
98273
98274
98275             context.map().supersurface.call(_editMenu);
98276           };
98277
98278           ui.closeEditMenu = function () {
98279             // remove any existing menu no matter how it was added
98280             context.map().supersurface.select('.edit-menu').remove();
98281           };
98282
98283           var _saveLoading = select(null);
98284
98285           context.uploader().on('saveStarted.ui', function () {
98286             _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
98287             context.container().call(_saveLoading); // block input during upload
98288           }).on('saveEnded.ui', function () {
98289             _saveLoading.close();
98290
98291             _saveLoading = select(null);
98292           });
98293           return ui;
98294         }
98295
98296         function coreContext() {
98297           var _this = this;
98298
98299           var dispatch$1 = dispatch('enter', 'exit', 'change');
98300           var context = utilRebind({}, dispatch$1, 'on');
98301
98302           var _deferred = new Set();
98303
98304           context.version = '2.19.5';
98305           context.privacyVersion = '20200407'; // iD will alter the hash so cache the parameters intended to setup the session
98306
98307           context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
98308           context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
98309           /* Changeset */
98310           // An osmChangeset object. Not loaded until needed.
98311
98312           context.changeset = null;
98313           var _defaultChangesetComment = context.initialHashParams.comment;
98314           var _defaultChangesetSource = context.initialHashParams.source;
98315           var _defaultChangesetHashtags = context.initialHashParams.hashtags;
98316
98317           context.defaultChangesetComment = function (val) {
98318             if (!arguments.length) return _defaultChangesetComment;
98319             _defaultChangesetComment = val;
98320             return context;
98321           };
98322
98323           context.defaultChangesetSource = function (val) {
98324             if (!arguments.length) return _defaultChangesetSource;
98325             _defaultChangesetSource = val;
98326             return context;
98327           };
98328
98329           context.defaultChangesetHashtags = function (val) {
98330             if (!arguments.length) return _defaultChangesetHashtags;
98331             _defaultChangesetHashtags = val;
98332             return context;
98333           };
98334           /* Document title */
98335
98336           /* (typically shown as the label for the browser window/tab) */
98337           // If true, iD will update the title based on what the user is doing
98338
98339
98340           var _setsDocumentTitle = true;
98341
98342           context.setsDocumentTitle = function (val) {
98343             if (!arguments.length) return _setsDocumentTitle;
98344             _setsDocumentTitle = val;
98345             return context;
98346           }; // The part of the title that is always the same
98347
98348
98349           var _documentTitleBase = document.title;
98350
98351           context.documentTitleBase = function (val) {
98352             if (!arguments.length) return _documentTitleBase;
98353             _documentTitleBase = val;
98354             return context;
98355           };
98356           /* User interface and keybinding */
98357
98358
98359           var _ui;
98360
98361           context.ui = function () {
98362             return _ui;
98363           };
98364
98365           context.lastPointerType = function () {
98366             return _ui.lastPointerType();
98367           };
98368
98369           var _keybinding = utilKeybinding('context');
98370
98371           context.keybinding = function () {
98372             return _keybinding;
98373           };
98374
98375           select(document).call(_keybinding);
98376           /* Straight accessors. Avoid using these if you can. */
98377           // Instantiate the connection here because it doesn't require passing in
98378           // `context` and it's needed for pre-init calls like `preauth`
98379
98380           var _connection = services.osm;
98381
98382           var _history;
98383
98384           var _validator;
98385
98386           var _uploader;
98387
98388           context.connection = function () {
98389             return _connection;
98390           };
98391
98392           context.history = function () {
98393             return _history;
98394           };
98395
98396           context.validator = function () {
98397             return _validator;
98398           };
98399
98400           context.uploader = function () {
98401             return _uploader;
98402           };
98403           /* Connection */
98404
98405
98406           context.preauth = function (options) {
98407             if (_connection) {
98408               _connection["switch"](options);
98409             }
98410
98411             return context;
98412           };
98413           /* connection options for source switcher (optional) */
98414
98415
98416           var _apiConnections;
98417
98418           context.apiConnections = function (val) {
98419             if (!arguments.length) return _apiConnections;
98420             _apiConnections = val;
98421             return context;
98422           }; // A string or array or locale codes to prefer over the browser's settings
98423
98424
98425           context.locale = function (locale) {
98426             if (!arguments.length) return _mainLocalizer.localeCode();
98427             _mainLocalizer.preferredLocaleCodes(locale);
98428             return context;
98429           };
98430
98431           function afterLoad(cid, callback) {
98432             return function (err, result) {
98433               if (err) {
98434                 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
98435                 if (err.status === 400 || err.status === 401 || err.status === 403) {
98436                   if (_connection) {
98437                     _connection.logout();
98438                   }
98439                 }
98440
98441                 if (typeof callback === 'function') {
98442                   callback(err);
98443                 }
98444
98445                 return;
98446               } else if (_connection && _connection.getConnectionId() !== cid) {
98447                 if (typeof callback === 'function') {
98448                   callback({
98449                     message: 'Connection Switched',
98450                     status: -1
98451                   });
98452                 }
98453
98454                 return;
98455               } else {
98456                 _history.merge(result.data, result.extent);
98457
98458                 if (typeof callback === 'function') {
98459                   callback(err, result);
98460                 }
98461
98462                 return;
98463               }
98464             };
98465           }
98466
98467           context.loadTiles = function (projection, callback) {
98468             var handle = window.requestIdleCallback(function () {
98469               _deferred["delete"](handle);
98470
98471               if (_connection && context.editableDataEnabled()) {
98472                 var cid = _connection.getConnectionId();
98473
98474                 _connection.loadTiles(projection, afterLoad(cid, callback));
98475               }
98476             });
98477
98478             _deferred.add(handle);
98479           };
98480
98481           context.loadTileAtLoc = function (loc, callback) {
98482             var handle = window.requestIdleCallback(function () {
98483               _deferred["delete"](handle);
98484
98485               if (_connection && context.editableDataEnabled()) {
98486                 var cid = _connection.getConnectionId();
98487
98488                 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
98489               }
98490             });
98491
98492             _deferred.add(handle);
98493           };
98494
98495           context.loadEntity = function (entityID, callback) {
98496             if (_connection) {
98497               var cid = _connection.getConnectionId();
98498
98499               _connection.loadEntity(entityID, afterLoad(cid, callback));
98500             }
98501           };
98502
98503           context.zoomToEntity = function (entityID, zoomTo) {
98504             // be sure to load the entity even if we're not going to zoom to it
98505             context.loadEntity(entityID, function (err, result) {
98506               if (err) return;
98507
98508               if (zoomTo !== false) {
98509                 var entity = result.data.find(function (e) {
98510                   return e.id === entityID;
98511                 });
98512
98513                 if (entity) {
98514                   _map.zoomTo(entity);
98515                 }
98516               }
98517             });
98518
98519             _map.on('drawn.zoomToEntity', function () {
98520               if (!context.hasEntity(entityID)) return;
98521
98522               _map.on('drawn.zoomToEntity', null);
98523
98524               context.on('enter.zoomToEntity', null);
98525               context.enter(modeSelect(context, [entityID]));
98526             });
98527
98528             context.on('enter.zoomToEntity', function () {
98529               if (_mode.id !== 'browse') {
98530                 _map.on('drawn.zoomToEntity', null);
98531
98532                 context.on('enter.zoomToEntity', null);
98533               }
98534             });
98535           };
98536
98537           var _minEditableZoom = 16;
98538
98539           context.minEditableZoom = function (val) {
98540             if (!arguments.length) return _minEditableZoom;
98541             _minEditableZoom = val;
98542
98543             if (_connection) {
98544               _connection.tileZoom(val);
98545             }
98546
98547             return context;
98548           }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
98549
98550
98551           context.maxCharsForTagKey = function () {
98552             return 255;
98553           };
98554
98555           context.maxCharsForTagValue = function () {
98556             return 255;
98557           };
98558
98559           context.maxCharsForRelationRole = function () {
98560             return 255;
98561           };
98562
98563           function cleanOsmString(val, maxChars) {
98564             // be lenient with input
98565             if (val === undefined || val === null) {
98566               val = '';
98567             } else {
98568               val = val.toString();
98569             } // remove whitespace
98570
98571
98572             val = val.trim(); // use the canonical form of the string
98573
98574             if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
98575
98576             return utilUnicodeCharsTruncated(val, maxChars);
98577           }
98578
98579           context.cleanTagKey = function (val) {
98580             return cleanOsmString(val, context.maxCharsForTagKey());
98581           };
98582
98583           context.cleanTagValue = function (val) {
98584             return cleanOsmString(val, context.maxCharsForTagValue());
98585           };
98586
98587           context.cleanRelationRole = function (val) {
98588             return cleanOsmString(val, context.maxCharsForRelationRole());
98589           };
98590           /* History */
98591
98592
98593           var _inIntro = false;
98594
98595           context.inIntro = function (val) {
98596             if (!arguments.length) return _inIntro;
98597             _inIntro = val;
98598             return context;
98599           }; // Immediately save the user's history to localstorage, if possible
98600           // This is called someteimes, but also on the `window.onbeforeunload` handler
98601
98602
98603           context.save = function () {
98604             // no history save, no message onbeforeunload
98605             if (_inIntro || context.container().select('.modal').size()) return;
98606             var canSave;
98607
98608             if (_mode && _mode.id === 'save') {
98609               canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
98610
98611               if (services.osm && services.osm.isChangesetInflight()) {
98612                 _history.clearSaved();
98613
98614                 return;
98615               }
98616             } else {
98617               canSave = context.selectedIDs().every(function (id) {
98618                 var entity = context.hasEntity(id);
98619                 return entity && !entity.isDegenerate();
98620               });
98621             }
98622
98623             if (canSave) {
98624               _history.save();
98625             }
98626
98627             if (_history.hasChanges()) {
98628               return _t('save.unsaved_changes');
98629             }
98630           }; // Debounce save, since it's a synchronous localStorage write,
98631           // and history changes can happen frequently (e.g. when dragging).
98632
98633
98634           context.debouncedSave = debounce(context.save, 350);
98635
98636           function withDebouncedSave(fn) {
98637             return function () {
98638               var result = fn.apply(_history, arguments);
98639               context.debouncedSave();
98640               return result;
98641             };
98642           }
98643           /* Graph */
98644
98645
98646           context.hasEntity = function (id) {
98647             return _history.graph().hasEntity(id);
98648           };
98649
98650           context.entity = function (id) {
98651             return _history.graph().entity(id);
98652           };
98653           /* Modes */
98654
98655
98656           var _mode;
98657
98658           context.mode = function () {
98659             return _mode;
98660           };
98661
98662           context.enter = function (newMode) {
98663             if (_mode) {
98664               _mode.exit();
98665
98666               dispatch$1.call('exit', _this, _mode);
98667             }
98668
98669             _mode = newMode;
98670
98671             _mode.enter();
98672
98673             dispatch$1.call('enter', _this, _mode);
98674           };
98675
98676           context.selectedIDs = function () {
98677             return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
98678           };
98679
98680           context.activeID = function () {
98681             return _mode && _mode.activeID && _mode.activeID();
98682           };
98683
98684           var _selectedNoteID;
98685
98686           context.selectedNoteID = function (noteID) {
98687             if (!arguments.length) return _selectedNoteID;
98688             _selectedNoteID = noteID;
98689             return context;
98690           }; // NOTE: Don't change the name of this until UI v3 is merged
98691
98692
98693           var _selectedErrorID;
98694
98695           context.selectedErrorID = function (errorID) {
98696             if (!arguments.length) return _selectedErrorID;
98697             _selectedErrorID = errorID;
98698             return context;
98699           };
98700           /* Behaviors */
98701
98702
98703           context.install = function (behavior) {
98704             return context.surface().call(behavior);
98705           };
98706
98707           context.uninstall = function (behavior) {
98708             return context.surface().call(behavior.off);
98709           };
98710           /* Copy/Paste */
98711
98712
98713           var _copyGraph;
98714
98715           context.copyGraph = function () {
98716             return _copyGraph;
98717           };
98718
98719           var _copyIDs = [];
98720
98721           context.copyIDs = function (val) {
98722             if (!arguments.length) return _copyIDs;
98723             _copyIDs = val;
98724             _copyGraph = _history.graph();
98725             return context;
98726           };
98727
98728           var _copyLonLat;
98729
98730           context.copyLonLat = function (val) {
98731             if (!arguments.length) return _copyLonLat;
98732             _copyLonLat = val;
98733             return context;
98734           };
98735           /* Background */
98736
98737
98738           var _background;
98739
98740           context.background = function () {
98741             return _background;
98742           };
98743           /* Features */
98744
98745
98746           var _features;
98747
98748           context.features = function () {
98749             return _features;
98750           };
98751
98752           context.hasHiddenConnections = function (id) {
98753             var graph = _history.graph();
98754
98755             var entity = graph.entity(id);
98756             return _features.hasHiddenConnections(entity, graph);
98757           };
98758           /* Photos */
98759
98760
98761           var _photos;
98762
98763           context.photos = function () {
98764             return _photos;
98765           };
98766           /* Map */
98767
98768
98769           var _map;
98770
98771           context.map = function () {
98772             return _map;
98773           };
98774
98775           context.layers = function () {
98776             return _map.layers();
98777           };
98778
98779           context.surface = function () {
98780             return _map.surface;
98781           };
98782
98783           context.editableDataEnabled = function () {
98784             return _map.editableDataEnabled();
98785           };
98786
98787           context.surfaceRect = function () {
98788             return _map.surface.node().getBoundingClientRect();
98789           };
98790
98791           context.editable = function () {
98792             // don't allow editing during save
98793             var mode = context.mode();
98794             if (!mode || mode.id === 'save') return false;
98795             return _map.editableDataEnabled();
98796           };
98797           /* Debug */
98798
98799
98800           var _debugFlags = {
98801             tile: false,
98802             // tile boundaries
98803             collision: false,
98804             // label collision bounding boxes
98805             imagery: false,
98806             // imagery bounding polygons
98807             target: false,
98808             // touch targets
98809             downloaded: false // downloaded data from osm
98810
98811           };
98812
98813           context.debugFlags = function () {
98814             return _debugFlags;
98815           };
98816
98817           context.getDebug = function (flag) {
98818             return flag && _debugFlags[flag];
98819           };
98820
98821           context.setDebug = function (flag, val) {
98822             if (arguments.length === 1) val = true;
98823             _debugFlags[flag] = val;
98824             dispatch$1.call('change');
98825             return context;
98826           };
98827           /* Container */
98828
98829
98830           var _container = select(null);
98831
98832           context.container = function (val) {
98833             if (!arguments.length) return _container;
98834             _container = val;
98835
98836             _container.classed('ideditor', true);
98837
98838             return context;
98839           };
98840
98841           context.containerNode = function (val) {
98842             if (!arguments.length) return context.container().node();
98843             context.container(select(val));
98844             return context;
98845           };
98846
98847           var _embed;
98848
98849           context.embed = function (val) {
98850             if (!arguments.length) return _embed;
98851             _embed = val;
98852             return context;
98853           };
98854           /* Assets */
98855
98856
98857           var _assetPath = '';
98858
98859           context.assetPath = function (val) {
98860             if (!arguments.length) return _assetPath;
98861             _assetPath = val;
98862             _mainFileFetcher.assetPath(val);
98863             return context;
98864           };
98865
98866           var _assetMap = {};
98867
98868           context.assetMap = function (val) {
98869             if (!arguments.length) return _assetMap;
98870             _assetMap = val;
98871             _mainFileFetcher.assetMap(val);
98872             return context;
98873           };
98874
98875           context.asset = function (val) {
98876             if (/^http(s)?:\/\//i.test(val)) return val;
98877             var filename = _assetPath + val;
98878             return _assetMap[filename] || filename;
98879           };
98880
98881           context.imagePath = function (val) {
98882             return context.asset("img/".concat(val));
98883           };
98884           /* reset (aka flush) */
98885
98886
98887           context.reset = context.flush = function () {
98888             context.debouncedSave.cancel();
98889             Array.from(_deferred).forEach(function (handle) {
98890               window.cancelIdleCallback(handle);
98891
98892               _deferred["delete"](handle);
98893             });
98894             Object.values(services).forEach(function (service) {
98895               if (service && typeof service.reset === 'function') {
98896                 service.reset(context);
98897               }
98898             });
98899             context.changeset = null;
98900
98901             _validator.reset();
98902
98903             _features.reset();
98904
98905             _history.reset();
98906
98907             _uploader.reset(); // don't leave stale state in the inspector
98908
98909
98910             context.container().select('.inspector-wrap *').remove();
98911             return context;
98912           };
98913           /* Projections */
98914
98915
98916           context.projection = geoRawMercator();
98917           context.curtainProjection = geoRawMercator();
98918           /* Init */
98919
98920           context.init = function () {
98921             instantiateInternal();
98922             initializeDependents();
98923             return context; // Load variables and properties. No property of `context` should be accessed
98924             // until this is complete since load statuses are indeterminate. The order
98925             // of instantiation shouldn't matter.
98926
98927             function instantiateInternal() {
98928               _history = coreHistory(context);
98929               context.graph = _history.graph;
98930               context.pauseChangeDispatch = _history.pauseChangeDispatch;
98931               context.resumeChangeDispatch = _history.resumeChangeDispatch;
98932               context.perform = withDebouncedSave(_history.perform);
98933               context.replace = withDebouncedSave(_history.replace);
98934               context.pop = withDebouncedSave(_history.pop);
98935               context.overwrite = withDebouncedSave(_history.overwrite);
98936               context.undo = withDebouncedSave(_history.undo);
98937               context.redo = withDebouncedSave(_history.redo);
98938               _validator = coreValidator(context);
98939               _uploader = coreUploader(context);
98940               _background = rendererBackground(context);
98941               _features = rendererFeatures(context);
98942               _map = rendererMap(context);
98943               _photos = rendererPhotos(context);
98944               _ui = uiInit(context);
98945             } // Set up objects that might need to access properties of `context`. The order
98946             // might matter if dependents make calls to each other. Be wary of async calls.
98947
98948
98949             function initializeDependents() {
98950               if (context.initialHashParams.presets) {
98951                 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
98952               }
98953
98954               if (context.initialHashParams.locale) {
98955                 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
98956               } // kick off some async work
98957
98958
98959               _mainLocalizer.ensureLoaded();
98960
98961               _background.ensureLoaded();
98962
98963               _mainPresetIndex.ensureLoaded();
98964               Object.values(services).forEach(function (service) {
98965                 if (service && typeof service.init === 'function') {
98966                   service.init();
98967                 }
98968               });
98969
98970               _map.init();
98971
98972               _validator.init();
98973
98974               _features.init();
98975
98976               if (services.maprules && context.initialHashParams.maprules) {
98977                 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
98978                   services.maprules.init();
98979                   mapcss.forEach(function (mapcssSelector) {
98980                     return services.maprules.addRule(mapcssSelector);
98981                   });
98982                 })["catch"](function () {
98983                   /* ignore */
98984                 });
98985               } // if the container isn't available, e.g. when testing, don't load the UI
98986
98987
98988               if (!context.container().empty()) {
98989                 _ui.ensureLoaded().then(function () {
98990                   _photos.init();
98991                 });
98992               }
98993             }
98994           };
98995
98996           return context;
98997         }
98998
98999         // This is only done in testing because of the performance penalty.
99000
99001         var debug = false; // Reexport just what our tests use, see #4379
99002         var d3 = {
99003           dispatch: dispatch,
99004           geoMercator: mercator,
99005           geoProjection: projection,
99006           polygonArea: d3_polygonArea,
99007           polygonCentroid: d3_polygonCentroid,
99008           select: select,
99009           selectAll: selectAll,
99010           timerFlush: timerFlush
99011         };
99012
99013         var iD = /*#__PURE__*/Object.freeze({
99014                 __proto__: null,
99015                 debug: debug,
99016                 d3: d3,
99017                 actionAddEntity: actionAddEntity,
99018                 actionAddMember: actionAddMember,
99019                 actionAddMidpoint: actionAddMidpoint,
99020                 actionAddVertex: actionAddVertex,
99021                 actionChangeMember: actionChangeMember,
99022                 actionChangePreset: actionChangePreset,
99023                 actionChangeTags: actionChangeTags,
99024                 actionCircularize: actionCircularize,
99025                 actionConnect: actionConnect,
99026                 actionCopyEntities: actionCopyEntities,
99027                 actionDeleteMember: actionDeleteMember,
99028                 actionDeleteMultiple: actionDeleteMultiple,
99029                 actionDeleteNode: actionDeleteNode,
99030                 actionDeleteRelation: actionDeleteRelation,
99031                 actionDeleteWay: actionDeleteWay,
99032                 actionDiscardTags: actionDiscardTags,
99033                 actionDisconnect: actionDisconnect,
99034                 actionExtract: actionExtract,
99035                 actionJoin: actionJoin,
99036                 actionMerge: actionMerge,
99037                 actionMergeNodes: actionMergeNodes,
99038                 actionMergePolygon: actionMergePolygon,
99039                 actionMergeRemoteChanges: actionMergeRemoteChanges,
99040                 actionMove: actionMove,
99041                 actionMoveMember: actionMoveMember,
99042                 actionMoveNode: actionMoveNode,
99043                 actionNoop: actionNoop,
99044                 actionOrthogonalize: actionOrthogonalize,
99045                 actionRestrictTurn: actionRestrictTurn,
99046                 actionReverse: actionReverse,
99047                 actionRevert: actionRevert,
99048                 actionRotate: actionRotate,
99049                 actionScale: actionScale,
99050                 actionSplit: actionSplit,
99051                 actionStraightenNodes: actionStraightenNodes,
99052                 actionStraightenWay: actionStraightenWay,
99053                 actionUnrestrictTurn: actionUnrestrictTurn,
99054                 actionReflect: actionReflect,
99055                 actionUpgradeTags: actionUpgradeTags,
99056                 behaviorAddWay: behaviorAddWay,
99057                 behaviorBreathe: behaviorBreathe,
99058                 behaviorDrag: behaviorDrag,
99059                 behaviorDrawWay: behaviorDrawWay,
99060                 behaviorDraw: behaviorDraw,
99061                 behaviorEdit: behaviorEdit,
99062                 behaviorHash: behaviorHash,
99063                 behaviorHover: behaviorHover,
99064                 behaviorLasso: behaviorLasso,
99065                 behaviorOperation: behaviorOperation,
99066                 behaviorPaste: behaviorPaste,
99067                 behaviorSelect: behaviorSelect,
99068                 coreContext: coreContext,
99069                 coreFileFetcher: coreFileFetcher,
99070                 fileFetcher: _mainFileFetcher,
99071                 coreDifference: coreDifference,
99072                 coreGraph: coreGraph,
99073                 coreHistory: coreHistory,
99074                 coreLocalizer: coreLocalizer,
99075                 t: _t,
99076                 localizer: _mainLocalizer,
99077                 prefs: corePreferences,
99078                 coreTree: coreTree,
99079                 coreUploader: coreUploader,
99080                 coreValidator: coreValidator,
99081                 geoExtent: geoExtent,
99082                 geoLatToMeters: geoLatToMeters,
99083                 geoLonToMeters: geoLonToMeters,
99084                 geoMetersToLat: geoMetersToLat,
99085                 geoMetersToLon: geoMetersToLon,
99086                 geoMetersToOffset: geoMetersToOffset,
99087                 geoOffsetToMeters: geoOffsetToMeters,
99088                 geoScaleToZoom: geoScaleToZoom,
99089                 geoSphericalClosestNode: geoSphericalClosestNode,
99090                 geoSphericalDistance: geoSphericalDistance,
99091                 geoZoomToScale: geoZoomToScale,
99092                 geoAngle: geoAngle,
99093                 geoChooseEdge: geoChooseEdge,
99094                 geoEdgeEqual: geoEdgeEqual,
99095                 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
99096                 geoHasLineIntersections: geoHasLineIntersections,
99097                 geoHasSelfIntersections: geoHasSelfIntersections,
99098                 geoRotate: geoRotate,
99099                 geoLineIntersection: geoLineIntersection,
99100                 geoPathHasIntersections: geoPathHasIntersections,
99101                 geoPathIntersections: geoPathIntersections,
99102                 geoPathLength: geoPathLength,
99103                 geoPointInPolygon: geoPointInPolygon,
99104                 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
99105                 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
99106                 geoViewportEdge: geoViewportEdge,
99107                 geoRawMercator: geoRawMercator,
99108                 geoVecAdd: geoVecAdd,
99109                 geoVecAngle: geoVecAngle,
99110                 geoVecCross: geoVecCross,
99111                 geoVecDot: geoVecDot,
99112                 geoVecEqual: geoVecEqual,
99113                 geoVecFloor: geoVecFloor,
99114                 geoVecInterp: geoVecInterp,
99115                 geoVecLength: geoVecLength,
99116                 geoVecLengthSquare: geoVecLengthSquare,
99117                 geoVecNormalize: geoVecNormalize,
99118                 geoVecNormalizedDot: geoVecNormalizedDot,
99119                 geoVecProject: geoVecProject,
99120                 geoVecSubtract: geoVecSubtract,
99121                 geoVecScale: geoVecScale,
99122                 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
99123                 geoOrthoCalcScore: geoOrthoCalcScore,
99124                 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
99125                 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
99126                 modeAddArea: modeAddArea,
99127                 modeAddLine: modeAddLine,
99128                 modeAddPoint: modeAddPoint,
99129                 modeAddNote: modeAddNote,
99130                 modeBrowse: modeBrowse,
99131                 modeDragNode: modeDragNode,
99132                 modeDragNote: modeDragNote,
99133                 modeDrawArea: modeDrawArea,
99134                 modeDrawLine: modeDrawLine,
99135                 modeMove: modeMove,
99136                 modeRotate: modeRotate,
99137                 modeSave: modeSave,
99138                 modeSelect: modeSelect,
99139                 modeSelectData: modeSelectData,
99140                 modeSelectError: modeSelectError,
99141                 modeSelectNote: modeSelectNote,
99142                 operationCircularize: operationCircularize,
99143                 operationContinue: operationContinue,
99144                 operationCopy: operationCopy,
99145                 operationDelete: operationDelete,
99146                 operationDisconnect: operationDisconnect,
99147                 operationDowngrade: operationDowngrade,
99148                 operationExtract: operationExtract,
99149                 operationMerge: operationMerge,
99150                 operationMove: operationMove,
99151                 operationOrthogonalize: operationOrthogonalize,
99152                 operationPaste: operationPaste,
99153                 operationReflectShort: operationReflectShort,
99154                 operationReflectLong: operationReflectLong,
99155                 operationReverse: operationReverse,
99156                 operationRotate: operationRotate,
99157                 operationSplit: operationSplit,
99158                 operationStraighten: operationStraighten,
99159                 osmChangeset: osmChangeset,
99160                 osmEntity: osmEntity,
99161                 osmNode: osmNode,
99162                 osmNote: osmNote,
99163                 osmRelation: osmRelation,
99164                 osmWay: osmWay,
99165                 QAItem: QAItem,
99166                 osmIntersection: osmIntersection,
99167                 osmTurn: osmTurn,
99168                 osmInferRestriction: osmInferRestriction,
99169                 osmLanes: osmLanes,
99170                 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
99171                 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
99172                 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
99173                 osmJoinWays: osmJoinWays,
99174                 get osmAreaKeys () { return osmAreaKeys; },
99175                 osmSetAreaKeys: osmSetAreaKeys,
99176                 osmTagSuggestingArea: osmTagSuggestingArea,
99177                 get osmPointTags () { return osmPointTags; },
99178                 osmSetPointTags: osmSetPointTags,
99179                 get osmVertexTags () { return osmVertexTags; },
99180                 osmSetVertexTags: osmSetVertexTags,
99181                 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
99182                 osmOneWayTags: osmOneWayTags,
99183                 osmPavedTags: osmPavedTags,
99184                 osmIsInterestingTag: osmIsInterestingTag,
99185                 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
99186                 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
99187                 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
99188                 presetCategory: presetCategory,
99189                 presetCollection: presetCollection,
99190                 presetField: presetField,
99191                 presetPreset: presetPreset,
99192                 presetManager: _mainPresetIndex,
99193                 presetIndex: presetIndex,
99194                 rendererBackgroundSource: rendererBackgroundSource,
99195                 rendererBackground: rendererBackground,
99196                 rendererFeatures: rendererFeatures,
99197                 rendererMap: rendererMap,
99198                 rendererPhotos: rendererPhotos,
99199                 rendererTileLayer: rendererTileLayer,
99200                 services: services,
99201                 serviceKeepRight: serviceKeepRight,
99202                 serviceImproveOSM: serviceImproveOSM,
99203                 serviceOsmose: serviceOsmose,
99204                 serviceMapillary: serviceMapillary,
99205                 serviceMapRules: serviceMapRules,
99206                 serviceNominatim: serviceNominatim,
99207                 serviceOpenstreetcam: serviceOpenstreetcam,
99208                 serviceOsm: serviceOsm,
99209                 serviceOsmWikibase: serviceOsmWikibase,
99210                 serviceStreetside: serviceStreetside,
99211                 serviceTaginfo: serviceTaginfo,
99212                 serviceVectorTile: serviceVectorTile,
99213                 serviceWikidata: serviceWikidata,
99214                 serviceWikipedia: serviceWikipedia,
99215                 svgAreas: svgAreas,
99216                 svgData: svgData,
99217                 svgDebug: svgDebug,
99218                 svgDefs: svgDefs,
99219                 svgKeepRight: svgKeepRight,
99220                 svgIcon: svgIcon,
99221                 svgGeolocate: svgGeolocate,
99222                 svgLabels: svgLabels,
99223                 svgLayers: svgLayers,
99224                 svgLines: svgLines,
99225                 svgMapillaryImages: svgMapillaryImages,
99226                 svgMapillarySigns: svgMapillarySigns,
99227                 svgMidpoints: svgMidpoints,
99228                 svgNotes: svgNotes,
99229                 svgMarkerSegments: svgMarkerSegments,
99230                 svgOpenstreetcamImages: svgOpenstreetcamImages,
99231                 svgOsm: svgOsm,
99232                 svgPassiveVertex: svgPassiveVertex,
99233                 svgPath: svgPath,
99234                 svgPointTransform: svgPointTransform,
99235                 svgPoints: svgPoints,
99236                 svgRelationMemberTags: svgRelationMemberTags,
99237                 svgSegmentWay: svgSegmentWay,
99238                 svgStreetside: svgStreetside,
99239                 svgTagClasses: svgTagClasses,
99240                 svgTagPattern: svgTagPattern,
99241                 svgTouch: svgTouch,
99242                 svgTurns: svgTurns,
99243                 svgVertices: svgVertices,
99244                 uiFieldDefaultCheck: uiFieldCheck,
99245                 uiFieldOnewayCheck: uiFieldCheck,
99246                 uiFieldCheck: uiFieldCheck,
99247                 uiFieldManyCombo: uiFieldCombo,
99248                 uiFieldMultiCombo: uiFieldCombo,
99249                 uiFieldNetworkCombo: uiFieldCombo,
99250                 uiFieldSemiCombo: uiFieldCombo,
99251                 uiFieldTypeCombo: uiFieldCombo,
99252                 uiFieldCombo: uiFieldCombo,
99253                 uiFieldUrl: uiFieldText,
99254                 uiFieldIdentifier: uiFieldText,
99255                 uiFieldNumber: uiFieldText,
99256                 uiFieldTel: uiFieldText,
99257                 uiFieldEmail: uiFieldText,
99258                 uiFieldText: uiFieldText,
99259                 uiFieldAccess: uiFieldAccess,
99260                 uiFieldAddress: uiFieldAddress,
99261                 uiFieldCycleway: uiFieldCycleway,
99262                 uiFieldLanes: uiFieldLanes,
99263                 uiFieldLocalized: uiFieldLocalized,
99264                 uiFieldMaxspeed: uiFieldMaxspeed,
99265                 uiFieldStructureRadio: uiFieldRadio,
99266                 uiFieldRadio: uiFieldRadio,
99267                 uiFieldRestrictions: uiFieldRestrictions,
99268                 uiFieldTextarea: uiFieldTextarea,
99269                 uiFieldWikidata: uiFieldWikidata,
99270                 uiFieldWikipedia: uiFieldWikipedia,
99271                 uiFields: uiFields,
99272                 uiIntro: uiIntro,
99273                 uiPanelBackground: uiPanelBackground,
99274                 uiPanelHistory: uiPanelHistory,
99275                 uiPanelLocation: uiPanelLocation,
99276                 uiPanelMeasurement: uiPanelMeasurement,
99277                 uiInfoPanels: uiInfoPanels,
99278                 uiPaneBackground: uiPaneBackground,
99279                 uiPaneHelp: uiPaneHelp,
99280                 uiPaneIssues: uiPaneIssues,
99281                 uiPaneMapData: uiPaneMapData,
99282                 uiPanePreferences: uiPanePreferences,
99283                 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
99284                 uiSectionBackgroundList: uiSectionBackgroundList,
99285                 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
99286                 uiSectionChanges: uiSectionChanges,
99287                 uiSectionDataLayers: uiSectionDataLayers,
99288                 uiSectionEntityIssues: uiSectionEntityIssues,
99289                 uiSectionFeatureType: uiSectionFeatureType,
99290                 uiSectionMapFeatures: uiSectionMapFeatures,
99291                 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
99292                 uiSectionOverlayList: uiSectionOverlayList,
99293                 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
99294                 uiSectionPresetFields: uiSectionPresetFields,
99295                 uiSectionPrivacy: uiSectionPrivacy,
99296                 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
99297                 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
99298                 uiSectionRawTagEditor: uiSectionRawTagEditor,
99299                 uiSectionSelectionList: uiSectionSelectionList,
99300                 uiSectionValidationIssues: uiSectionValidationIssues,
99301                 uiSectionValidationOptions: uiSectionValidationOptions,
99302                 uiSectionValidationRules: uiSectionValidationRules,
99303                 uiSectionValidationStatus: uiSectionValidationStatus,
99304                 uiSettingsCustomBackground: uiSettingsCustomBackground,
99305                 uiSettingsCustomData: uiSettingsCustomData,
99306                 uiInit: uiInit,
99307                 uiAccount: uiAccount,
99308                 uiAttribution: uiAttribution,
99309                 uiChangesetEditor: uiChangesetEditor,
99310                 uiCmd: uiCmd,
99311                 uiCombobox: uiCombobox,
99312                 uiCommit: uiCommit,
99313                 uiCommitWarnings: uiCommitWarnings,
99314                 uiConfirm: uiConfirm,
99315                 uiConflicts: uiConflicts,
99316                 uiContributors: uiContributors,
99317                 uiCurtain: uiCurtain,
99318                 uiDataEditor: uiDataEditor,
99319                 uiDataHeader: uiDataHeader,
99320                 uiDisclosure: uiDisclosure,
99321                 uiEditMenu: uiEditMenu,
99322                 uiEntityEditor: uiEntityEditor,
99323                 uiFeatureInfo: uiFeatureInfo,
99324                 uiFeatureList: uiFeatureList,
99325                 uiField: uiField,
99326                 uiFieldHelp: uiFieldHelp,
99327                 uiFlash: uiFlash,
99328                 uiFormFields: uiFormFields,
99329                 uiFullScreen: uiFullScreen,
99330                 uiGeolocate: uiGeolocate,
99331                 uiImproveOsmComments: uiImproveOsmComments,
99332                 uiImproveOsmDetails: uiImproveOsmDetails,
99333                 uiImproveOsmEditor: uiImproveOsmEditor,
99334                 uiImproveOsmHeader: uiImproveOsmHeader,
99335                 uiInfo: uiInfo,
99336                 uiInspector: uiInspector,
99337                 uiIssuesInfo: uiIssuesInfo,
99338                 uiKeepRightDetails: uiKeepRightDetails,
99339                 uiKeepRightEditor: uiKeepRightEditor,
99340                 uiKeepRightHeader: uiKeepRightHeader,
99341                 uiLasso: uiLasso,
99342                 uiLoading: uiLoading,
99343                 uiMapInMap: uiMapInMap,
99344                 uiModal: uiModal,
99345                 uiNotice: uiNotice,
99346                 uiNoteComments: uiNoteComments,
99347                 uiNoteEditor: uiNoteEditor,
99348                 uiNoteHeader: uiNoteHeader,
99349                 uiNoteReport: uiNoteReport,
99350                 uiPopover: uiPopover,
99351                 uiPresetIcon: uiPresetIcon,
99352                 uiPresetList: uiPresetList,
99353                 uiRestore: uiRestore,
99354                 uiScale: uiScale,
99355                 uiSidebar: uiSidebar,
99356                 uiSourceSwitch: uiSourceSwitch,
99357                 uiSpinner: uiSpinner,
99358                 uiSplash: uiSplash,
99359                 uiStatus: uiStatus,
99360                 uiSuccess: uiSuccess,
99361                 uiTagReference: uiTagReference,
99362                 uiToggle: uiToggle,
99363                 uiTooltip: uiTooltip,
99364                 uiVersion: uiVersion,
99365                 uiViewOnOSM: uiViewOnOSM,
99366                 uiViewOnKeepRight: uiViewOnKeepRight,
99367                 uiZoom: uiZoom,
99368                 utilAesEncrypt: utilAesEncrypt,
99369                 utilAesDecrypt: utilAesDecrypt,
99370                 utilArrayChunk: utilArrayChunk,
99371                 utilArrayDifference: utilArrayDifference,
99372                 utilArrayFlatten: utilArrayFlatten,
99373                 utilArrayGroupBy: utilArrayGroupBy,
99374                 utilArrayIdentical: utilArrayIdentical,
99375                 utilArrayIntersection: utilArrayIntersection,
99376                 utilArrayUnion: utilArrayUnion,
99377                 utilArrayUniq: utilArrayUniq,
99378                 utilArrayUniqBy: utilArrayUniqBy,
99379                 utilAsyncMap: utilAsyncMap,
99380                 utilCleanTags: utilCleanTags,
99381                 utilCombinedTags: utilCombinedTags,
99382                 utilDeepMemberSelector: utilDeepMemberSelector,
99383                 utilDetect: utilDetect,
99384                 utilDisplayName: utilDisplayName,
99385                 utilDisplayNameForPath: utilDisplayNameForPath,
99386                 utilDisplayType: utilDisplayType,
99387                 utilDisplayLabel: utilDisplayLabel,
99388                 utilEntityRoot: utilEntityRoot,
99389                 utilEditDistance: utilEditDistance,
99390                 utilEntitySelector: utilEntitySelector,
99391                 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
99392                 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
99393                 utilFastMouse: utilFastMouse,
99394                 utilFunctor: utilFunctor,
99395                 utilGetAllNodes: utilGetAllNodes,
99396                 utilGetSetValue: utilGetSetValue,
99397                 utilHashcode: utilHashcode,
99398                 utilHighlightEntities: utilHighlightEntities,
99399                 utilKeybinding: utilKeybinding,
99400                 utilNoAuto: utilNoAuto,
99401                 utilObjectOmit: utilObjectOmit,
99402                 utilPrefixCSSProperty: utilPrefixCSSProperty,
99403                 utilPrefixDOMProperty: utilPrefixDOMProperty,
99404                 utilQsString: utilQsString,
99405                 utilRebind: utilRebind,
99406                 utilSafeClassName: utilSafeClassName,
99407                 utilSetTransform: utilSetTransform,
99408                 utilSessionMutex: utilSessionMutex,
99409                 utilStringQs: utilStringQs,
99410                 utilTagDiff: utilTagDiff,
99411                 utilTagText: utilTagText,
99412                 utilTiler: utilTiler,
99413                 utilTotalExtent: utilTotalExtent,
99414                 utilTriggerEvent: utilTriggerEvent,
99415                 utilUnicodeCharsCount: utilUnicodeCharsCount,
99416                 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
99417                 utilUniqueDomId: utilUniqueDomId,
99418                 utilWrap: utilWrap,
99419                 validationAlmostJunction: validationAlmostJunction,
99420                 validationCloseNodes: validationCloseNodes,
99421                 validationCrossingWays: validationCrossingWays,
99422                 validationDisconnectedWay: validationDisconnectedWay,
99423                 validationFormatting: validationFormatting,
99424                 validationHelpRequest: validationHelpRequest,
99425                 validationImpossibleOneway: validationImpossibleOneway,
99426                 validationIncompatibleSource: validationIncompatibleSource,
99427                 validationMaprules: validationMaprules,
99428                 validationMismatchedGeometry: validationMismatchedGeometry,
99429                 validationMissingRole: validationMissingRole,
99430                 validationMissingTag: validationMissingTag,
99431                 validationOutdatedTags: validationOutdatedTags,
99432                 validationPrivateData: validationPrivateData,
99433                 validationSuspiciousName: validationSuspiciousName,
99434                 validationUnsquareWay: validationUnsquareWay
99435         });
99436
99437         window.requestIdleCallback = window.requestIdleCallback || function (cb) {
99438           var start = Date.now();
99439           return window.requestAnimationFrame(function () {
99440             cb({
99441               didTimeout: false,
99442               timeRemaining: function timeRemaining() {
99443                 return Math.max(0, 50 - (Date.now() - start));
99444               }
99445             });
99446           });
99447         };
99448
99449         window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
99450           window.cancelAnimationFrame(id);
99451         };
99452         window.iD = iD;
99453
99454 }());